基于WPF实现颜色选择器控件

 更新时间:2023年08月18日 08:58:17   作者:WPF开发者  
这篇文章主要介绍了如何基于WPF实现简单的颜色选择器控件,文中的示例代码讲解详细,对我们学习或工作有一定帮助,需要的小伙伴可以参考一下

WPF 实现颜色选择器控件

  • 框架使用.NET4 至 .NET6
  • Visual Studio 2022;

实现代码

1)新增 ColorPicker.cs 代码如下:

  • 包含一个Slider(用于选择色调)、一个Canvas(用于选择饱和度和亮度)、一个Thumb(拖动选择饱和度和亮度的指示器)和一个Button(用于切换颜色类型)。
  • 通过使用ColorPicker控件,用户可以选择一个颜色,并且可以通过绑定SelectedColor属性来获取所选颜色。这个属性是一个依赖属性,支持双向绑定,并且当颜色发生改变时会触发SelectedColorChanged事件。
  • ColorType属性用于指定颜色类型,可以选择RGB、HSL或HEX三种类型之一。当用户点击Button时,可以循环切换颜色类型。
  • 在控件的模板中,通过TemplatePart特性标记了四个重要的子元素:HueSlider、Canvas、Thumb和Button。在OnApplyTemplate方法中,根据模板找到这些子元素,并注册相应的事件处理程序。
  • 控件通过使用颜色转换工具类ColorUtil实现颜色的转换和计算。当用户在Canvas上点击或拖动Thumb时,会计算得到相应的HSB(色调、饱和度、亮度)值,并将其设置为依赖属性HSB的值。然后根据HSB的值计算出对应的颜色,并更新SelectedColor属性的值。
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Input;
using System.Windows.Media;
using WPFDevelopers.Utilities;
namespace WPFDevelopers.Controls
{
    [TemplatePart(Name = HueSliderColorTemplateName, Type = typeof(Slider))]
    [TemplatePart(Name = CanvasTemplateName, Type = typeof(Canvas))]
    [TemplatePart(Name = ThumbTemplateName, Type = typeof(Thumb))]
    [TemplatePart(Name = ButtonTemplateName, Type = typeof(Button))]
    public class ColorPicker : Control
    {
        private const string HueSliderColorTemplateName = "PART_HueSlider";
        private const string CanvasTemplateName = "PART_Canvas";
        private const string ThumbTemplateName = "PART_Thumb";
        private const string ButtonTemplateName = "PART_Button";
        private static readonly DependencyPropertyKey HueColorPropertyKey =
            DependencyProperty.RegisterReadOnly("HueColor", typeof(Color), typeof(ColorPicker),
                new PropertyMetadata(Colors.Red));
        public static readonly DependencyProperty HueColorProperty = HueColorPropertyKey.DependencyProperty;
        public static readonly DependencyProperty SelectedColorProperty =
            DependencyProperty.Register("SelectedColor", typeof(Color), typeof(ColorPicker),
                new FrameworkPropertyMetadata(Colors.Red, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
                    OnSelectedColorChanged));
        private static readonly DependencyPropertyKey HSBPropertyKey =
            DependencyProperty.RegisterReadOnly("HSB", typeof(HSB), typeof(ColorPicker),
                new PropertyMetadata(new HSB()));
        public static readonly DependencyProperty HSBHProperty = HSBPropertyKey.DependencyProperty;
        public static readonly DependencyProperty ColorTypeProperty =
            DependencyProperty.Register("ColorType", typeof(ColorTypeEnum), typeof(ColorPicker),
                new PropertyMetadata(ColorTypeEnum.RGB));
        private Button _button;
        private Canvas _canvas;
        private Slider _hueSliderColor;
        private bool _isInnerUpdateSelectedColor;
        private Thumb _thumb;
        private ColorTypeEnum[] colorTypeEnums;
        private int currentGridStateIndex;
        static ColorPicker()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(ColorPicker),
                new FrameworkPropertyMetadata(typeof(ColorPicker)));
        }
        public Color HueColor => (Color) GetValue(HueColorProperty);
        public Color SelectedColor
        {
            get => (Color) GetValue(SelectedColorProperty);
            set => SetValue(SelectedColorProperty, value);
        }
        public HSB HSB => (HSB) GetValue(HSBHProperty);
        public ColorTypeEnum ColorType
        {
            get => (ColorTypeEnum) GetValue(ColorTypeProperty);
            set => SetValue(ColorTypeProperty, value);
        }
        private static void OnSelectedColorChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var ctrl = d as ColorPicker;
            if (ctrl._isInnerUpdateSelectedColor)
            {
                ctrl._isInnerUpdateSelectedColor = false;
                return;
            }
            var color = (Color) e.NewValue;
            double h = 0, s = 0, b = 0;
            ColorUtil.HsbFromColor(color, ref h, ref s, ref b);
            var hsb = new HSB {H = h, S = s, B = b};
            ctrl.SetValue(HueColorPropertyKey, ColorUtil.ColorFromHsb(hsb.H, 1, 1));
            ctrl.SetValue(HSBPropertyKey, hsb);
            Canvas.SetLeft(ctrl._thumb, s * ctrl._canvas.ActualWidth - ctrl._thumb.ActualWidth / 2);
            Canvas.SetTop(ctrl._thumb, (1 - b) * ctrl._canvas.ActualHeight - ctrl._thumb.ActualHeight / 2);
            ctrl._hueSliderColor.Value = 1 - h;
        }
        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();
            if (_hueSliderColor != null)
                _hueSliderColor.ValueChanged -= HueSliderColor_OnValueChanged;
            _canvas = GetTemplateChild(CanvasTemplateName) as Canvas;
            if (_canvas != null)
            {
                _canvas.Loaded += Canvas_Loaded;
                _canvas.MouseUp += Canvas_MouseUp;
            }
            _thumb = GetTemplateChild(ThumbTemplateName) as Thumb;
            if (_thumb != null)
                _thumb.DragDelta += Thumb_DragDelta;
            _hueSliderColor = GetTemplateChild(HueSliderColorTemplateName) as Slider;
            if (_hueSliderColor != null)
                _hueSliderColor.ValueChanged += HueSliderColor_OnValueChanged;
            _button = GetTemplateChild(ButtonTemplateName) as Button;
            currentGridStateIndex = 0;
            colorTypeEnums = (ColorTypeEnum[]) Enum.GetValues(typeof(ColorTypeEnum));
            if (_button != null)
                _button.Click += Button_Click;
        }
        private void Button_Click(object sender, RoutedEventArgs e)
        {
            currentGridStateIndex = (currentGridStateIndex + 1) % colorTypeEnums.Length;
            ColorType = colorTypeEnums[currentGridStateIndex];
        }
        private void Canvas_MouseUp(object sender, MouseButtonEventArgs e)
        {
            var canvasPosition = e.GetPosition(_canvas);
            GetHSB(canvasPosition);
        }
        private void Canvas_MouseDown(object sender, MouseButtonEventArgs e)
        {
            var canvasPosition = e.GetPosition(_canvas);
            GetHSB(canvasPosition);
        }
        private void GetHSB(Point point, bool isMove = true)
        {
            var newLeft = point.X - _thumb.ActualWidth / 2;
            var newTop = point.Y - _thumb.ActualHeight / 2;
            var thumbW = _thumb.ActualWidth / 2;
            var thumbH = _thumb.ActualHeight / 2;
            var canvasRight = _canvas.ActualWidth - thumbW;
            var canvasBottom = _canvas.ActualHeight - thumbH;
            if (newLeft < -thumbW)
                newLeft = -thumbW;
            else if (newLeft > canvasRight)
                newLeft = canvasRight;
            if (newTop < -thumbH)
                newTop = -thumbH;
            else if (newTop > canvasBottom)
                newTop = canvasBottom;
            if (isMove)
            {
                Canvas.SetLeft(_thumb, newLeft);
                Canvas.SetTop(_thumb, newTop);
            }
            var hsb = new HSB
            {
                H = HSB.H, S = (newLeft + thumbW) / _canvas.ActualWidth,
                B = 1 - (newTop + thumbH) / _canvas.ActualHeight
            };
            SetValue(HSBPropertyKey, hsb);
            var currentColor = ColorUtil.ColorFromAhsb(1, HSB.H, HSB.S, HSB.B);
            if (SelectedColor != currentColor)
            {
                _isInnerUpdateSelectedColor = true;
                SelectedColor = currentColor;
            }
        }
        private void Thumb_DragDelta(object sender, DragDeltaEventArgs e)
        {
            var point = Mouse.GetPosition(_canvas);
            GetHSB(point);
        }
        private void Canvas_Loaded(object sender, RoutedEventArgs e)
        {
            var width = (int) _canvas.ActualWidth;
            var height = (int) _canvas.ActualHeight;
            var point = new Point(width - _thumb.ActualWidth / 2, -_thumb.ActualHeight / 2);
            Canvas.SetLeft(_thumb, point.X);
            Canvas.SetTop(_thumb, point.Y);
            var hsb = new HSB {H = _hueSliderColor.Value, S = HSB.S, B = HSB.B};
            SetValue(HSBPropertyKey, hsb);
        }
        private void HueSliderColor_OnValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
        {
            if (DoubleUtil.AreClose(HSB.H, e.NewValue))
                return;
            var hsb = new HSB {H = 1 - e.NewValue, S = HSB.S, B = HSB.B};
            SetValue(HSBPropertyKey, hsb);
            SetValue(HueColorPropertyKey, ColorUtil.ColorFromHsb(HSB.H, 1, 1));
            var newLeft = Canvas.GetLeft(_thumb);
            var newTop = Canvas.GetTop(_thumb);
            var point = new Point(newLeft, newTop);
            GetHSB(point, false);
        }
    }
    public enum ColorTypeEnum
    {
        RGB,
        HSL,
        HEX
    }
}

2)新增 ColorPicker.xaml 代码如下:

  • 在Canvas的背景中使用了DrawingBrush和DrawingGroup来创建渐变和几何形状。
  • 创建了一个线性渐变刷(LinearGradientBrush),渐变的起点是(0,0),终点是(1,0)。其中的GradientStop标签指定了两个渐变停止点,一个偏移量为0,颜色为白色,另一个偏移量为1,颜色绑定到了HueColor属性。
  • 接下来,同样方式创建了另一个线性渐变刷,渐变的起点是(0,0),终点是(0,1)。GradientStop指定了两个渐变停止点,一个偏移量为0,颜色为透明("#00000000"),另一个偏移量为1,颜色为黑色。
<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:controls="clr-namespace:WPFDevelopers.Controls"
    xmlns:convert="clr-namespace:WPFDevelopers.Converts"
    xmlns:helpers="clr-namespace:WPFDevelopers.Helpers"
    xmlns:input="clr-namespace:System.Windows.Input;assembly=PresentationCore"
    xmlns:po="http://schemas.microsoft.com/winfx/2006/xaml/presentation/options">
    <ResourceDictionary.MergedDictionaries>
        <ResourceDictionary Source="Basic/ControlBasic.xaml" />
    </ResourceDictionary.MergedDictionaries>
    <convert:ColorToBrushConverter x:Key="WD.ColorToBrushConverter" />
    <convert:ColorToRedConverter x:Key="WD.ColorToRedConverter" />
    <convert:ColorToGreenConverter x:Key="WD.ColorToGreenConverter" />
    <convert:ColorToBlueConverter x:Key="WD.ColorToBlueConverter" />
    <convert:ColorTypeToVisibilityConverter x:Key="WD.ColorTypeToVisibilityConverter" />
    <convert:ColorToStringConverter x:Key="WD.ColorToStringConverter" />
    <convert:HToColorConverter x:Key="WD.HToColorConverter" />
    <convert:SToColorConverter x:Key="WD.SToColorConverter" />
    <convert:LToColorConverter x:Key="WD.LToColorConverter" />
    <LinearGradientBrush x:Key="WD.ColorPickerRainbowBrush" po:Freeze="True">
        <GradientStop Color="#FF0000" />
        <GradientStop Offset="0.167" Color="#FF00FF" />
        <GradientStop Offset="0.334" Color="#0000FF" />
        <GradientStop Offset="0.501" Color="#00FFFF" />
        <GradientStop Offset="0.668" Color="#00FF00" />
        <GradientStop Offset="0.835" Color="#FFFF00" />
        <GradientStop Offset="1" Color="#FF0000" />
    </LinearGradientBrush>
    <ControlTemplate x:Key="WD.ColorPickerSliderThumbTemplate" TargetType="Thumb">
        <Border
            Width="{TemplateBinding Width}"
            Height="{TemplateBinding Height}"
            Background="Transparent"
            BorderBrush="White"
            BorderThickness="3"
            CornerRadius="{Binding ActualWidth, RelativeSource={RelativeSource Self}, Converter={StaticResource WD.HalfValueConverter}}" />
    </ControlTemplate>
    <Style x:Key="WD.ColorPickerSliderRepeatButtonBaseStyle" TargetType="RepeatButton">
        <Setter Property="OverridesDefaultStyle" Value="true" />
        <Setter Property="Background" Value="Transparent" />
        <Setter Property="Focusable" Value="false" />
        <Setter Property="IsTabStop" Value="false" />
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="RepeatButton">
                    <Rectangle
                        Width="{TemplateBinding Width}"
                        Height="{TemplateBinding Height}"
                        Fill="{TemplateBinding Background}" />
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
    <Style x:Key="WD.ColorPickerSlider" TargetType="{x:Type Slider}">
        <Setter Property="Background" Value="{StaticResource WD.ColorPickerRainbowBrush}" />
        <Setter Property="Stylus.IsPressAndHoldEnabled" Value="false" />
        <Setter Property="Orientation" Value="Horizontal" />
        <Setter Property="Height" Value="15" />
        <Setter Property="Margin" Value="4,0" />
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type Slider}">
                    <controls:SmallPanel>
                        <Border
                            MaxWidth="{TemplateBinding MaxWidth}"
                            Margin="{TemplateBinding Margin}"
                            Background="{TemplateBinding Background}"
                            CornerRadius="2" />
                        <Track x:Name="PART_Track" Orientation="{TemplateBinding Orientation}">
                            <Track.DecreaseRepeatButton>
                                <RepeatButton Command="{x:Static Slider.DecreaseLarge}" Style="{StaticResource WD.ColorPickerSliderRepeatButtonBaseStyle}" />
                            </Track.DecreaseRepeatButton>
                            <Track.IncreaseRepeatButton>
                                <RepeatButton Command="{x:Static Slider.IncreaseLarge}" Style="{StaticResource WD.ColorPickerSliderRepeatButtonBaseStyle}" />
                            </Track.IncreaseRepeatButton>
                            <Track.Thumb>
                                <Thumb
                                    x:Name="Thumb"
                                    Width="15"
                                    Height="15"
                                    Focusable="False"
                                    OverridesDefaultStyle="True"
                                    Template="{StaticResource WD.ColorPickerSliderThumbTemplate}">
                                    <Thumb.Effect>
                                        <DropShadowEffect Opacity=".6" ShadowDepth="0" />
                                    </Thumb.Effect>
                                </Thumb>
                            </Track.Thumb>
                        </Track>
                    </controls:SmallPanel>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
    <Style
        x:Key="WD.ColorPicker"
        BasedOn="{StaticResource WD.ControlBasicStyle}"
        TargetType="{x:Type controls:ColorPicker}">
        <Setter Property="Width" Value="260" />
        <Setter Property="Height" Value="200" />
        <Setter Property="Margin" Value="2" />
        <Setter Property="BorderThickness" Value="1" />
        <Setter Property="BorderBrush" Value="{DynamicResource WD.BaseSolidColorBrush}" />
        <Setter Property="Background" Value="{DynamicResource WD.BackgroundSolidColorBrush}" />
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type controls:ColorPicker}">
                    <Border
                        Margin="{TemplateBinding Margin}"
                        Background="{TemplateBinding Background}"
                        BorderBrush="{TemplateBinding BorderBrush}"
                        BorderThickness="{TemplateBinding BorderThickness}">
                        <Grid>
                            <Grid.RowDefinitions>
                                <RowDefinition />
                                <RowDefinition Height="Auto" />
                                <RowDefinition Height="Auto" />
                            </Grid.RowDefinitions>
                            <Canvas
                                x:Name="PART_Canvas"
                                Margin="1,1,1,0"
                                ClipToBounds="True">
                                <Canvas.Background>
                                    <DrawingBrush>
                                        <DrawingBrush.Drawing>
                                            <DrawingGroup>
                                                <GeometryDrawing>
                                                    <GeometryDrawing.Brush>
                                                        <LinearGradientBrush EndPoint="1,0">
                                                            <GradientStop Offset="0" Color="White" />
                                                            <GradientStop Offset="1" Color="{Binding HueColor, RelativeSource={RelativeSource TemplatedParent}}" />
                                                        </LinearGradientBrush>
                                                    </GeometryDrawing.Brush>
                                                    <GeometryDrawing.Geometry>
                                                        <RectangleGeometry Rect="0,0,5,5" />
                                                    </GeometryDrawing.Geometry>
                                                </GeometryDrawing>
                                                <GeometryDrawing>
                                                    <GeometryDrawing.Brush>
                                                        <LinearGradientBrush EndPoint="0,1">
                                                            <GradientStop Offset="0" Color="#00000000" />
                                                            <GradientStop Offset="1" Color="{StaticResource WD.BlackColor}" />
                                                        </LinearGradientBrush>
                                                    </GeometryDrawing.Brush>
                                                    <GeometryDrawing.Geometry>
                                                        <RectangleGeometry Rect="0,0,5,5" />
                                                    </GeometryDrawing.Geometry>
                                                </GeometryDrawing>
                                            </DrawingGroup>
                                        </DrawingBrush.Drawing>
                                    </DrawingBrush>
                                </Canvas.Background>
                                <Thumb
                                    x:Name="PART_Thumb"
                                    Width="15"
                                    Height="15"
                                    Background="Transparent"
                                    BorderBrush="White"
                                    BorderThickness="3">
                                    <Thumb.Template>
                                        <ControlTemplate TargetType="{x:Type Thumb}">
                                            <controls:SmallPanel>
                                                <Border
                                                    Background="{TemplateBinding Background}"
                                                    BorderBrush="{TemplateBinding BorderBrush}"
                                                    BorderThickness="{TemplateBinding BorderThickness}"
                                                    CornerRadius="{Binding ActualWidth, RelativeSource={RelativeSource Self}, Converter={StaticResource WD.HalfValueConverter}}"
                                                    SnapsToDevicePixels="True">
                                                    <Border.Effect>
                                                        <DropShadowEffect Opacity=".6" ShadowDepth="0" />
                                                    </Border.Effect>
                                                </Border>
                                            </controls:SmallPanel>
                                        </ControlTemplate>
                                    </Thumb.Template>
                                </Thumb>
                            </Canvas>
                            <Grid Grid.Row="1" Margin="6,5,6,0">
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition Width="Auto" />
                                    <ColumnDefinition />
                                </Grid.ColumnDefinitions>
                                <Ellipse
                                    Width="25"
                                    Height="25"
                                    Margin="0,0,4,0"
                                    Fill="{TemplateBinding SelectedColor,
                                                           Converter={StaticResource WD.ColorToBrushConverter}}">
                                    <Ellipse.Effect>
                                        <DropShadowEffect Opacity=".6" ShadowDepth="0" />
                                    </Ellipse.Effect>
                                </Ellipse>
                                <Slider
                                    Name="PART_HueSlider"
                                    Grid.Column="1"
                                    Width="Auto"
                                    IsMoveToPointEnabled="True"
                                    LargeChange="0.01"
                                    Maximum="1"
                                    SmallChange="0.01"
                                    Style="{StaticResource WD.ColorPickerSlider}"
                                    Value="1" />
                            </Grid>
                            <Grid
                                Grid.Row="2"
                                Margin="4"
                                VerticalAlignment="Center">
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition Width="Auto" />
                                    <ColumnDefinition />
                                </Grid.ColumnDefinitions>
                                <Grid.Resources>
                                    <Style TargetType="{x:Type StackPanel}">
                                        <Setter Property="Margin" Value="4,0" />
                                    </Style>
                                    <Style
                                        x:Key="WD.TextBoxColorPicker"
                                        BasedOn="{StaticResource WD.DefaultTextBox}"
                                        TargetType="{x:Type TextBox}">
                                        <Setter Property="VerticalContentAlignment" Value="Center" />
                                        <Setter Property="TextAlignment" Value="Center" />
                                        <Setter Property="Width" Value="50" />
                                    </Style>
                                    <Style BasedOn="{StaticResource WD.NumericBox}" TargetType="{x:Type controls:NumericBox}">
                                        <Setter Property="VerticalContentAlignment" Value="Center" />
                                        <Setter Property="TextAlignment" Value="Center" />
                                        <Setter Property="Width" Value="50" />
                                        <Setter Property="UpDownButtonsWidth" Value="0" />
                                        <Setter Property="Maximum" Value="255" />
                                        <Setter Property="Minimum" Value="0" />
                                    </Style>
                                    <Style TargetType="{x:Type TextBlock}">
                                        <Setter Property="HorizontalAlignment" Value="Center" />
                                        <Setter Property="Foreground" Value="{DynamicResource WD.PrimaryTextSolidColorBrush}" />
                                        <Setter Property="FontSize" Value="10" />
                                    </Style>
                                </Grid.Resources>
                                <Button
                                    Name="PART_Button"
                                    Grid.Column="0"
                                    Width="30"
                                    Height="30"
                                    Margin="0,0,4,0"
                                    helpers:ElementHelper.IsRound="True"
                                    Style="{StaticResource WD.NormalButton}">
                                    <controls:PathIcon Kind="UnfoldMore" />
                                </Button>
                                <UniformGrid
                                    Grid.Column="1"
                                    Rows="1"
                                    Visibility="{Binding ColorType, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource WD.ColorTypeToVisibilityConverter}, ConverterParameter={x:Static controls:ColorTypeEnum.RGB}}">
                                    <StackPanel>
                                        <controls:NumericBox Value="{Binding SelectedColor, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource WD.ColorToRedConverter}}" />
                                        <TextBlock Text="R" />
                                    </StackPanel>
                                    <StackPanel>
                                        <controls:NumericBox Value="{Binding SelectedColor, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource WD.ColorToGreenConverter}}" />
                                        <TextBlock Text="G" />
                                    </StackPanel>
                                    <StackPanel>
                                        <controls:NumericBox Value="{Binding SelectedColor, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource WD.ColorToBlueConverter}}" />
                                        <TextBlock Text="B" />
                                    </StackPanel>
                                </UniformGrid>
                                <UniformGrid
                                    Grid.Column="1"
                                    Rows="1"
                                    Visibility="{Binding ColorType, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource WD.ColorTypeToVisibilityConverter}, ConverterParameter={x:Static controls:ColorTypeEnum.HSL}}">
                                    <StackPanel>
                                        <TextBox
                                            helpers:TextBoxHelper.AllowOnlyNumericInput="True"
                                            helpers:TextBoxHelper.IsEnterUpdateEnabled="True"
                                            helpers:TextBoxHelper.SelectAllOnClick="True"
                                            Style="{StaticResource WD.TextBoxColorPicker}"
                                            Text="{Binding SelectedColor, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource WD.HToColorConverter}}" />
                                        <TextBlock Text="H" />
                                    </StackPanel>
                                    <StackPanel Grid.Column="1">
                                        <TextBox
                                            helpers:TextBoxHelper.IsEnterUpdateEnabled="True"
                                            helpers:TextBoxHelper.SelectAllOnClick="True"
                                            Style="{StaticResource WD.TextBoxColorPicker}"
                                            Text="{Binding SelectedColor, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource WD.SToColorConverter}}" />
                                        <TextBlock Text="S" />
                                    </StackPanel>
                                    <StackPanel Grid.Column="2">
                                        <TextBox
                                            helpers:TextBoxHelper.IsEnterUpdateEnabled="True"
                                            helpers:TextBoxHelper.SelectAllOnClick="True"
                                            Style="{StaticResource WD.TextBoxColorPicker}"
                                            Text="{Binding SelectedColor, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource WD.LToColorConverter}}" />
                                        <TextBlock Text="L" />
                                    </StackPanel>
                                </UniformGrid>
                                <StackPanel
                                    Grid.Column="1"
                                    Margin="12,0"
                                    Visibility="{Binding ColorType, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource WD.ColorTypeToVisibilityConverter}, ConverterParameter={x:Static controls:ColorTypeEnum.HEX}}">
                                    <TextBox
                                        helpers:TextBoxHelper.IsEnterUpdateEnabled="True"
                                        helpers:TextBoxHelper.SelectAllOnClick="True"
                                        MaxLength="9"
                                        Text="{Binding SelectedColor, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource WD.ColorToStringConverter}}"
                                        TextAlignment="Center" />
                                    <TextBlock Text="HEX" />
                                </StackPanel>
                            </Grid>
                        </Grid>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
    <Style BasedOn="{StaticResource WD.ColorPicker}" TargetType="{x:Type controls:ColorPicker}" />
</ResourceDictionary>

3)新增颜色转换工具类 ColorUtil.cs 代码如下:

  • 包含了将 HSL 颜色空间转换为 RGB 颜色空间以及将 RGB 颜色空间转换为 HSL 颜色空间的方法。
  • ConvertHSLToColor 方法用于将 HSL 颜色转换为 RGB 颜色。HSLToRgb 方法实现了将 HSL 颜色转换为 RGB 颜色的算法,而 SetColor 方法用于在计算过程中设置颜色值。
  • RgbToHSL 方法用于将 RGB 颜色转换为 HSL 颜色。HsbFromColor 方法则实现了从 RGB 颜色获取 HSB(色相、饱和度、亮度)的算法,并修改了传入的引用类型参数。ColorFromAhsb 和 ColorFromHsb 方法分别用于根据 AHSB(透明度、色相、饱和度、亮度)和 HSB 值创建颜色对象。
using System;
using System.Windows.Media;
using WPFDevelopers.Controls;
namespace WPFDevelopers.Utilities
{
    public static class ColorUtil
    {
        public static Color ConvertHSLToColor(Color color, double h = double.NaN, double sl = double.NaN,
            double l = double.NaN)
        {
            var hsl = RgbToHSL(color);
            if (!double.IsNaN(h))
                hsl.H = h;
            if (!double.IsNaN(sl))
                hsl.S = sl;
            if (!double.IsNaN(l))
                hsl.L = l;
            var rgb = HSLToRgb(hsl);
            return rgb;
        }
        private static Color HSLToRgb(HSL hslColor)
        {
            var rgbColor = new Color();
            if (hslColor.S == 0)
            {
                rgbColor.R = (byte) (hslColor.L * 255);
                rgbColor.G = (byte) (hslColor.L * 255);
                rgbColor.B = (byte) (hslColor.L * 255);
                rgbColor.A = (byte) (hslColor.A * 255);
                return rgbColor;
            }
            double t1;
            if (hslColor.L < 0.5)
                t1 = hslColor.L * (1.0 + hslColor.S);
            else
                t1 = hslColor.L + hslColor.S - hslColor.L * hslColor.S;
            var t2 = 2.0 * hslColor.L - t1;
            var h = hslColor.H / 360;
            var tR = h + 1.0 / 3.0;
            var r = SetColor(t1, t2, tR);
            var tG = h;
            var g = SetColor(t1, t2, tG);
            var tB = h - 1.0 / 3.0;
            var b = SetColor(t1, t2, tB);
            rgbColor.R = (byte) (r * 255);
            rgbColor.G = (byte) (g * 255);
            rgbColor.B = (byte) (b * 255);
            rgbColor.A = (byte) (hslColor.A * 255);
            return rgbColor;
        }
        private static double SetColor(double t1, double t2, double t3)
        {
            if (t3 < 0) t3 += 1.0;
            if (t3 > 1) t3 -= 1.0;
            double color;
            if (6.0 * t3 < 1)
                color = t2 + (t1 - t2) * 6.0 * t3;
            else if (2.0 * t3 < 1)
                color = t1;
            else if (3.0 * t3 < 2)
                color = t2 + (t1 - t2) * (2.0 / 3.0 - t3) * 6.0;
            else
                color = t2;
            return color;
        }
        public static HSL RgbToHSL(Color rgbColor)
        {
            var hslColor = new HSL();
            var r = (double) rgbColor.R / 255;
            var g = (double) rgbColor.G / 255;
            var b = (double) rgbColor.B / 255;
            var a = (double) rgbColor.A / 255;
            var min = Math.Min(r, Math.Min(g, b));
            var max = Math.Max(r, Math.Max(g, b));
            var delta = max - min;
            if (max == min)
            {
                hslColor.H = 0;
                hslColor.S = 0;
                hslColor.L = max;
                return hslColor;
            }
            hslColor.L = (min + max) / 2;
            if (hslColor.L < 0.5)
                hslColor.S = delta / (max + min);
            else
                hslColor.S = delta / (2.0 - max - min);
            if (r == max) hslColor.H = (g - b) / delta;
            if (g == max) hslColor.H = 2.0 + (b - r) / delta;
            if (b == max) hslColor.H = 4.0 + (r - g) / delta;
            hslColor.H *= 60;
            if (hslColor.H < 0) hslColor.H += 360;
            hslColor.A = a;
            return hslColor;
        }
        public static void HsbFromColor(Color C, ref double H, ref double S, ref double B)
        {
            var r = C.R / 255d;
            var g = C.G / 255d;
            var b = C.B / 255d;
            var max = Math.Max(Math.Max(r, g), b);
            var min = Math.Min(Math.Min(r, g), b);
            var delta = max - min;
            var hue = 0d;
            var saturation = DoubleUtil.GreaterThan(max, 0) ? delta / max : 0.0;
            var brightness = max;
            if (!DoubleUtil.IsZero(delta))
            {
                if (DoubleUtil.AreClose(r, max))
                    hue = (g - b) / delta;
                else if (DoubleUtil.AreClose(g, max))
                    hue = 2 + (b - r) / delta;
                else if (DoubleUtil.AreClose(b, max))
                    hue = 4 + (r - g) / delta;
                hue = hue * 60;
                if (DoubleUtil.LessThan(hue, 0d))
                    hue += 360;
            }
            H = hue / 360d;
            S = saturation;
            B = brightness;
        }
        public static Color ColorFromAhsb(double a, double h, double s, double b)
        {
            var r = ColorFromHsb(h, s, b);
            r.A = (byte) Math.Round(a * 255d);
            return r;
        }
        public static Color ColorFromHsb(double H, double S, double B)
        {
            double red = 0.0, green = 0.0, blue = 0.0;
            if (DoubleUtil.IsZero(S))
            {
                red = green = blue = B;
            }
            else
            {
                var h = DoubleUtil.IsOne(H) ? 0d : H * 6.0;
                var i = (int) Math.Floor(h);
                var f = h - i;
                var r = B * (1.0 - S);
                var s = B * (1.0 - S * f);
                var t = B * (1.0 - S * (1.0 - f));
                switch (i)
                {
                    case 0:
                        red = B;
                        green = t;
                        blue = r;
                        break;
                    case 1:
                        red = s;
                        green = B;
                        blue = r;
                        break;
                    case 2:
                        red = r;
                        green = B;
                        blue = t;
                        break;
                    case 3:
                        red = r;
                        green = s;
                        blue = B;
                        break;
                    case 4:
                        red = t;
                        green = r;
                        blue = B;
                        break;
                    case 5:
                        red = B;
                        green = r;
                        blue = s;
                        break;
                }
            }
            return Color.FromRgb((byte) Math.Round(red * 255.0), (byte) Math.Round(green * 255.0),
                (byte) Math.Round(blue * 255.0));
        }
    }
}

4)示例 代码如下:

xmlns:wd="https://github.com/WPFDevelopersOrg/WPFDevelopers"
<wd:ColorPicker />

效果图

到此这篇关于基于WPF实现颜色选择器控件的文章就介绍到这了,更多相关WPF颜色选择内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • WinForm实现仿视频播放器左下角滚动新闻效果的方法

    WinForm实现仿视频播放器左下角滚动新闻效果的方法

    这篇文章主要介绍了WinForm实现仿视频播放器左下角滚动新闻效果的方法,涉及WinForm窗口滚动字幕设置的实现技巧,具有一定参考借鉴价值,需要的朋友可以参考下
    2015-08-08
  • Winform+.Net6实现图片拖拽上传功能

    Winform+.Net6实现图片拖拽上传功能

    这篇文章主要为大家详细介绍了如何使用WinformPictureBox控件+.Net6 WebApi实现图片拖拽上传功能,文中的示例代码讲解详细,感兴趣的可以学习一下
    2023-09-09
  • c#中LINQ的基本用法(三)

    c#中LINQ的基本用法(三)

    这篇文章介绍了c#中LINQ的基本用法,文中通过示例代码介绍的非常详细。对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下的相关资料
    2022-04-04
  • C#登入实例

    C#登入实例

    本篇文章通过截图的方式向大家展示C#程序登陆实现的全过程,利用了C#三层架构的编写方法,希望对大家今后编写代码有所帮助
    2016-11-11
  • C#利用OpenCvSharp实现玉米粒计数

    C#利用OpenCvSharp实现玉米粒计数

    这篇文章主要为大家详细介绍了C#如何结合OpenCVSharp4实现玉米粒计数,文中的示例代码简洁易懂,具有一定的学习价值,需要的小伙伴可以参考下
    2023-11-11
  • 基于WPF实现代码查看器控件

    基于WPF实现代码查看器控件

    这篇文章主要为大家详细介绍了WPF如何实现代码查看器控件,文中的示例代码讲解详细,对我们学习或工作有一定帮助,感兴趣的小伙伴可以了解一下
    2022-11-11
  • c#中将uint值转换成int的实例方法

    c#中将uint值转换成int的实例方法

    在本文里小编给大家整理的是关于c#中将uint值转换成int的实例方法,需要的朋友们学习参考下。
    2019-08-08
  • 浅析C#中goto跳转语句的用法

    浅析C#中goto跳转语句的用法

    在我们日常工作中常用的C#跳转语句有break、continue、return,但是还有一个C#跳转语句很多同学可能都比较的陌生就是goto,下面我们就来看看goto跳转语句的用法吧
    2024-03-03
  • 利用C#实现可以继承的"枚举"

    利用C#实现可以继承的"枚举"

    工作中许多代码中用到枚举(enum),更用到了需要继承的枚举,由于C#的枚举不允许被继承,所以本文就来模拟实现一个可以继承的仿枚举吧
    2023-05-05
  • 轻松学习C#的基础入门

    轻松学习C#的基础入门

    轻松学习C#的基础入门,了解C#最基本的知识点,C#是一种简洁的,类型安全的一种完全面向对象的开发语言,是Microsoft专门基于.NET Framework平台开发的而量身定做的高级程序设计语言,需要的朋友可以参考下
    2015-11-11

最新评论