WPFDevelopers 实战:主题切换、颜色选择与圆形菜单一站式集成
目录一、ColorSwitchBtn —— 主题色切换按钮1.1 效果1.2 XAML 结构1.3 C# 后台代码1.4 三步接入你自己的项目二、CircleMenu —— 圆形弹出菜单2.1 效果2.2 XAML 结构2.3 常用依赖属性一览2.4 路由事件2.5 后台处理命令示例2.6 拖动 点击判定2.7 动画实现原理三、组合使用建议四、完整最小示例一、ColorSwitchBtn —— 主题色切换按钮1.1 效果点击标题栏上的调色板图标按钮弹出一个Popup内含ColorPicker颜色选择器用户挑选好颜色后点Apply即可实时切换整个应用的主题色点Cancel则关闭弹层不应用。1.2 XAML 结构wd:Window.TitleBarLayout StackPanel HorizontalAlignmentRight wd:PanelHelper.Spacing2 OrientationHorizontal wd:SwitchButton x:NameThemeSwitchBtn Width30 Height30 ClickThemeSwitchBtn_Click wd:SwitchButton.UncheckedContent /wd:SwitchButton.UncheckedContent wd:SwitchButton.CheckedContent /wd:SwitchButton.CheckedContent /wd:SwitchButton wd:SwitchButton x:NameColorSwitchBtn Width30 Height30 wd:SwitchButton.UncheckedContent wd:PathIcon Data... ForegroundWhite / /wd:SwitchButton.UncheckedContent wd:SwitchButton.CheckedContent wd:PathIcon Data... ForegroundWhite / /wd:SwitchButton.CheckedContent /wd:SwitchButton Popup AllowsTransparencyTrue HorizontalOffset-200 IsOpen{Binding IsChecked, ElementNameColorSwitchBtn, ModeTwoWay} PlacementBottom PlacementTarget{Binding ElementNameColorSwitchBtn} StaysOpenFalse Border Margin10 Background{DynamicResource WD.BackgroundBrush} BorderBrush{DynamicResource WD.BaseBrush} BorderThickness1 CornerRadius4 Effect{StaticResource WD.PopupShadowDepth} StackPanel Margin4 wd:ColorPicker x:NameThemeColorPicker / StackPanel HorizontalAlignmentRight wd:PanelHelper.Spacing4 OrientationHorizontal Button ContentApply Style{StaticResource WD.PrimaryButton} ClickColorPicker_Apply / Button ContentCancel Style{StaticResource WD.DefaultButton} ClickColorPicker_Cancel / /StackPanel /StackPanel /Border /Popup /StackPanel /wd:Window.TitleBarLayout关键点wd:SwitchButton自带Checked/Unchecked两态内容可直接当作开关图标。Popup.IsOpen双向绑定到ColorSwitchBtn.IsChecked点击按钮自动弹出点外部自动收起。ColorPicker控件来自 WPFDevelopers开箱即用。1.3 C# 后台代码private void OnMainWindow_Loaded(object sender, RoutedEventArgs e) { SetThemeSource(); // 用当前主题色初始化颜色选择器 ThemeColorPicker.SelectedColor ThemeManager.Instance.PrimaryColor; } private void ColorPicker_Apply(object sender, RoutedEventArgs e) { ColorSwitchBtn.IsChecked false; // 关闭 Popup ThemeManager.Instance.SetColor(ThemeColorPicker.SelectedColor); } private void ColorPicker_Cancel(object sender, RoutedEventArgs e) { ColorSwitchBtn.IsChecked false; // 仅关闭 Popup }1.4 三步接入你自己的项目在窗口顶部或任意容器放置wd:SwitchButtonwd:ColorPickerPopup。Popup.IsOpen双向绑定到按钮IsChecked。在 Apply 按钮事件中调用ThemeManager.Instance.SetColor(picker.SelectedColor)。二、CircleMenu —— 圆形弹出菜单2.1 效果悬浮在窗口右下角的圆形按钮点击中心按钮后子菜单项沿圆形轨迹向外展开带 0.4s 动画点击某一项触发命令再次点击中心按钮则收回。整个圆形菜单还可拖动。2.2 XAML 结构wd:CircleMenu Grid.Column2 Width100 Height100 Margin20 HorizontalAlignmentRight VerticalAlignmentBottom ItemClickCommand{Binding CircleMenuItemClickCommand, RelativeSource{RelativeSource AncestorTypeWindow}} wd:CircleMenuItem x:NameScreenShot ToolTipScreenShot wd:SvgViewer Sourcepack://application:,,,/WPFDevelopers.Samples;component/Resources/Svg/ScreenShot.svg / /wd:CircleMenuItem wd:CircleMenuItem x:NameGithub ToolTipGithub wd:SvgViewer Sourcepack://application:,,,/WPFDevelopers.Samples;component/Resources/Svg/Github.svg / /wd:CircleMenuItem wd:CircleMenuItem x:NameGrayscale ToolTipGrayscale wd:SvgViewer x:NameGrayscaleSvg Sourcepack://application:,,,/WPFDevelopers.Samples;component/Resources/Svg/EnableGrayscale.svg / /wd:CircleMenuItem wd:CircleMenuItem x:NameTheme ToolTipTheme wd:SvgViewer x:NameThemeSvg Sourcepack://application:,,,/WPFDevelopers.Samples;component/Resources/Svg/Sun.svg / /wd:CircleMenuItem wd:CircleMenuItem x:NameCode ToolTipMainWindow Code wd:SvgViewer Sourcepack://application:,,,/WPFDevelopers.Samples;component/Resources/Svg/Code.svg / /wd:CircleMenuItem wd:CircleMenuItem x:NameClearToast ToolTipClear Toast wd:PathIcon Width10 Height10 KindWindowClose / /wd:CircleMenuItem /wd:CircleMenu2.3 常用依赖属性一览属性类型说明ItemsCircleMenuItemCollection子项集合也可直接在 XAML 中写子元素IsExpandedbool控制展开/收起支持 TwoWay 绑定ItemClickCommandICommand子项点击命令参数为被点击的CircleMenuItemSelectedIndex/SelectedItemint/object选中项默认双向绑定SectorBackgroundBrush扇区背景色SectorDualBackgroundBrush奇数项扇区交替色SelectedBackgroundBrush选中扇区背景色MinItemsint子项最小数量低于此值自动隐藏默认 2CanDragbool是否允许拖动整个菜单默认 true2.4 路由事件wd:CircleMenu ItemClickCircleMenu_ItemClick ... /private void CircleMenu_ItemClick(object sender, RoutedEventArgs e) { var item e.OriginalSource as CircleMenuItem; // 处理点击... }ItemClick和ItemClickCommand会同时触发MVVM 推荐用 Command复杂交互可用事件。2.5 后台处理命令示例public ICommand CircleMenuItemClickCommand new RelayCommand(param { if (param isnot CircleMenuItem item) return; switch (item.Name) { caseScreenShot: // 截图... break; caseGithub: Process.Start(new ProcessStartInfo(https://github.com/...) { UseShellExecute true }); break; caseTheme: var isDark ThemeSvg.Source.Contains(Moon); App.Theme isDark ? ThemeType.Dark : ThemeType.Light; ThemeManager.Instance.SetTheme(App.Theme); break; caseCode: CodeDrawer.IsOpen !CodeDrawer.IsOpen; break; caseClearToast: Toast.ClearAll(); break; } });2.6 拖动 点击判定CanDragTrue默认时拖动菜单会在父容器范围内移动光标变为 SizeAll。当按下到抬起的水平/垂直位移都小于 3 像素时判定为点击触发IsExpanded翻转。2.7 动画实现原理展开/收起基于ItemsPresenter.Clip的EllipseGeometry.RadiusX/RadiusY配合CubicEase(EaseOut)展开 0.4s、收起 0.3s。子项角度在UpdateAllAnglesCore()中按360 / Items.Count均分计算。三、组合使用建议位置CircleMenu一般放在窗口角落如示例的右下角ColorSwitchBtn适合放在TitleBarLayout。主题联动CircleMenu 中的Theme项可与ThemeSwitchBtn共享同一套ThemeManager逻辑保证 UI 一致。MVVM所有交互尽量通过ItemClickCommandRelayCommand处理后台只保留视图层必要的绑定如IsChecked、Source切换。子项数量建议 3–8 个超过 8 个扇区会过于拥挤。MinItems默认为 2可根据业务调整。资源示例使用wd:SvgViewer加载 SVG 图标也支持wd:PathIcon等任意UIElement作为子项内容。四、完整最小示例wd:Window xmlns:wdhttps://github.com/WPFDevelopersOrg/WPFDevelopers ... wd:Window.TitleBarLayout StackPanel HorizontalAlignmentRight OrientationHorizontal wd:SwitchButton x:NameColorSwitchBtn Width30 Height30 wd:SwitchButton.UncheckedContent wd:PathIcon Data... ForegroundWhite / /wd:SwitchButton.UncheckedContent wd:SwitchButton.CheckedContent wd:PathIcon Data... ForegroundWhite / /wd:SwitchButton.CheckedContent /wd:SwitchButton Popup IsOpen{Binding IsChecked, ElementNameColorSwitchBtn, ModeTwoWay} PlacementBottom PlacementTarget{Binding ElementNameColorSwitchBtn} StaysOpenFalse StackPanel wd:ColorPicker x:NameThemeColorPicker / Button ContentApply ClickColorPicker_Apply / /StackPanel /Popup /StackPanel /wd:Window.TitleBarLayout Grid wd:CircleMenu Width100 Height100 HorizontalAlignmentRight VerticalAlignmentBottom ItemClickCommand{Binding MenuClickCmd} wd:CircleMenuItem ToolTipItem 1 wd:PathIcon KindHome / /wd:CircleMenuItem wd:CircleMenuItem ToolTipItem 2 wd:PathIcon KindSettings / /wd:CircleMenuItem /wd:CircleMenu /Grid /wd:Windowprivate void ColorPicker_Apply(object sender, RoutedEventArgs e) { ColorSwitchBtn.IsChecked false; ThemeManager.Instance.SetColor(ThemeColorPicker.SelectedColor); }引入地址