需求概述
首先明确我们要做什么:一个包含4个关注点的配置系统,每个关注点包含名称、颜色、半径、启用状态四个可配置属性。所有配置需持久化到数据库,并能实时反馈到UI显示上。
-
核心功能点:
-
关注点属性动态配置
-
配置数据实时生效
-
所有数据持久化存储
-
优雅、用户友好的交互界面
-
需求分析
按上述需求,可以通过一个关注点类,将名称、颜色、半径、启用作为它的属性,同时由于名称是可变化的,最好再添加一个别名或ID的属性,以便在数据库中进行存储。
关注点类:名称与颜色的存储,可以使用字符串,半径使用浮点数,是否启用使用bool值。
所有关注点可以形成一个可观察对象的集合,以用于UI上的绑定。
需求实现
UI代码如下,以下为WINUI xaml代码,WPF亦可做参考(仅需极少改动即可):
<?xml version="1.0" encoding="utf-8" ?> <Windowx:Class="WINUIDemo.MainWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:converters="using:WINUIDemo.Converters"xmlns:d="http://schemas.microsoft.com/expression/blend/2008"xmlns:local="using:WINUIDemo"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"xmlns:viewmodels="using:WINUIDemo.ViewModel"mc:Ignorable="d"><StackPanel><StackPanel.Resources><Style x:Key="FocusPointItemStyle" TargetType="ListViewItem"><Setter Property="HorizontalContentAlignment" Value="Left" /><!-- 内容左对齐 --><Setter Property="Padding" Value="10" /><!-- 内边距 --><Setter Property="Margin" Value="0,0,10,0" /><!-- 禁止水平拉伸 --><Setter Property="HorizontalAlignment" Value="Left" /><Setter Property="Width" Value="Auto" /><!-- 禁用悬停和选中时的背景变化 --><Setter Property="Background" Value="Transparent" /><Setter Property="BorderBrush" Value="Transparent" /><!-- 修改 VisualStateManager 行为 --><Setter Property="Template"><Setter.Value><ControlTemplate TargetType="ListViewItem"><Gridx:Name="ContentBorder"Background="{TemplateBinding Background}"BorderBrush="{TemplateBinding BorderBrush}"BorderThickness="{TemplateBinding BorderThickness}"><ContentPresenterx:Name="ContentPresenter"Margin="{TemplateBinding Padding}"HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"VerticalAlignment="{TemplateBinding VerticalContentAlignment}"Content="{TemplateBinding Content}"ContentTemplate="{TemplateBinding ContentTemplate}"ContentTransitions="{TemplateBinding ContentTransitions}" /></Grid></ControlTemplate></Setter.Value></Setter></Style><DataTemplate x:Key="FocusPointTemplate" x:DataType="viewmodels:FocusPoint"><BorderPadding="10"Background="{ThemeResource CardBackgroundFillColorDefault}"BorderBrush="AliceBlue"BorderThickness="1"CornerRadius="8"><StackPanel Orientation="Horizontal" Spacing="10"><!-- 名称 --><TextBoxWidth="100"VerticalAlignment="Center"Text="{x:Bind Name}"TextAlignment="Center" ></TextBox><!-- 颜色选择按钮(默认显示图标) --><Buttonx:Name="ColorPickerButton"Width="32"Height="32"Padding="0"><Button.Content><!-- 小图标:显示当前颜色的方块 --><RectangleWidth="20"Height="20"Fill="{x:Bind ToBrush(Color), Mode=OneWay}" /></Button.Content><Button.Flyout><Flyout Placement="Bottom" ShowMode="TransientWithDismissOnPointerMoveAway"><!-- 展开后的完整ColorPicker --><ColorPickerWidth="320"Height="320"ColorSpectrumShape="Ring"IsAlphaEnabled="False"IsColorPreviewVisible="False"Color="{x:Bind Color, Mode=TwoWay}" /></Flyout></Button.Flyout></Button><!-- 半径和启用控件 --><StackPanel VerticalAlignment="Center" Orientation="Horizontal"><TextBlockMargin="0,0,10,0"VerticalAlignment="Center"Text="半径" /><NumberBoxWidth="50"Header=""Maximum="50"Minimum="1"Value="{x:Bind Radius, Mode=TwoWay}" /></StackPanel><CheckBoxWidth="Auto"MinWidth="0"Content="启用"IsChecked="{x:Bind IsEnabled, Mode=TwoWay}" /></StackPanel></Border></DataTemplate></StackPanel.Resources><ListViewVerticalAlignment="Center"HorizontalContentAlignment="Center"ItemContainerStyle="{StaticResource FocusPointItemStyle}"ItemTemplate="{StaticResource FocusPointTemplate}"ItemsSource="{x:Bind viewModel.FocusPoints}"Loaded="ListView_Loaded"><ListView.ItemsPanel><ItemsPanelTemplate><!--<ItemsStackPanel Orientation="Horizontal" />--><ItemsWrapGridHorizontalAlignment="Left"VerticalAlignment="Center"MaximumRowsOrColumns="2"Orientation="Horizontal" /></ItemsPanelTemplate></ListView.ItemsPanel></ListView></StackPanel> </Window>
UI设计亮点:
-
集成式颜色选择:将
ColorPicker
嵌入到Flyout
中,节省空间,交互优雅。 -
数据绑定:所有控件属性均与ViewModel中的数据进行绑定,实现双向更新。
以下为FocusPoint,使用ObservableObject(MVVMToolkit)
来实现属性变更通知。
using CommunityToolkit.Mvvm.ComponentModel; using Microsoft.UI; using System; using Windows.UI;namespace WINUIDemo.ViewModel {// 关注点数据模型public partial class FocusPoint : ObservableObject{private string name;private string color;private double radius;private bool isEnabled;public string Name{get => name;set { SetProperty(ref name, value); }}public string Color{get => color;set { SetProperty(ref color, value); }}public double Radius{get => radius;set { SetProperty(ref radius, value); }}public bool IsEnabled{get => isEnabled;set { SetProperty(ref isEnabled, value); }}public Microsoft.UI.Xaml.Media.SolidColorBrush ToBrush(string color){return new Microsoft.UI.Xaml.Media.SolidColorBrush(FromHex(color));}private static Color FromHex(string hex){hex = hex.TrimStart('#');byte a = 255; // 默认不透明if (hex.Length == 8){a = Convert.ToByte(hex.Substring(0, 2), 16);hex = hex.Substring(2); // 移除 Alpha 部分 }byte r = Convert.ToByte(hex.Substring(0, 2), 16);byte g = Convert.ToByte(hex.Substring(2, 2), 16);byte b = Convert.ToByte(hex.Substring(4, 2), 16);return ColorHelper.FromArgb(a, r, g, b);}// 默认值构造函数public FocusPoint(string name, string color, double radius, bool isEnabled){Name = name;Color = color;Radius = radius;IsEnabled = isEnabled;}}}
设计要点:颜色采用Hex字符串存储,便于序列化和数据库存储,同时提供方法与XAML的Brush
相互转换。
以下为VM
using CommunityToolkit.Mvvm.ComponentModel; using Microsoft.UI; using System.Collections.ObjectModel;namespace WINUIDemo.ViewModel {public partial class MainViewModel : ObservableRecipient{[ObservableProperty]public ObservableCollection<FocusPoint> focusPoints;public MainViewModel(){FocusPoints = new ObservableCollection<FocusPoint>{new ("关注点1", Colors.Red.ToString(), 10.0, true),new ("关注点2", Colors.Blue.ToString(), 15.0, false),new ("关注点3", Colors.Yellow.ToString(), 15.0, false),new ("关注点4", Colors.Green.ToString(), 15.0, false),};}} }
实现效果