在斯克迪亚看到一篇WPF动态改变主题颜色的文章,来了兴趣,于是自己搞了个简单的ColorPicker控件。
控件其实很简单,定义了5个依赖属性
FinalBrushProperty, AProperty, RProperty, GProperty, BProperty
然后当A,R,G,B发生变化时,构造新的FinalBrush
在FinalBrush发生变化时,更新ARGB的值。
Code
private static void OnFinalBrushChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
ColorPicker picker = sender as ColorPicker;
Color newColor = ((SolidColorBrush)e.NewValue).Color;
picker.A = newColor.A;
picker.R = newColor.R;
picker.G = newColor.G;
picker.B = newColor.B;
picker.RaiseEvent(new FinalBrushChangedEventArgs(FinalBrushChangedEvent, picker, (SolidColorBrush)e.OldValue, (SolidColorBrush)e.NewValue));
}
private static void OnColorChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
ColorPicker picker = sender as ColorPicker;
picker.FinalBrush = new SolidColorBrush(Color.FromArgb(picker.A, picker.R, picker.G, picker.B));
}
private static void OnFinalBrushChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
ColorPicker picker = sender as ColorPicker;
Color newColor = ((SolidColorBrush)e.NewValue).Color;
picker.A = newColor.A;
picker.R = newColor.R;
picker.G = newColor.G;
picker.B = newColor.B;
picker.RaiseEvent(new FinalBrushChangedEventArgs(FinalBrushChangedEvent, picker, (SolidColorBrush)e.OldValue, (SolidColorBrush)e.NewValue));
}
private static void OnColorChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
ColorPicker picker = sender as ColorPicker;
picker.FinalBrush = new SolidColorBrush(Color.FromArgb(picker.A, picker.R, picker.G, picker.B));
}
在ColorPicker的模板里面,分别放置4个Slider绑定到ARGB,一个Border绑定到FinalBrush以预览结果。
Code
<Style TargetType="{x:Type local:ColorPicker}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:ColorPicker}">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<DockPanel>
<Border CornerRadius="5" BorderBrush="Black" BorderThickness="1"
Width="60" Height="60" Margin="10"
Background="{TemplateBinding FinalBrush}"/>
<Grid>
<Grid.Resources>
<Style TargetType="{x:Type Slider}">
<Setter Property="VerticalAlignment" Value="Center"/>
<Setter Property="Minimum" Value="0"/>
<Setter Property="Maximum" Value="255"/>
<Setter Property="SmallChange" Value="1"/>
<Setter Property="LargeChange" Value="15"/>
<Setter Property="Grid.Column" Value="1"/>
</Style>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="VerticalAlignment" Value="Center"/>
<Setter Property="HorizontalAlignment" Value="Right"/>
<Setter Property="Grid.Column" Value="0"/>
</Style>
</Grid.Resources>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="65"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Text="Alpha"/>
<TextBlock Grid.Row="1" Text="Red"/>
<TextBlock Grid.Row="2" Text="Green"/>
<TextBlock Grid.Row="3" Text="Blue"/>
<Slider Grid.Row="0" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=A, Mode=TwoWay}"/>
<Slider Grid.Row="1" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=R, Mode=TwoWay}"/>
<Slider Grid.Row="2" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=G, Mode=TwoWay}"/>
<Slider Grid.Row="3" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=B, Mode=TwoWay}"/>
</Grid>
</DockPanel>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="{x:Type local:ColorPicker}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:ColorPicker}">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<DockPanel>
<Border CornerRadius="5" BorderBrush="Black" BorderThickness="1"
Width="60" Height="60" Margin="10"
Background="{TemplateBinding FinalBrush}"/>
<Grid>
<Grid.Resources>
<Style TargetType="{x:Type Slider}">
<Setter Property="VerticalAlignment" Value="Center"/>
<Setter Property="Minimum" Value="0"/>
<Setter Property="Maximum" Value="255"/>
<Setter Property="SmallChange" Value="1"/>
<Setter Property="LargeChange" Value="15"/>
<Setter Property="Grid.Column" Value="1"/>
</Style>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="VerticalAlignment" Value="Center"/>
<Setter Property="HorizontalAlignment" Value="Right"/>
<Setter Property="Grid.Column" Value="0"/>
</Style>
</Grid.Resources>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="65"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Text="Alpha"/>
<TextBlock Grid.Row="1" Text="Red"/>
<TextBlock Grid.Row="2" Text="Green"/>
<TextBlock Grid.Row="3" Text="Blue"/>
<Slider Grid.Row="0" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=A, Mode=TwoWay}"/>
<Slider Grid.Row="1" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=R, Mode=TwoWay}"/>
<Slider Grid.Row="2" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=G, Mode=TwoWay}"/>
<Slider Grid.Row="3" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=B, Mode=TwoWay}"/>
</Grid>
</DockPanel>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
这个时候,ColorPicker就可以使用了。在Demo里面,我做了一个ColorPickerDialog。它继承自Window,里面放了一个ColorPicker控件,然后将它的FinalBrush属性绑定到资源中的WindowBackground上。这样打开Dialog的时候,它的颜色自动和资源的颜色同步。同时,监听它的ColorPicker的FinalBrushChanged事件,更新资源中的颜色。这样,当我们调节ColorPickerDialog的颜色的时候,Window的颜色同步变化。
当然,你可以做的更完善,比如添加一个确定和取消按钮,当取消的时候恢复原来的颜色。或者放一个CheckBox,指定是否同步预览。
我的美工功底比斯克迪亚差远了,呵呵,就是原始的样式。
源代码下载:https://files.cnblogs.com/RMay/ChangeColor.rar
晕啊,用Chrome编辑有问题。