重命名
This commit is contained in:
25
NeoUI/Melskin/Controls/ColorPicker/ColorInputMode.cs
Normal file
25
NeoUI/Melskin/Controls/ColorPicker/ColorInputMode.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
namespace VariaStudio.Controls;
|
||||
// 定义颜色输入模式的枚举
|
||||
/// <summary>
|
||||
/// 定义了颜色输入模式的枚举。此枚举用于指定在颜色选择器中用户可以选择的颜色表示方式。
|
||||
/// </summary>
|
||||
public enum ColorInputMode
|
||||
{
|
||||
/// <summary>
|
||||
/// 表示颜色输入模式为十六进制格式。在这种模式下,用户可以使用十六进制代码(如 #FF5733)来指定颜色。
|
||||
/// </summary>
|
||||
HEX,
|
||||
|
||||
/// <summary>
|
||||
/// 表示颜色输入模式为HSB(色相、饱和度、亮度)格式。在这种模式下,用户可以通过调整色相、饱和度和亮度来指定颜色。
|
||||
/// </summary>
|
||||
HSB,
|
||||
|
||||
/// <summary>
|
||||
/// 表示颜色输入模式为RGB格式。在这种模式下,用户可以通过分别设置红色、绿色和蓝色的分量值来指定颜色。
|
||||
/// </summary>
|
||||
RGB,
|
||||
}
|
||||
|
||||
|
||||
|
||||
234
NeoUI/Melskin/Controls/ColorPicker/ColorPanel.xaml
Normal file
234
NeoUI/Melskin/Controls/ColorPicker/ColorPanel.xaml
Normal file
@@ -0,0 +1,234 @@
|
||||
<ResourceDictionary
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:assists="clr-namespace:VariaStudio.Assists"
|
||||
xmlns:controls="clr-namespace:VariaStudio.Controls"
|
||||
xmlns:converters="clr-namespace:VariaStudio.Converters"
|
||||
xmlns:internal="clr-namespace:VariaStudio.Converters.Internal"
|
||||
xmlns:markup="clr-namespace:VariaStudio.Markup"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
<!-- 1. ColorPanel 样式 -->
|
||||
<Style TargetType="{x:Type controls:ColorPanel}">
|
||||
<Setter Property="Padding" Value="4" />
|
||||
<Setter Property="assists:ControlAssist.CornerRadius" Value="8" />
|
||||
<Setter Property="Background" Value="{DynamicResource ControlBackgroundNormalBrush}" />
|
||||
<Setter Property="Width" Value="340" />
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="{x:Type controls:ColorPanel}">
|
||||
<ControlTemplate.Resources>
|
||||
<!-- 为每种模式定义一个数据模板 -->
|
||||
<DataTemplate x:Key="HexInputTemplate">
|
||||
<TextBox HorizontalContentAlignment="Center" Text="{Binding SelectedColor, RelativeSource={RelativeSource AncestorType=controls:ColorPanel}, Converter={x:Static internal:ColorToHexConverter.Instance}, UpdateSourceTrigger=PropertyChanged}" />
|
||||
</DataTemplate>
|
||||
|
||||
<DataTemplate x:Key="HsbInputTemplate">
|
||||
<UniformGrid Rows="1">
|
||||
<TextBox HorizontalContentAlignment="Center" Text="{Binding Hue, RelativeSource={RelativeSource AncestorType=controls:ColorPanel}, UpdateSourceTrigger=PropertyChanged}" />
|
||||
<TextBox HorizontalContentAlignment="Center" Text="{Binding Saturation, RelativeSource={RelativeSource AncestorType=controls:ColorPanel}, Converter={x:Static converters:PercentageConverter.Instance}, UpdateSourceTrigger=PropertyChanged}" />
|
||||
<TextBox HorizontalContentAlignment="Center" Text="{Binding Brightness, RelativeSource={RelativeSource AncestorType=controls:ColorPanel}, Converter={x:Static converters:PercentageConverter.Instance}, UpdateSourceTrigger=PropertyChanged}" />
|
||||
</UniformGrid>
|
||||
</DataTemplate>
|
||||
|
||||
<DataTemplate x:Key="RgbInputTemplate">
|
||||
<UniformGrid Rows="1">
|
||||
<TextBox HorizontalContentAlignment="Center" Text="{Binding Red, RelativeSource={RelativeSource AncestorType=controls:ColorPanel}, UpdateSourceTrigger=PropertyChanged}" />
|
||||
<TextBox HorizontalContentAlignment="Center" Text="{Binding Green, RelativeSource={RelativeSource AncestorType=controls:ColorPanel}, UpdateSourceTrigger=PropertyChanged}" />
|
||||
<TextBox HorizontalContentAlignment="Center" Text="{Binding Blue, RelativeSource={RelativeSource AncestorType=controls:ColorPanel}, UpdateSourceTrigger=PropertyChanged}" />
|
||||
</UniformGrid>
|
||||
</DataTemplate>
|
||||
</ControlTemplate.Resources>
|
||||
|
||||
<Grid>
|
||||
<Border
|
||||
Background="{TemplateBinding Background}"
|
||||
BorderBrush="{TemplateBinding BorderBrush}"
|
||||
BorderThickness="{TemplateBinding BorderThickness}"
|
||||
CornerRadius="{TemplateBinding assists:ControlAssist.CornerRadius}" />
|
||||
<!-- Effect="{DynamicResource PopupShadow}" -->
|
||||
<StackPanel Margin="{TemplateBinding Padding}">
|
||||
<Canvas
|
||||
ClipToBounds="True"
|
||||
Height="150"
|
||||
x:Name="PART_ColorCanvas">
|
||||
<Rectangle
|
||||
Fill="{Binding Path=Hue, RelativeSource={RelativeSource TemplatedParent}, Converter={x:Static internal:HueToBrushConverter.Instance}}"
|
||||
Height="{Binding ActualHeight, ElementName=PART_ColorCanvas}"
|
||||
Width="{Binding ActualWidth, ElementName=PART_ColorCanvas}" />
|
||||
<Rectangle Height="{Binding ActualHeight, ElementName=PART_ColorCanvas}" Width="{Binding ActualWidth, ElementName=PART_ColorCanvas}">
|
||||
<Rectangle.Fill>
|
||||
<LinearGradientBrush EndPoint="1,0" StartPoint="0,0">
|
||||
<GradientStop Color="White" Offset="0" />
|
||||
<GradientStop Color="Transparent" Offset="1" />
|
||||
</LinearGradientBrush>
|
||||
</Rectangle.Fill>
|
||||
</Rectangle>
|
||||
<Rectangle Height="{Binding ActualHeight, ElementName=PART_ColorCanvas}" Width="{Binding ActualWidth, ElementName=PART_ColorCanvas}">
|
||||
<Rectangle.Fill>
|
||||
<LinearGradientBrush EndPoint="0,1" StartPoint="0,0">
|
||||
<GradientStop Color="Transparent" Offset="0" />
|
||||
<GradientStop Color="Black" Offset="1" />
|
||||
</LinearGradientBrush>
|
||||
</Rectangle.Fill>
|
||||
</Rectangle>
|
||||
<Thumb
|
||||
Height="16"
|
||||
Margin="-8,-8,0,0"
|
||||
Width="16"
|
||||
x:Name="PART_ColorSelector">
|
||||
<Thumb.Template>
|
||||
<ControlTemplate TargetType="Thumb">
|
||||
<Grid>
|
||||
<Ellipse
|
||||
Fill="Transparent"
|
||||
Stroke="{DynamicResource BackgroundFloatingBrush}"
|
||||
StrokeThickness="2" />
|
||||
<Ellipse
|
||||
Fill="Transparent"
|
||||
Margin="1"
|
||||
Stroke="{DynamicResource ControlBackgroundNormalBrush}"
|
||||
StrokeThickness="1" />
|
||||
</Grid>
|
||||
</ControlTemplate>
|
||||
</Thumb.Template>
|
||||
</Thumb>
|
||||
</Canvas>
|
||||
<Grid Margin="0,12,0,0">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<StackPanel
|
||||
Grid.Column="0"
|
||||
Margin="0,0,12,0"
|
||||
VerticalAlignment="Center">
|
||||
<Slider
|
||||
Maximum="360"
|
||||
Minimum="0"
|
||||
Style="{DynamicResource ColorSliderStyle}"
|
||||
Value="{Binding Hue, RelativeSource={RelativeSource TemplatedParent}, Mode=TwoWay}">
|
||||
<Slider.Background>
|
||||
<LinearGradientBrush EndPoint="1,0" StartPoint="0,0">
|
||||
<GradientStop Color="Red" Offset="0.0" />
|
||||
<GradientStop Color="Yellow" Offset="0.166" />
|
||||
<GradientStop Color="Green" Offset="0.333" />
|
||||
<GradientStop Color="Cyan" Offset="0.5" />
|
||||
<GradientStop Color="Blue" Offset="0.666" />
|
||||
<GradientStop Color="Magenta" Offset="0.833" />
|
||||
<GradientStop Color="Red" Offset="1.0" />
|
||||
</LinearGradientBrush>
|
||||
</Slider.Background>
|
||||
</Slider>
|
||||
<Slider
|
||||
Margin="0,8,0,0"
|
||||
Maximum="255"
|
||||
Minimum="0"
|
||||
Style="{DynamicResource ColorSliderStyle}"
|
||||
Value="{Binding Alpha, RelativeSource={RelativeSource TemplatedParent}, Mode=TwoWay}">
|
||||
<Slider.Background>
|
||||
<LinearGradientBrush EndPoint="1,0" StartPoint="0,0">
|
||||
<GradientStop Color="Transparent" Offset="0.0" />
|
||||
<GradientStop Offset="1.0">
|
||||
<GradientStop.Color>
|
||||
<Binding
|
||||
Converter="{x:Static internal:ColorToOpaqueColorConverter.Instance}"
|
||||
Path="SelectedColor"
|
||||
RelativeSource="{RelativeSource TemplatedParent}" />
|
||||
</GradientStop.Color>
|
||||
</GradientStop>
|
||||
</LinearGradientBrush>
|
||||
</Slider.Background>
|
||||
</Slider>
|
||||
</StackPanel>
|
||||
|
||||
<Border
|
||||
Background="{DynamicResource CheckerboardBrushLarge}"
|
||||
BorderBrush="{DynamicResource BorderNormalBrush}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="4"
|
||||
Grid.Column="1"
|
||||
Height="36"
|
||||
Width="36">
|
||||
<Rectangle RadiusX="3" RadiusY="3">
|
||||
<Rectangle.Fill>
|
||||
<SolidColorBrush Color="{Binding SelectedColor, RelativeSource={RelativeSource TemplatedParent}}" />
|
||||
</Rectangle.Fill>
|
||||
</Rectangle>
|
||||
</Border>
|
||||
</Grid>
|
||||
<Grid Margin="0,12,0,0">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="64" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<ComboBox
|
||||
Grid.Column="0"
|
||||
HorizontalContentAlignment="Center"
|
||||
ItemsSource="{markup:EnumSource EnumType=controls:ColorInputMode}"
|
||||
SelectedItem="{Binding ColorInputMode, RelativeSource={RelativeSource TemplatedParent}, Mode=TwoWay}"
|
||||
x:Name="ColorModeComboBox" />
|
||||
<ContentControl Grid.Column="1">
|
||||
<ContentControl.Style>
|
||||
<Style TargetType="ContentControl">
|
||||
<Style.Triggers>
|
||||
<!-- 使用DataTrigger来切换ContentTemplate -->
|
||||
<DataTrigger Binding="{Binding ColorInputMode, RelativeSource={RelativeSource AncestorType=controls:ColorPanel}}" Value="{x:Static controls:ColorInputMode.HEX}">
|
||||
<Setter Property="ContentTemplate" Value="{StaticResource HexInputTemplate}" />
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding ColorInputMode, RelativeSource={RelativeSource AncestorType=controls:ColorPanel}}" Value="{x:Static controls:ColorInputMode.HSB}">
|
||||
<Setter Property="ContentTemplate" Value="{StaticResource HsbInputTemplate}" />
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding ColorInputMode, RelativeSource={RelativeSource AncestorType=controls:ColorPanel}}" Value="{x:Static controls:ColorInputMode.RGB}">
|
||||
<Setter Property="ContentTemplate" Value="{StaticResource RgbInputTemplate}" />
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</ContentControl.Style>
|
||||
</ContentControl>
|
||||
<TextBox
|
||||
Grid.Column="2"
|
||||
HorizontalContentAlignment="Center"
|
||||
Text="{Binding Alpha, RelativeSource={RelativeSource TemplatedParent}, Converter={x:Static internal:AlphaToPercentConverter.Instance}, UpdateSourceTrigger=PropertyChanged}"
|
||||
x:Name="AlphaTextBox" />
|
||||
</Grid>
|
||||
<ItemsControl ItemsSource="{Binding PresetColors, RelativeSource={RelativeSource TemplatedParent}}" Margin="0,12,0,-6">
|
||||
<ItemsControl.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<WrapPanel />
|
||||
</ItemsPanelTemplate>
|
||||
</ItemsControl.ItemsPanel>
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Button
|
||||
Command="{Binding SelectPresetColorCommand, RelativeSource={RelativeSource AncestorType=controls:ColorPanel}}"
|
||||
CommandParameter="{Binding}"
|
||||
Height="22"
|
||||
Margin="0,0,8,8"
|
||||
ToolTip="{Binding}"
|
||||
Width="22">
|
||||
<Button.Template>
|
||||
<ControlTemplate TargetType="Button">
|
||||
<Border
|
||||
Background="{DynamicResource CheckerboardBrushLarge}"
|
||||
BorderBrush="{DynamicResource BorderNormalBrush}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="2">
|
||||
<Rectangle RadiusX="1" RadiusY="1">
|
||||
<Rectangle.Fill>
|
||||
<SolidColorBrush Color="{Binding}" />
|
||||
</Rectangle.Fill>
|
||||
</Rectangle>
|
||||
</Border>
|
||||
</ControlTemplate>
|
||||
</Button.Template>
|
||||
</Button>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
</ResourceDictionary>
|
||||
441
NeoUI/Melskin/Controls/ColorPicker/ColorPanel.xaml.cs
Normal file
441
NeoUI/Melskin/Controls/ColorPicker/ColorPanel.xaml.cs
Normal file
@@ -0,0 +1,441 @@
|
||||
using System.Diagnostics;
|
||||
using System.Windows.Controls.Primitives;
|
||||
using System.Windows.Input;
|
||||
using VariaStudio.Utilities;
|
||||
|
||||
namespace VariaStudio.Controls;
|
||||
|
||||
/// <summary>
|
||||
/// ColorPanel 控件提供了一个用于选择颜色的界面。用户可以通过此控件来选取特定的颜色,支持多种颜色输入模式,如HEX、RGB和HSV。
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 该控件定义了多个依赖属性来表示颜色的不同组成部分(如Alpha透明度、Hue色调、Saturation饱和度、Brightness亮度以及RGB值),
|
||||
/// 并且允许通过绑定或其他方式动态地改变这些属性。此外,还支持预设颜色列表的选择功能。
|
||||
/// </remarks>
|
||||
[TemplatePart(Name = "PART_ColorCanvas", Type = typeof(Canvas))]
|
||||
[TemplatePart(Name = "PART_ColorSelector", Type = typeof(Thumb))]
|
||||
public class ColorPanel : Control
|
||||
{
|
||||
private Thumb? colorSelector;
|
||||
private Canvas? colorCanvas;
|
||||
private bool isUpdating;
|
||||
|
||||
#region Events
|
||||
|
||||
/// <summary>
|
||||
/// 当颜色被选中时触发的路由事件。此事件允许监听者响应颜色选择的变化。
|
||||
/// </summary>
|
||||
public static readonly RoutedEvent ColorSelectedEvent =
|
||||
EventManager.RegisterRoutedEvent(nameof(ColorSelected), RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(ColorPanel));
|
||||
|
||||
/// <summary>
|
||||
/// 当颜色被选中时触发的事件。此事件允许监听者响应颜色选择的变化,通常用于更新UI或执行其他逻辑。
|
||||
/// </summary>
|
||||
public event RoutedEventHandler ColorSelected
|
||||
{
|
||||
add => AddHandler(ColorSelectedEvent, value);
|
||||
remove => RemoveHandler(ColorSelectedEvent, value);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Commands
|
||||
|
||||
/// <summary>
|
||||
/// 选择预设颜色的命令。此命令允许用户从预定义的颜色列表中选取颜色。
|
||||
/// </summary>
|
||||
public ICommand SelectPresetColorCommand { get; }
|
||||
|
||||
private void ExecuteSelectPresetColor(object parameter)
|
||||
{
|
||||
if (parameter is Color color)
|
||||
{
|
||||
SelectedColor = color;
|
||||
RaiseEvent(new RoutedEventArgs(ColorSelectedEvent));
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Dependency Properties
|
||||
|
||||
/// <summary>
|
||||
/// 颜色模式
|
||||
/// </summary>
|
||||
public ColorInputMode ColorInputMode
|
||||
{
|
||||
get => (ColorInputMode)GetValue(ColorInputModeProperty);
|
||||
set => SetValue(ColorInputModeProperty, value);
|
||||
}
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty ColorInputModeProperty =
|
||||
DependencyProperty.Register(nameof(ColorInputMode), typeof(ColorInputMode), typeof(ColorPanel), new PropertyMetadata(ColorInputMode.HEX));
|
||||
|
||||
//private static void OnColorInputModeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
//{
|
||||
|
||||
//}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 选定颜色的依赖属性。此属性用于获取或设置当前选中的颜色值,并支持双向数据绑定。
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty SelectedColorProperty = DependencyProperty.Register(nameof(SelectedColor), typeof(Color),
|
||||
typeof(ColorPanel), new FrameworkPropertyMetadata(Colors.Red, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnSelectedColorChanged));
|
||||
|
||||
/// <summary>
|
||||
/// 获取或设置当前选中的颜色。此属性支持双向数据绑定,并在颜色更改时触发相关事件。
|
||||
/// </summary>
|
||||
public Color SelectedColor
|
||||
{
|
||||
get => (Color)GetValue(SelectedColorProperty);
|
||||
set => SetValue(SelectedColorProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 表示颜色透明度的依赖属性。此属性允许绑定和双向数据更新,其默认值为255(完全不透明)。
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty AlphaProperty = DependencyProperty.Register(nameof(Alpha), typeof(byte), typeof(ColorPanel),
|
||||
new FrameworkPropertyMetadata((byte)255, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnAlphaChanged));
|
||||
|
||||
/// <summary>
|
||||
/// 表示颜色的透明度(Alpha通道)值。此属性支持双向数据绑定,允许用户通过UI控件直接修改颜色的透明度。
|
||||
/// </summary>
|
||||
public byte Alpha
|
||||
{
|
||||
get => (byte)GetValue(AlphaProperty);
|
||||
set => SetValue(AlphaProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 用于表示颜色面板中色调值的依赖属性。此属性允许用户设置或获取当前选定颜色的色调部分,取值范围为0到360的整数。
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty HueProperty =
|
||||
DependencyProperty.Register(nameof(Hue), typeof(int), typeof(ColorPanel), new PropertyMetadata(0, OnHsvChanged));
|
||||
|
||||
/// <summary>
|
||||
/// 获取或设置颜色的色调值,范围为0到360的整数。此属性用于指定当前选定颜色的色相部分,并在颜色模型中与其他属性(如饱和度和亮度)共同定义一个特定的颜色。
|
||||
/// </summary>
|
||||
public int Hue
|
||||
{
|
||||
get => (int)GetValue(HueProperty);
|
||||
set => SetValue(HueProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 表示颜色饱和度的依赖属性。此属性允许设置或获取颜色的饱和度值,范围通常在0.0到1.0之间。
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty SaturationProperty =
|
||||
DependencyProperty.Register(nameof(Saturation), typeof(double), typeof(ColorPanel), new PropertyMetadata(1.0, OnHsvChanged));
|
||||
|
||||
/// <summary>
|
||||
/// 表示颜色的饱和度。饱和度是HSV颜色模型中的一个分量,用于描述颜色的纯度或灰度。
|
||||
/// 值为0表示灰色(无色),值为1表示该颜色最纯的状态。
|
||||
/// </summary>
|
||||
public double Saturation
|
||||
{
|
||||
get => (double)GetValue(SaturationProperty);
|
||||
set => SetValue(SaturationProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 用于控制颜色亮度的依赖属性。此属性允许用户设置或获取颜色面板中的亮度值,范围通常在0.0到1.0之间。
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty BrightnessProperty =
|
||||
DependencyProperty.Register(nameof(Brightness), typeof(double), typeof(ColorPanel), new PropertyMetadata(1.0, OnHsvChanged));
|
||||
|
||||
/// <summary>
|
||||
/// 表示颜色的亮度。此属性的值范围从0.0到1.0,其中0.0表示完全黑暗,1.0表示最大亮度。
|
||||
/// </summary>
|
||||
public double Brightness
|
||||
{
|
||||
get => (double)GetValue(BrightnessProperty);
|
||||
set => SetValue(BrightnessProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// RGB颜色模式下的红色分量依赖属性。此属性允许用户设置或获取当前选定颜色的红色分量值,取值范围为0到255。
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty RedProperty =
|
||||
DependencyProperty.Register(nameof(Red), typeof(byte), typeof(ColorPanel), new FrameworkPropertyMetadata((byte)255, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnRgbChanged));
|
||||
|
||||
/// <summary>
|
||||
/// 获取或设置颜色的红色分量值,范围为0到255。此属性用于RGB颜色模式下指定当前选定颜色的红色部分。
|
||||
/// </summary>
|
||||
public byte Red
|
||||
{
|
||||
get => (byte)GetValue(RedProperty);
|
||||
set => SetValue(RedProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// RGB颜色模式下的绿色分量依赖属性。此属性允许用户设置或获取当前选定颜色的绿色分量值,取值范围为0到255。
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty GreenProperty =
|
||||
DependencyProperty.Register(nameof(Green), typeof(byte), typeof(ColorPanel), new FrameworkPropertyMetadata((byte)0, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnRgbChanged));
|
||||
|
||||
/// <summary>
|
||||
/// 获取或设置颜色的绿色分量值,范围为0到255。此属性用于RGB颜色模式下指定当前选定颜色的绿色部分。
|
||||
/// </summary>
|
||||
public byte Green
|
||||
{
|
||||
get => (byte)GetValue(GreenProperty);
|
||||
set => SetValue(GreenProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// RGB颜色模式下的蓝色分量依赖属性。此属性允许用户设置或获取当前选定颜色的蓝色分量值,取值范围为0到255。
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty BlueProperty =
|
||||
DependencyProperty.Register(nameof(Blue), typeof(byte), typeof(ColorPanel), new FrameworkPropertyMetadata((byte)0, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnRgbChanged));
|
||||
|
||||
/// <summary>
|
||||
/// 获取或设置颜色的蓝色分量值,范围为0到255。此属性用于RGB颜色模式下指定当前选定颜色的蓝色部分。
|
||||
/// </summary>
|
||||
public byte Blue
|
||||
{
|
||||
get => (byte)GetValue(BlueProperty);
|
||||
set => SetValue(BlueProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 预设颜色的依赖属性。此属性用于获取或设置预定义的颜色列表,这些颜色可以被用户选择。
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty PresetColorsProperty =
|
||||
DependencyProperty.Register(nameof(PresetColors), typeof(List<Color>), typeof(ColorPanel), new PropertyMetadata(null));
|
||||
|
||||
/// <summary>
|
||||
/// 预设颜色列表。此属性允许用户定义一组预设的颜色,这些颜色可以在颜色选择器中直接使用。
|
||||
/// </summary>
|
||||
public List<Color> PresetColors
|
||||
{
|
||||
get => (List<Color>)GetValue(PresetColorsProperty);
|
||||
set => SetValue(PresetColorsProperty, value);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
static ColorPanel()
|
||||
{
|
||||
DefaultStyleKeyProperty.OverrideMetadata(typeof(ColorPanel), new FrameworkPropertyMetadata(typeof(ColorPanel)));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 用于选择颜色的面板控件。此控件允许用户通过HSV颜色模型调整颜色,同时也支持预设颜色的选择。
|
||||
/// </summary>
|
||||
public ColorPanel()
|
||||
{
|
||||
SelectPresetColorCommand = new RelayCommand(ExecuteSelectPresetColor);
|
||||
Loaded += OnPanelLoaded;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 当控件模板应用到此控件时调用。在此方法中,通过模板获取颜色选择器和颜色画布的引用,并为这些元素添加事件处理程序。
|
||||
/// </summary>
|
||||
public override void OnApplyTemplate()
|
||||
{
|
||||
base.OnApplyTemplate();
|
||||
colorCanvas = (Canvas?)GetTemplateChild("PART_ColorCanvas");
|
||||
colorSelector = (Thumb?)GetTemplateChild("PART_ColorSelector");
|
||||
if (colorSelector == null || colorCanvas == null) return;
|
||||
colorSelector.DragDelta += ColorSelector_DragDelta;
|
||||
colorCanvas.MouseLeftButtonDown += ColorCanvas_MouseLeftButtonDown;
|
||||
colorCanvas.SizeChanged += ColorCanvas_SizeChanged;
|
||||
}
|
||||
|
||||
private void OnPanelLoaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
UpdateHsvFromColor(this.SelectedColor);
|
||||
UpdateRgbFromColor(this.SelectedColor);
|
||||
UpdateSelectorPosition();
|
||||
}
|
||||
|
||||
private void ColorCanvas_SizeChanged(object sender, SizeChangedEventArgs e)
|
||||
{
|
||||
if (e.NewSize is not { Width: > 0, Height: > 0 }) return;
|
||||
UpdateSelectorPosition();
|
||||
if (colorCanvas != null) colorCanvas.SizeChanged -= ColorCanvas_SizeChanged;
|
||||
}
|
||||
|
||||
#region Callbacks
|
||||
|
||||
private static void OnSelectedColorChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
var p = (ColorPanel)d;
|
||||
if (p.isUpdating) return;
|
||||
p.isUpdating = true;
|
||||
var newColor = (Color)e.NewValue;
|
||||
p.Alpha = newColor.A;
|
||||
p.UpdateHsvFromColor(newColor);
|
||||
p.UpdateRgbFromColor(newColor);
|
||||
p.UpdateSelectorPosition();
|
||||
p.isUpdating = false;
|
||||
}
|
||||
|
||||
private static void OnAlphaChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
var p = (ColorPanel)d;
|
||||
if (p.isUpdating) return;
|
||||
p.isUpdating = true;
|
||||
p.SelectedColor = Color.FromArgb((byte)e.NewValue, p.Red, p.Green, p.Blue);
|
||||
p.isUpdating = false;
|
||||
}
|
||||
|
||||
private static void OnHsvChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
var p = (ColorPanel)d;
|
||||
if (p.isUpdating) return;
|
||||
p.isUpdating = true;
|
||||
var newColor = HsvToRgb(p.Hue, p.Saturation, p.Brightness, p.Alpha);
|
||||
p.SelectedColor = newColor;
|
||||
p.UpdateRgbFromColor(newColor);
|
||||
p.isUpdating = false;
|
||||
p.UpdateSelectorPosition();
|
||||
}
|
||||
|
||||
private static void OnRgbChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
var p = (ColorPanel)d;
|
||||
if (p.isUpdating) return;
|
||||
p.isUpdating = true;
|
||||
var newColor = Color.FromArgb(p.Alpha, p.Red, p.Green, p.Blue);
|
||||
p.SelectedColor = newColor;
|
||||
p.UpdateHsvFromColor(newColor);
|
||||
p.isUpdating = false;
|
||||
p.UpdateSelectorPosition();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region UI Handlers
|
||||
|
||||
private void ColorCanvas_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
UpdateSaturationAndBrightness(e.GetPosition(colorCanvas));
|
||||
Debug.Assert(colorCanvas != null, nameof(colorCanvas) + " != null");
|
||||
if (colorCanvas == null) return;
|
||||
colorCanvas.CaptureMouse();
|
||||
colorCanvas.MouseMove += ColorCanvas_MouseMove;
|
||||
colorCanvas.MouseUp += ColorCanvas_MouseUp;
|
||||
}
|
||||
|
||||
private void ColorCanvas_MouseUp(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
Debug.Assert(colorCanvas != null, nameof(colorCanvas) + " != null");
|
||||
|
||||
if (colorCanvas == null) return;
|
||||
colorCanvas.ReleaseMouseCapture();
|
||||
colorCanvas.MouseMove -= ColorCanvas_MouseMove;
|
||||
colorCanvas.MouseUp -= ColorCanvas_MouseUp;
|
||||
}
|
||||
|
||||
private void ColorCanvas_MouseMove(object sender, MouseEventArgs e)
|
||||
{
|
||||
if (e.LeftButton == MouseButtonState.Pressed) UpdateSaturationAndBrightness(e.GetPosition(colorCanvas));
|
||||
}
|
||||
|
||||
private void ColorSelector_DragDelta(object sender, DragDeltaEventArgs e)
|
||||
{
|
||||
if (colorSelector != null)
|
||||
UpdateSaturationAndBrightness(new Point(Canvas.GetLeft(colorSelector) + e.HorizontalChange,
|
||||
Canvas.GetTop(colorSelector) + e.VerticalChange));
|
||||
}
|
||||
|
||||
private void UpdateSaturationAndBrightness(Point position)
|
||||
{
|
||||
switch (colorCanvas)
|
||||
{
|
||||
case { ActualWidth: 0 }:
|
||||
case null:
|
||||
return;
|
||||
default:
|
||||
Saturation = Math.Max(0, Math.Min(1, position.X / colorCanvas.ActualWidth));
|
||||
Brightness = Math.Max(0, Math.Min(1, 1 - position.Y / colorCanvas.ActualHeight));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateHsvFromColor(Color color)
|
||||
{
|
||||
var hsv = RgbToHsv(color.R, color.G, color.B);
|
||||
Hue = (int)Math.Round(hsv.Hue); // 转换为整数
|
||||
Saturation = hsv.Saturation;
|
||||
Brightness = hsv.Brightness;
|
||||
}
|
||||
|
||||
private void UpdateRgbFromColor(Color color)
|
||||
{
|
||||
Red = color.R;
|
||||
Green = color.G;
|
||||
Blue = color.B;
|
||||
}
|
||||
|
||||
private void UpdateSelectorPosition()
|
||||
{
|
||||
if (colorCanvas is not { ActualWidth: > 0 }) return;
|
||||
if (colorSelector == null) return;
|
||||
Canvas.SetLeft(colorSelector, Saturation * colorCanvas.ActualWidth);
|
||||
Canvas.SetTop(colorSelector, (1 - Brightness) * colorCanvas.ActualHeight);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Color Conversion
|
||||
|
||||
private static HSVColor RgbToHsv(byte r, byte g, byte b)
|
||||
{
|
||||
double redNormalized = r / 255.0, greenNormalized = g / 255.0, blueNormalized = b / 255.0;
|
||||
double max = Math.Max(redNormalized, Math.Max(greenNormalized, blueNormalized)),
|
||||
min = Math.Min(redNormalized, Math.Min(greenNormalized, blueNormalized));
|
||||
var delta = max - min;
|
||||
double h = 0;
|
||||
if (delta != 0)
|
||||
{
|
||||
if (Math.Abs(max - redNormalized) < 10e-6) h = 60 * (((greenNormalized - blueNormalized) / delta) % 6);
|
||||
else if (Math.Abs(max - greenNormalized) < 10e-6) h = 60 * (((blueNormalized - redNormalized) / delta) + 2);
|
||||
else h = 60 * (((redNormalized - greenNormalized) / delta) + 4);
|
||||
}
|
||||
|
||||
if (h < 0) h += 360;
|
||||
var s = max == 0 ? 0 : delta / max;
|
||||
return new HSVColor(h, s, max);
|
||||
}
|
||||
|
||||
internal static Color HsvToRgb(double h, double s, double v, byte a)
|
||||
{
|
||||
double r = 0, g = 0, b = 0, c = v * s, x = c * (1 - Math.Abs((h / 60) % 2 - 1)), m = v - c;
|
||||
switch (h)
|
||||
{
|
||||
case < 60:
|
||||
r = c;
|
||||
g = x;
|
||||
break;
|
||||
case < 120:
|
||||
r = x;
|
||||
g = c;
|
||||
break;
|
||||
case < 180:
|
||||
g = c;
|
||||
b = x;
|
||||
break;
|
||||
case < 240:
|
||||
g = x;
|
||||
b = c;
|
||||
break;
|
||||
case < 300:
|
||||
r = x;
|
||||
b = c;
|
||||
break;
|
||||
default:
|
||||
r = c;
|
||||
b = x;
|
||||
break;
|
||||
}
|
||||
|
||||
return Color.FromArgb(a, (byte)((r + m) * 255), (byte)((g + m) * 255), (byte)((b + m) * 255));
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
213
NeoUI/Melskin/Controls/ColorPicker/ColorPicker.xaml
Normal file
213
NeoUI/Melskin/Controls/ColorPicker/ColorPicker.xaml
Normal file
@@ -0,0 +1,213 @@
|
||||
<ResourceDictionary
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:assists="clr-namespace:VariaStudio.Assists"
|
||||
xmlns:controls="clr-namespace:VariaStudio.Controls"
|
||||
xmlns:effects="clr-namespace:VariaStudio.Effects"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
<!-- 两种尺寸的棋盘格 -->
|
||||
<DrawingBrush
|
||||
TileMode="Tile"
|
||||
Viewport="0,0,16,16"
|
||||
ViewportUnits="Absolute"
|
||||
x:Key="CheckerboardBrushLarge">
|
||||
<DrawingBrush.Drawing>
|
||||
<DrawingGroup>
|
||||
<GeometryDrawing Brush="White">
|
||||
<GeometryDrawing.Geometry>
|
||||
<GeometryGroup>
|
||||
<RectangleGeometry Rect="0,0,8,8" />
|
||||
<RectangleGeometry Rect="8,8,8,8" />
|
||||
</GeometryGroup>
|
||||
</GeometryDrawing.Geometry>
|
||||
</GeometryDrawing>
|
||||
<GeometryDrawing Brush="#FFE0E0E0">
|
||||
<GeometryDrawing.Geometry>
|
||||
<GeometryGroup>
|
||||
<RectangleGeometry Rect="8,0,8,8" />
|
||||
<RectangleGeometry Rect="0,8,8,8" />
|
||||
</GeometryGroup>
|
||||
</GeometryDrawing.Geometry>
|
||||
</GeometryDrawing>
|
||||
</DrawingGroup>
|
||||
</DrawingBrush.Drawing>
|
||||
</DrawingBrush>
|
||||
<DrawingBrush
|
||||
TileMode="Tile"
|
||||
Viewport="0,0,8,8"
|
||||
ViewportUnits="Absolute"
|
||||
x:Key="CheckerboardBrushSmall">
|
||||
<DrawingBrush.Drawing>
|
||||
<DrawingGroup>
|
||||
<GeometryDrawing Brush="White">
|
||||
<GeometryDrawing.Geometry>
|
||||
<GeometryGroup>
|
||||
<RectangleGeometry Rect="0,0,4,4" />
|
||||
<RectangleGeometry Rect="4,4,4,4" />
|
||||
</GeometryGroup>
|
||||
</GeometryDrawing.Geometry>
|
||||
</GeometryDrawing>
|
||||
<GeometryDrawing Brush="#FFE0E0E0">
|
||||
<GeometryDrawing.Geometry>
|
||||
<GeometryGroup>
|
||||
<RectangleGeometry Rect="4,0,4,4" />
|
||||
<RectangleGeometry Rect="0,4,4,4" />
|
||||
</GeometryGroup>
|
||||
</GeometryDrawing.Geometry>
|
||||
</GeometryDrawing>
|
||||
</DrawingGroup>
|
||||
</DrawingBrush.Drawing>
|
||||
</DrawingBrush>
|
||||
|
||||
<Style TargetType="{x:Type RepeatButton}" x:Key="SliderRepeatButtonStyle">
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="{x:Type RepeatButton}">
|
||||
<Grid Background="Transparent" />
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<Style TargetType="{x:Type Slider}" x:Key="ColorSliderStyle">
|
||||
<Setter Property="Height" Value="16" />
|
||||
<Setter Property="VerticalAlignment" Value="Center" />
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="{x:Type Slider}">
|
||||
<Grid>
|
||||
<Grid
|
||||
Height="8"
|
||||
Margin="6,0"
|
||||
x:Name="TrackBackground">
|
||||
<Rectangle
|
||||
Fill="{StaticResource CheckerboardBrushSmall}"
|
||||
RadiusX="4"
|
||||
RadiusY="4" />
|
||||
<Rectangle
|
||||
Fill="{TemplateBinding Background}"
|
||||
RadiusX="4"
|
||||
RadiusY="4" />
|
||||
</Grid>
|
||||
<Track x:Name="PART_Track">
|
||||
<Track.DecreaseRepeatButton>
|
||||
<RepeatButton Command="{x:Static Slider.DecreaseLarge}" Style="{StaticResource SliderRepeatButtonStyle}" />
|
||||
</Track.DecreaseRepeatButton>
|
||||
<Track.IncreaseRepeatButton>
|
||||
<RepeatButton Command="{x:Static Slider.IncreaseLarge}" Style="{StaticResource SliderRepeatButtonStyle}" />
|
||||
</Track.IncreaseRepeatButton>
|
||||
<Track.Thumb>
|
||||
<Thumb
|
||||
FocusVisualStyle="{x:Null}"
|
||||
Height="12"
|
||||
Width="12">
|
||||
<Thumb.Template>
|
||||
<ControlTemplate TargetType="Thumb">
|
||||
<Grid>
|
||||
<Ellipse
|
||||
Fill="Transparent"
|
||||
Stroke="White"
|
||||
StrokeThickness="2">
|
||||
<Ellipse.Effect>
|
||||
<DropShadowEffect
|
||||
BlurRadius="2"
|
||||
Color="{DynamicResource DarkShadowColor}"
|
||||
Opacity="0.8"
|
||||
ShadowDepth="0" />
|
||||
</Ellipse.Effect>
|
||||
</Ellipse>
|
||||
</Grid>
|
||||
</ControlTemplate>
|
||||
</Thumb.Template>
|
||||
</Thumb>
|
||||
</Track.Thumb>
|
||||
</Track>
|
||||
</Grid>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<!-- 2. ColorPicker 样式 -->
|
||||
<Style TargetType="{x:Type controls:ColorPicker}">
|
||||
<Setter Property="Width" Value="32" />
|
||||
<Setter Property="Height" Value="32" />
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="{x:Type controls:ColorPicker}">
|
||||
<Grid>
|
||||
<ToggleButton x:Name="PART_Trigger">
|
||||
<ToggleButton.Template>
|
||||
<ControlTemplate TargetType="ToggleButton">
|
||||
<Border
|
||||
Background="{StaticResource CheckerboardBrushLarge}"
|
||||
BorderBrush="{DynamicResource BorderNormalBrush}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="4"
|
||||
x:Name="border">
|
||||
<Rectangle RadiusX="3" RadiusY="3">
|
||||
<Rectangle.Fill>
|
||||
<SolidColorBrush Color="{Binding Path=SelectedColor, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=controls:ColorPicker}}" />
|
||||
</Rectangle.Fill>
|
||||
</Rectangle>
|
||||
<!--<Border.Effect>
|
||||
<DropShadowEffect
|
||||
BlurRadius="4"
|
||||
Opacity="0.6"
|
||||
ShadowDepth="1"
|
||||
Color="{DynamicResource DarkShadowColor}" />
|
||||
</Border.Effect>-->
|
||||
</Border>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter Property="Effect">
|
||||
<Setter.Value>
|
||||
<effects:BrightnessContrastEffect Brightness="0.08" />
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
<Setter Property="Effect" TargetName="border">
|
||||
<Setter.Value>
|
||||
<DropShadowEffect
|
||||
BlurRadius="0"
|
||||
Color="{DynamicResource DarkShadowColor}"
|
||||
Opacity="0.4"
|
||||
ShadowDepth="0" />
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Trigger>
|
||||
<Trigger Property="IsPressed" Value="True">
|
||||
<Setter Property="Effect">
|
||||
<Setter.Value>
|
||||
<effects:BrightnessContrastEffect Brightness="0.06" />
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</ToggleButton.Template>
|
||||
</ToggleButton>
|
||||
|
||||
<Popup
|
||||
AllowsTransparency="True"
|
||||
IsOpen="{Binding IsChecked, ElementName=PART_Trigger, Mode=TwoWay}"
|
||||
Placement="Bottom"
|
||||
PlacementTarget="{Binding RelativeSource={RelativeSource TemplatedParent}}"
|
||||
PopupAnimation="None"
|
||||
StaysOpen="True"
|
||||
assists:BehaviorAssist.SimulateNativeBehavior="True"
|
||||
x:Name="PART_Popup">
|
||||
<Border
|
||||
Background="{TemplateBinding Background}"
|
||||
BorderThickness="{TemplateBinding BorderThickness}"
|
||||
Margin="4">
|
||||
<controls:ColorPanel
|
||||
Margin="8"
|
||||
PresetColors="{Binding Path=PlacementTarget.PresetColors, RelativeSource={RelativeSource AncestorType=Popup}}"
|
||||
SelectedColor="{Binding Path=PlacementTarget.SelectedColor, RelativeSource={RelativeSource AncestorType=Popup}, Mode=TwoWay}" />
|
||||
</Border>
|
||||
</Popup>
|
||||
</Grid>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
</ResourceDictionary>
|
||||
99
NeoUI/Melskin/Controls/ColorPicker/ColorPicker.xaml.cs
Normal file
99
NeoUI/Melskin/Controls/ColorPicker/ColorPicker.xaml.cs
Normal file
@@ -0,0 +1,99 @@
|
||||
namespace VariaStudio.Controls
|
||||
{
|
||||
/// <summary>
|
||||
/// ColorPicker 控件允许用户从一系列预设颜色中选择一个颜色,或者自定义颜色。该控件支持双向数据绑定,并且在颜色值发生更改时会自动更新显示。
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 本控件定义了三个主要的依赖属性:SelectedColor、IsOpen 和 PresetColors。通过这些属性可以控制当前选中的颜色、控件的打开/关闭状态以及可用的颜色列表。
|
||||
/// </remarks>
|
||||
[TemplatePart(Name = "PART_ColorPanel", Type = typeof(ColorPanel))]
|
||||
public class ColorPicker : Control
|
||||
{
|
||||
/// <summary>
|
||||
/// 代表 ColorPicker 控件中用于显示和选择颜色的面板。此组件允许用户从预设的颜色列表中选取颜色,同时也支持自定义颜色的选择。
|
||||
/// 在控件模板中通过 "PART_ColorPanel" 名称引用,并且在颜色被选中时会触发相关事件来关闭颜色选择器。
|
||||
/// </summary>
|
||||
private ColorPanel? colorPanel;
|
||||
|
||||
#region Dependency Properties
|
||||
|
||||
/// <summary>
|
||||
/// 表示 ColorPicker 控件中当前选中的颜色的依赖属性。
|
||||
/// 该属性为 Color 类型,用于获取或设置控件内用户选定的颜色。默认值设置为红色(Colors.Red)。
|
||||
/// 此属性支持双向数据绑定,并且在颜色值发生更改时会触发控件重绘。
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty SelectedColorProperty =
|
||||
DependencyProperty.Register(nameof(SelectedColor), typeof(Color), typeof(ColorPicker),
|
||||
new FrameworkPropertyMetadata(
|
||||
Colors.Red,
|
||||
FrameworkPropertyMetadataOptions.BindsTwoWayByDefault | FrameworkPropertyMetadataOptions.AffectsRender
|
||||
));
|
||||
|
||||
/// <summary>
|
||||
/// 表示 ColorPicker 控件中当前选中的颜色的依赖属性。
|
||||
/// 该属性为 Color 类型,用户可以通过此属性获取或设置当前选定的颜色。默认值为红色(Colors.Red)。
|
||||
/// 属性支持双向数据绑定,并且任何运行时的颜色变化都会触发控件重绘。
|
||||
/// </summary>
|
||||
public Color SelectedColor
|
||||
{
|
||||
get => (Color)GetValue(SelectedColorProperty);
|
||||
set => SetValue(SelectedColorProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 表示 ColorPicker 控件是否处于打开状态的依赖属性。
|
||||
/// 该属性为布尔类型,当设置为 true 时,表示控件已打开;设置为 false 时,表示控件已关闭。
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty IsOpenProperty =
|
||||
DependencyProperty.Register(nameof(IsOpen), typeof(bool), typeof(ColorPicker), new PropertyMetadata(false));
|
||||
|
||||
/// <summary>
|
||||
/// 获取或设置一个布尔值,指示 ColorPicker 控件是否处于打开状态。
|
||||
/// 当该属性为 true 时,表示控件已打开;当该属性为 false 时,表示控件已关闭。
|
||||
/// </summary>
|
||||
public bool IsOpen
|
||||
{
|
||||
get => (bool)GetValue(IsOpenProperty);
|
||||
set => SetValue(IsOpenProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 表示 ColorPicker 控件中预设颜色列表的依赖属性。
|
||||
/// 该属性包含一个颜色列表,用户可以从这些预设的颜色中进行选择。默认情况下,它包含了多种常用的颜色。
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty PresetColorsProperty =
|
||||
DependencyProperty.Register(nameof(PresetColors), typeof(List<Color>), typeof(ColorPicker),
|
||||
new PropertyMetadata(new List<Color> { Color.FromRgb(244, 67, 54), Color.FromRgb(233, 30, 99), Color.FromRgb(156, 39, 176), Color.FromRgb(103, 58, 183), Color.FromRgb(63, 81, 181), Color.FromRgb(33, 150, 243), Color.FromRgb(0, 188, 212), Color.FromRgb(0, 150, 136), Color.FromRgb(76, 175, 80), Color.FromRgb(205, 220, 57), Color.FromRgb(255, 235, 59), Color.FromRgb(255, 152, 0) }));
|
||||
|
||||
/// <summary>
|
||||
/// 表示 ColorPicker 控件中预设颜色列表的依赖属性。
|
||||
/// 该属性为 类型,包含了一系列预定义的颜色选项,用户可以从这些颜色中选择。
|
||||
/// </summary>
|
||||
public List<Color> PresetColors
|
||||
{
|
||||
get => (List<Color>)GetValue(PresetColorsProperty);
|
||||
set => SetValue(PresetColorsProperty, value);
|
||||
}
|
||||
#endregion
|
||||
|
||||
static ColorPicker()
|
||||
{
|
||||
DefaultStyleKeyProperty.OverrideMetadata(typeof(ColorPicker), new FrameworkPropertyMetadata(typeof(ColorPicker)));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 当控件的模板被应用时调用此方法。在此方法中,ColorPicker 控件会尝试获取其模板中的 ColorPanel 部分,并为其 ColorSelected 事件添加处理程序。
|
||||
/// 如果成功获取到 ColorPanel,则设置一个事件处理器,当用户从 ColorPanel 中选择了一个颜色后,该处理器将关闭 ColorPicker 的弹出窗口。
|
||||
/// </summary>
|
||||
public override void OnApplyTemplate()
|
||||
{
|
||||
base.OnApplyTemplate();
|
||||
colorPanel = GetTemplateChild("PART_ColorPanel") as ColorPanel;
|
||||
if (colorPanel != null)
|
||||
{
|
||||
// 这个事件处理依然是必要的,用于点击预设颜色时关闭Popup
|
||||
colorPanel.ColorSelected += (_, _) => IsOpen = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
43
NeoUI/Melskin/Controls/ColorPicker/HSVColor.cs
Normal file
43
NeoUI/Melskin/Controls/ColorPicker/HSVColor.cs
Normal file
@@ -0,0 +1,43 @@
|
||||
namespace VariaStudio.Controls;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 表示HSV颜色空间中的颜色。HSV颜色模型通过色调(Hue)、饱和度(Saturation)和亮度(Brightness)来描述颜色。
|
||||
/// 该结构体提供了这三个属性的只读访问,并且通过构造函数接收这三个参数来初始化一个HSV颜色实例。
|
||||
/// 色调(Hue)定义了颜色在色轮上的位置,取值范围为0到360度;饱和度(Saturation)表示颜色的纯度,取值范围从0.0(灰度)到1.0(全彩);
|
||||
/// 亮度(Brightness)决定了颜色的明暗程度,同样地,其取值范围也是从0.0(黑色)到1.0(最亮)。
|
||||
/// </summary>
|
||||
public struct HSVColor
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取或设置当前颜色的色调值。色调定义了颜色在色轮上的位置,取值范围为0到360度。
|
||||
/// 通过调整此属性可以改变颜色的基本外观,例如从红色过渡到黄色等。
|
||||
/// </summary>
|
||||
public double Hue { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取或设置颜色的饱和度值。饱和度定义了颜色的纯度,取值范围从0.0(灰度)到1.0(全彩)。此属性用于描述HSV颜色模型中的饱和度分量。
|
||||
/// </summary>
|
||||
public double Saturation { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 表示HSV颜色模型中的亮度值。亮度决定了颜色的明暗程度,取值范围从0.0(黑色)到1.0(最亮)。此属性为只读。
|
||||
/// </summary>
|
||||
public double Brightness { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 表示HSV颜色空间中的颜色。该结构体用于存储和操作基于色调(Hue)、饱和度(Saturation)和亮度(Brightness)定义的颜色。
|
||||
/// 通过构造函数初始化一个HSVColor实例,其中色调范围为0到360度,饱和度和亮度的取值范围均为0.0到1.0。
|
||||
/// </summary>
|
||||
public HSVColor(double hue,
|
||||
double saturation,
|
||||
double value)
|
||||
{
|
||||
Hue = hue;
|
||||
Saturation = saturation;
|
||||
Brightness = value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user