下面我将为你展示如何在WPF中自定义实现一个功能完整的颜色拾取器(Color Picker)。这个颜色拾取器将包含颜色选择区域、亮度滑块、RGB/HSV数值输入和十六进制颜色代码输入等功能。
![图片[1]_基于WPF自定义实现颜色拾取器_知途无界](https://zhituwujie.com/wp-content/uploads/2025/10/d2b5ca33bd20251023093008.png)
1. 基本结构设计
首先创建一个名为ColorPicker.xaml的用户控件:
<UserControl x:Class="YourNamespace.ColorPicker"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="350">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<!-- 主要颜色选择区域 -->
<Border Grid.Row="0" Background="White" BorderBrush="Gray" BorderThickness="1" Margin="10">
<Grid>
<!-- 色彩选择面板 -->
<Canvas x:Name="ColorPanel" Background="White" Margin="0,0,0,20" MouseLeftButtonDown="ColorPanel_MouseLeftButtonDown" MouseMove="ColorPanel_MouseMove" MouseLeftButtonUp="ColorPanel_MouseLeftButtonUp">
<!-- 渐变色将在代码中生成 -->
</Canvas>
<!-- 亮度滑块 -->
<Border x:Name="BrightnessSlider" VerticalAlignment="Bottom" Height="20" Margin="0,0,0,0"
Background="Gray" MouseLeftButtonDown="BrightnessSlider_MouseLeftButtonDown"
MouseMove="BrightnessSlider_MouseMove" MouseLeftButtonUp="BrightnessSlider_MouseLeftButtonUp"/>
<!-- 当前选中颜色的小方块 -->
<Border x:Name="SelectedColorPreview" Width="30" Height="30" VerticalAlignment="Top" HorizontalAlignment="Right"
Margin="0,10,10,0" BorderBrush="Black" BorderThickness="1" Background="White"/>
</Grid>
</Border>
<!-- 颜色值显示和输入区域 -->
<StackPanel Grid.Row="1" Orientation="Vertical" Margin="10,0,10,10">
<!-- RGB 数值输入 -->
<GroupBox Header="RGB 值" Margin="0,5">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="30"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="30"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="30"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBlock Text="R:" VerticalAlignment="Center" Margin="5"/>
<TextBox x:Name="RgbR" Width="40" Margin="5" Grid.Column="1" TextChanged="Rgb_ValueChanged"/>
<TextBlock Text="G:" VerticalAlignment="Center" Margin="5" Grid.Column="2"/>
<TextBox x:Name="RgbG" Width="40" Margin="5" Grid.Column="3" TextChanged="Rgb_ValueChanged"/>
<TextBlock Text="B:" VerticalAlignment="Center" Margin="5" Grid.Column="4"/>
<TextBox x:Name="RgbB" Width="40" Margin="5" Grid.Column="5" TextChanged="Rgb_ValueChanged"/>
</Grid>
</GroupBox>
<!-- 十六进制颜色代码 -->
<GroupBox Header="十六进制颜色代码" Margin="0,5">
<TextBox x:Name="HexColor" Width="100" Margin="5" TextChanged="HexColor_TextChanged"/>
</GroupBox>
<!-- 当前选中的颜色值显示 -->
<Border Height="30" Margin="0,10,0,0" BorderBrush="Gray" BorderThickness="1">
<Border.Background>
<SolidColorBrush x:Name="CurrentColor" Color="White"/>
</Border.Background>
</Border>
</StackPanel>
</Grid>
</UserControl>
2. 后台代码实现
对应的后台代码文件ColorPicker.xaml.cs:
using System;
using System.Globalization;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Shapes;
namespace YourNamespace
{
public partial class ColorPicker : UserControl
{
// 当前选中的颜色
private Color _currentColor = Colors.White;
// 用于绘制色彩面板的渐变矩形集合
private Rectangle[,] _colorRectangles;
// 是否正在拖拽
private bool _isDragging = false;
private bool _isDraggingBrightness = false;
// 拖拽的目标元素
private FrameworkElement _dragTarget = null;
public ColorPicker()
{
InitializeComponent();
InitializeColorPanel();
UpdateColorDisplay();
}
// 初始化色彩选择面板
private void InitializeColorPanel()
{
ColorPanel.Children.Clear();
int width = 200;
int height = 150;
ColorPanel.Width = width;
ColorPanel.Height = height;
// 创建一个彩色渐变网格
_colorRectangles = new Rectangle[20, 15];
double rectWidth = width / 20.0;
double rectHeight = height / 15.0;
for (int i = 0; i < 20; i++)
{
for (int j = 0; j < 15; j++)
{
Rectangle rect = new Rectangle();
rect.Width = rectWidth;
rect.Height = rectHeight;
rect.Margin = new Thickness(i * rectWidth, j * rectHeight, 0, 0);
// 生成HSL颜色并转换为RGB
double hue = (i / 19.0) * 360.0;
double saturation = 1.0;
double lightness = 1.0 - (j / 14.0);
Color color = HslToRgb(hue, saturation, lightness);
rect.Fill = new SolidColorBrush(color);
ColorPanel.Children.Add(rect);
_colorRectangles[i, j] = rect;
}
}
// 创建亮度滑块背景
CreateBrightnessSliderBackground();
}
// 创建亮度滑块背景
private void CreateBrightnessSliderBackground()
{
// 移除旧的亮度滑块背景
var oldChildren = BrightnessSlider.Children;
oldChildren.Clear();
// 创建一个从当前颜色到黑色的渐变
GradientStopCollection stops = new GradientStopCollection();
// 从当前颜色(不透明)到当前颜色(透明)再到黑色
stops.Add(new GradientStop(_currentColor, 0.0));
stops.Add(new GradientStop(_currentColor, 0.7));
stops.Add(new GradientStop(Colors.Black, 1.0));
LinearGradientBrush brush = new LinearGradientBrush(stops, 0.0);
BrightnessSlider.Background = brush;
}
// HSL转RGB
private Color HslToRgb(double h, double s, double l)
{
double r, g, b;
if (s == 0)
{
r = g = b = l; // 灰度
}
else
{
double q = l < 0.5 ? l * (1 + s) : l + s - l * s;
double p = 2 * l - q;
r = HueToRgb(p, q, h / 360.0 + 1.0 / 3.0);
g = HueToRgb(p, q, h / 360.0);
b = HueToRgb(p, q, h / 360.0 - 1.0 / 3.0);
}
return Color.FromRgb(
(byte)(r * 255),
(byte)(g * 255),
(byte)(b * 255));
}
private double HueToRgb(double p, double q, double t)
{
if (t < 0) t += 1;
if (t > 1) t -= 1;
if (t < 1.0 / 6.0) return p + (q - p) * 6 * t;
if (t < 1.0 / 2.0) return q;
if (t < 2.0 / 3.0) return p + (q - p) * (2.0 / 3.0 - t) * 6;
return p;
}
// 从RGB获取HSL
private void RgbToHsl(byte r, byte g, byte b, out double h, out double s, out double l)
{
double red = r / 255.0;
double green = g / 255.0;
double blue = b / 255.0;
double max = Math.Max(red, Math.Max(green, blue));
double min = Math.Min(red, Math.Min(green, blue));
l = (max + min) / 2;
if (max == min)
{
h = s = 0; // 灰度
}
else
{
double d = max - min;
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
if (max == red)
{
h = (green - blue) / d + (green < blue ? 6 : 0);
}
else if (max == green)
{
h = (blue - red) / d + 2;
}
else
{
h = (red - green) / d + 4;
}
h /= 6;
}
}
// 获取指定坐标的颜色
private Color GetColorFromPosition(Point position)
{
// 获取相对于ColorPanel的坐标
Point relativePos = new Point(position.X - ColorPanel.Margin.Left, position.Y - ColorPanel.Margin.Top);
// 确保坐标在面板范围内
if (relativePos.X < 0 || relativePos.Y < 0 ||
relativePos.X > ColorPanel.ActualWidth || relativePos.Y > ColorPanel.ActualHeight - 20)
{
return _currentColor;
}
// 计算最近的矩形块
int col = (int)(relativePos.X / (ColorPanel.ActualWidth / 20.0));
int row = (int)(relativePos.Y / (ColorPanel.ActualHeight / 15.0));
col = Math.Max(0, Math.Min(19, col));
row = Math.Max(0, Math.Min(14, row));
if (_colorRectangles != null && _colorRectangles[col, row] != null)
{
var brush = _colorRectangles[col, row].Fill as SolidColorBrush;
if (brush != null)
{
return brush.Color;
}
}
return _currentColor;
}
// 更新亮度
private Color UpdateBrightness(Color color, double brightness)
{
// brightness: 0.0 (黑) 到 1.0 (原色)
if (brightness >= 1.0)
return color;
if (brightness <= 0.0)
return Colors.Black;
byte r = (byte)(color.R * brightness);
byte g = (byte)(color.G * brightness);
byte b = (byte)(color.B * brightness);
return Color.FromRgb(r, g, b);
}
// 更新颜色显示
private void UpdateColorDisplay()
{
// 更新当前颜色预览
SelectedColorPreview.Background = new SolidColorBrush(_currentColor);
// 更新十六进制颜色代码
HexColor.Text = ColorToHex(_currentColor);
// 更新RGB输入框
RgbR.Text = ((int)_currentColor.R).ToString();
RgbG.Text = ((int)_currentColor.G).ToString();
RgbB.Text = ((int)_currentColor.B).ToString();
// 更新当前颜色显示区域
CurrentColor.Color = _currentColor;
// 更新亮度滑块
CreateBrightnessSliderBackground();
}
// 颜色转十六进制
private string ColorToHex(Color color)
{
return "#" + color.R.ToString("X2") + color.G.ToString("X2") + color.B.ToString("X2");
}
// 十六进制转颜色
private Color HexToColor(string hex)
{
try
{
// 移除#号
if (hex.StartsWith("#"))
hex = hex.Substring(1);
if (hex.Length == 6)
{
byte r = Byte.Parse(hex.Substring(0, 2), NumberStyles.HexNumber);
byte g = Byte.Parse(hex.Substring(2, 2), NumberStyles.HexNumber);
byte b = Byte.Parse(hex.Substring(4, 2), NumberStyles.HexNumber);
return Color.FromRgb(r, g, b);
}
}
catch
{
// 如果转换失败,返回当前颜色
}
return _currentColor;
}
// 颜色值改变事件处理
private void Rgb_ValueChanged(object sender, TextChangedEventArgs e)
{
if (!_isDragging)
{
try
{
byte r = byte.Parse(RgbR.Text);
byte g = byte.Parse(RgbG.Text);
byte b = byte.Parse(RgbB.Text);
_currentColor = Color.FromRgb(r, g, b);
UpdateColorDisplay();
CreateBrightnessSliderBackground();
}
catch
{
// 忽略无效输入
}
}
}
private void HexColor_TextChanged(object sender, TextChangedEventArgs e)
{
if (!_isDragging)
{
_currentColor = HexToColor(HexColor.Text);
UpdateColorDisplay();
CreateBrightnessSliderBackground();
}
}
// 色彩面板鼠标事件
private void ColorPanel_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (e.ChangedButton == MouseButton.Left)
{
_isDragging = true;
_dragTarget = sender as FrameworkElement;
ColorPanel.CaptureMouse();
UpdateColorFromMouse(e.GetPosition(ColorPanel));
}
}
private void ColorPanel_MouseMove(object sender, MouseEventArgs e)
{
if (_isDragging && e.ChangedButton == MouseButton.Left)
{
UpdateColorFromMouse(e.GetPosition(ColorPanel));
}
}
private void ColorPanel_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
if (e.ChangedButton == MouseButton.Left)
{
_isDragging = false;
if (_dragTarget != null)
{
_dragTarget.ReleaseMouseCapture();
}
_dragTarget = null;
}
}
// 亮度滑块鼠标事件
private void BrightnessSlider_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (e.ChangedButton == MouseButton.Left)
{
_isDraggingBrightness = true;
_dragTarget = sender as FrameworkElement;
BrightnessSlider.CaptureMouse();
UpdateBrightnessFromMouse(e.GetPosition(BrightnessSlider));
}
}
private void BrightnessSlider_MouseMove(object sender, MouseEventArgs e)
{
if (_isDraggingBrightness && e.ChangedButton == MouseButton.Left)
{
UpdateBrightnessFromMouse(e.GetPosition(BrightnessSlider));
}
}
private void BrightnessSlider_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
if (e.ChangedButton == MouseButton.Left)
{
_isDraggingBrightness = false;
if (_dragTarget != null)
{
_dragTarget.ReleaseMouseCapture();
}
_dragTarget = null;
}
}
// 从鼠标位置更新颜色
private void UpdateColorFromMouse(Point position)
{
Color color = GetColorFromPosition(position);
_currentColor = UpdateBrightness(color, 1.0); // 先获取原始色彩
UpdateColorDisplay();
}
// 从鼠标位置更新亮度
private void UpdateBrightnessFromMouse(Point position)
{
// 亮度滑块的位置决定亮度值
double relativeY = position.Y;
double sliderHeight = BrightnessSlider.ActualHeight;
// 亮度从顶部(1.0)到底部(0.0)
double brightness = 1.0 - (relativeY / sliderHeight);
brightness = Math.Max(0.0, Math.Min(1.0, brightness));
// 获取当前基础颜色(从色彩面板选择的颜色)
// 我们需要从当前选中的颜色中提取HSL,然后保持H和S不变,只改变L
double h, s, l;
byte r = _currentColor.R;
byte g = _currentColor.G;
byte b = _currentColor.B;
RgbToHsl(r, g, b, out h, out s, out l);
// 使用新的亮度值
l = brightness;
// 将HSL转换回RGB
Color newColor = HslToRgb(h * 360.0, s, l);
_currentColor = newColor;
UpdateColorDisplay();
}
// 公共属性:当前选中的颜色
public Color SelectedColor
{
get { return _currentColor; }
set
{
_currentColor = value;
UpdateColorDisplay();
}
}
// 颜色改变事件
public event EventHandler<ColorChangedEventArgs> ColorChanged;
// 触发颜色改变事件
protected virtual void OnColorChanged(Color color)
{
ColorChanged?.Invoke(this, new ColorChangedEventArgs(color));
}
}
// 颜色改变事件参数
public class ColorChangedEventArgs : EventArgs
{
public Color Color { get; }
public ColorChangedEventArgs(Color color)
{
Color = color;
}
}
}
3. 在窗口中使用颜色拾取器
现在你可以在主窗口或其他地方使用这个颜色拾取器了。以下是如何在窗口中使用它的示例:
XAML (MainWindow.xaml)
<Window x:Class="YourNamespace.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:YourNamespace"
Title="颜色拾取器示例" Height="450" Width="600">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<local:ColorPicker x:Name="colorPicker" Grid.Row="0" Margin="10" ColorChanged="ColorPicker_ColorChanged"/>
<StackPanel Grid.Row="1" Orientation="Horizontal" HorizontalAlignment="Center" Margin="10">
<TextBlock Text="当前选中颜色: " VerticalAlignment="Center" Margin="5"/>
<Rectangle Width="50" Height="30" Margin="5"
Fill="{Binding SelectedColor, ElementName=colorPicker}"/>
<TextBlock Text="{Binding SelectedColor, ElementName=colorPicker, StringFormat='{}#{0:X2}{1:X2}{2:X2}'}"
VerticalAlignment="Center" Margin="5"/>
</StackPanel>
</Grid>
</Window>
后台代码 (MainWindow.xaml.cs)
using System.Windows;
namespace YourNamespace
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void ColorPicker_ColorChanged(object sender, ColorChangedEventArgs e)
{
// 当颜色改变时触发
var color = e.Color;
// 可以在这里处理颜色改变的逻辑
System.Diagnostics.Debug.WriteLine($"选中颜色: #{color.R:X2}{color.G:X2}{color.B:X2}");
}
}
}
4. 功能说明
这个自定义颜色拾取器具有以下功能:
- 色彩选择面板:点击或拖拽选择基础颜色
- 亮度滑块:调整所选颜色的亮度
- 实时预览:右上角显示当前选中的颜色
- RGB数值输入:可以直接输入RGB值来设置颜色
- 十六进制颜色代码:支持输入或显示十六进制颜色代码
- 颜色改变事件:当颜色改变时触发事件,方便在其他地方响应颜色变化
5. 扩展建议
如果想进一步增强这个颜色拾取器,可以考虑添加以下功能:
- HSV数值输入:除了RGB,还可以添加色调、饱和度、亮度的数值输入
- 调色板:提供常用颜色快速选择
- 最近使用颜色:记录和显示最近选择的颜色
- 颜色历史:保存颜色选择历史
- 更精确的色彩选择:使用更复杂的算法生成色彩面板,提供更丰富的颜色选择
这个自定义颜色拾取器提供了一个良好的基础,可以根据具体需求进行扩展和定制。
© 版权声明
文中内容均来源于公开资料,受限于信息的时效性和复杂性,可能存在误差或遗漏。我们已尽力确保内容的准确性,但对于因信息变更或错误导致的任何后果,本站不承担任何责任。如需引用本文内容,请注明出处并尊重原作者的版权。
THE END

























暂无评论内容