百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术教程 > 正文

WPF 实现颜色选择器控件 wpf颜色选择对话框

suiw9 2024-12-19 16:23 14 浏览 0 评论

WPF 实现颜色选择器控件

控件名:ColorPicker

作 者:WPFDevelopersOrg - 黄佳 | 驚鏵

原文链接[1]:https://github.com/WPFDevelopersOrg/WPFDevelopers

  • 框架使用.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 != )
_hueSliderColor.ValueChanged -= HueSliderColor_OnValueChanged;
_canvas = GetTemplateChild(CanvasTemplateName) as Canvas;
if (_canvas != )
{
_canvas.Loaded += Canvas_Loaded;
_canvas.MouseUp += Canvas_MouseUp;
}

_thumb = GetTemplateChild(ThumbTemplateName) as Thumb;
if (_thumb != )
_thumb.DragDelta += Thumb_DragDelta;
_hueSliderColor = GetTemplateChild(HueSliderColorTemplateName) as Slider;
if (_hueSliderColor != )
_hueSliderColor.ValueChanged += HueSliderColor_OnValueChanged;

_button = GetTemplateChild(ButtonTemplateName) as Button;
currentGridStateIndex = 0;
colorTypeEnums = (ColorTypeEnum[]) Enum.GetValues(typeof(ColorTypeEnum));
if (_button != )
_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 />

参考资料

[1]

原文链接: https://github.com/WPFDevelopersOrg/WPFDevelopers


相关推荐

俄罗斯的 HTTPS 也要被废了?(俄罗斯网站关闭)

发布该推文的ScottHelme是一名黑客,SecurityHeaders和ReportUri的创始人、Pluralsight作者、BBC常驻黑客。他表示,CAs现在似乎正在停止为俄罗斯域名颁发...

如何强制所有流量使用 HTTPS一网上用户

如何强制所有流量使用HTTPS一网上用户使用.htaccess强制流量到https的最常见方法可能是使用.htaccess重定向请求。.htaccess是一个简单的文本文件,简称为“.h...

https和http的区别(https和http有何区别)

“HTTPS和HTTP都是数据传输的应用层协议,区别在于HTTPS比HTTP安全”。区别在哪里,我们接着往下看:...

快码住!带你十分钟搞懂HTTP与HTTPS协议及请求的区别

什么是协议?网络协议是计算机之间为了实现网络通信从而达成的一种“约定”或“规则”,正是因为这个“规则”的存在,不同厂商的生产设备、及不同操作系统组成的计算机之间,才可以实现通信。简单来说,计算机与网络...

简述HTTPS工作原理(简述https原理,以及与http的区别)

https是在http协议的基础上加了一层SSL(由网景公司开发),加密由ssl实现,它的目的是为用户提供对网站服务器的身份认证(需要CA),以至于保护交换数据的隐私和完整性,原理如图示。1、客户端发...

21、HTTPS 有几次握手和挥手?HTTPS 的原理什么是(高薪 常问)

HTTPS是3次握手和4次挥手,和HTTP是一样的。HTTPS的原理...

一次安全可靠的通信——HTTPS原理

为什么HTTPS协议就比HTTP安全呢?一次安全可靠的通信应该包含什么东西呢,这篇文章我会尝试讲清楚这些细节。Alice与Bob的通信...

为什么有的网站没有使用https(为什么有的网站点不开)

有的网站没有使用HTTPS的原因可能涉及多个方面,以下是.com、.top域名的一些见解:服务器性能限制:HTTPS使用公钥加密和私钥解密技术,这要求服务器具备足够的计算能力来处理加解密操作。如果服务...

HTTPS是什么?加密原理和证书。SSL/TLS握手过程

秘钥的产生过程非对称加密...

图解HTTPS「转」(图解http 完整版 彩色版 pdf)

我们都知道HTTPS能够加密信息,以免敏感信息被第三方获取。所以很多银行网站或电子邮箱等等安全级别较高的服务都会采用HTTPS协议。...

HTTP 和 HTTPS 有何不同?一文带你全面了解

随着互联网时代的高速发展,Web服务器和客户端之间的安全通信需求也越来越高。HTTP和HTTPS是两种广泛使用的Web通信协议。本文将介绍HTTP和HTTPS的区别,并探讨为什么HTTPS已成为We...

HTTP与HTTPS的区别,详细介绍(http与https有什么区别)

HTTP与HTTPS介绍超文本传输协议HTTP协议被用于在Web浏览器和网站服务器之间传递信息,HTTP协议以明文方式发送内容,不提供任何方式的数据加密,如果攻击者截取了Web浏览器和网站服务器之间的...

一文让你轻松掌握 HTTPS(https详解)

一文让你轻松掌握HTTPS原文作者:UC国际研发泽原写在最前:欢迎你来到“UC国际技术”公众号,我们将为大家提供与客户端、服务端、算法、测试、数据、前端等相关的高质量技术文章,不限于原创与翻译。...

如何在Spring Boot应用程序上启用HTTPS?

HTTPS是HTTP的安全版本,旨在提供传输层安全性(TLS)[安全套接字层(SSL)的后继产品],这是地址栏中的挂锁图标,用于在Web服务器和浏览器之间建立加密连接。HTTPS加密每个数据包以安全方...

一文彻底搞明白Http以及Https(http0)

早期以信息发布为主的Web1.0时代,HTTP已可以满足绝大部分需要。证书费用、服务器的计算资源都比较昂贵,作为HTTP安全扩展的HTTPS,通常只应用在登录、交易等少数环境中。但随着越来越多的重要...

取消回复欢迎 发表评论: