ColorComboBox






4.58/5 (16投票s)
使用 ToolStripDropDown 的 ColorComboBox 颜色选择器。
引言
这是使用 ToolStripDropDown
类创建颜色选择器组合框的演示。说实话,我很惊讶 .NET 框架没有提供这个控件,因为任何富文本编辑器应用程序都会在它们的工具栏中需要一个这样的控件。
背景
由于这是我第一次尝试 C# 编程,我最初的想法是创建一个继承自 CheckBox
的控件来完成创建 ColorComboBox
的任务,当选中时,它会创建一个不带标题栏的窗体并显示它,该窗体将包含代表颜色的平面单选按钮。当弹出窗口显示时,必须检测到任何在窗口外部的鼠标点击才能关闭弹出窗口。我很快了解到,要在弹出窗口外部捕获鼠标点击的唯一方法是使用 Windows Hook(我们都知道捕获鼠标会阻止用户点击子按钮)。但是,这会将此控件绑定到 Windows。所以,我必须找到一种 .NET 方法来做同样的事情,这让我找到了 ToolStripDropDown
类。
这个思路的另一个问题是,我将复选框的属性暴露给了外部世界。复选框需要是扁平的,没有自动调整大小,并且 Text
属性必须为空。如果前两个设置不正确,将会导致灾难性的后果。所以,我将整个东西封装在一个继承自 UserControl
的类中,以隐藏 CheckBox
的属性,使其不对用户可见。
还有一个障碍需要克服。当下拉列表显示时,如果用户点击下拉按钮来关闭它,它会关闭,然后立即重新打开。我发现解决这个问题的唯一方法是在下拉列表显示时禁用下拉按钮。这是借助 Timer
完成的。这不是一个完美的解决方案,但这是我能想到的唯一一个。
因此,最终结果包括一个 ColorComboBox
(继承自 UserControl
),其中包含一个 ColorComboButton
(继承自 CheckBox
),其中包含一个 PopupWindow
(继承自 ToolStripDropDown
),其中包含一个 ColorPopup
(继承自 UserControl
),其中包含一个 ColorRadio
Button
(继承自 RadioButton
)。
让我们来详细介绍一下。
我们从 ColorChangedHandler
事件开始。ColorComboBox
、PopupWindow
和 ColorComboButton
都拥有 ColorChangedHandler
。PopupWindow
和 ColorComboButton
中的那些对类用户是不可见的;它们在内部用于将颜色更改事件向下传递。
//define the color changed event argument
public class ColorChangeArgs : System.EventArgs
{
public ColorChangeArgs(Color color)
{
this.color = color;
}
//the selected color
public Color color;
}
//event handler delegate
public delegate void ColorChangedHandler(object sender, ColorChangeArgs e);
ColorComboBox
类,它继承自 UserControl
,本身非常简单。它有一个构造函数,以及两个事件处理程序,一个用于 SizeChanged
事件,另一个用于捕获来自颜色弹出窗口的 ColorChanged
事件,以便将其传递给父控件。
public partial class ColorComboBox : UserControl
{
/// <summary>
/// Set or get the selected color
/// </summary>
public Color SelectedColor
{
get
{
return button.SelectedColor;
}
set
{
button.SelectedColor = value;
}
}
/// <summary>
/// Set whether the control is in extended color mode or normal mode
/// </summary>
public Boolean Extended
{
set
{
button.Extended = value;
}
get
{
return button.Extended;
}
}
/// <summary>
/// color change event handler
/// </summary>
public event ColorChangedHandler ColorChanged;
public ColorComboBox()
{
InitializeComponent();
//setup event handler to catch the ColorChanged message from the
//color popup
button.ColorChanged += new ColorChangedHandler(button_ColorChanged);
}
public void button_ColorChanged(object sender, ColorChangeArgs e)
{
if (ColorChanged != null)
{
ColorChanged(this, e);
}
}
private void ColorComboBox_SizeChanged(object sender, EventArgs e)
{
button.Location = new Point(0, 0);
button.Size = this.Size;
}
}
链中的下一个控件是 ColorComboButton
。这是此控件中第一个可见的元素。这是显示所选颜色并右侧带有下拉箭头的按钮。此类中重要的项是 ColorChanged
事件、ColorCombo_Click
事件处理程序和 OnCheckStatus
定时器事件处理程序。
private class ColorComboButton : CheckBox
{
private void ColorCombo_Click(object sender, EventArgs e)
{
//if it is already down, don't do anything.
//this shouldn't happen anymore since we
//started to disable the button when the
//drop down is being displayed
if (!this.Checked)
{
return;
}
//create a popup window
popupWnd = new PopupWindow(colors);
//calculate its position in screen coordinates
Rectangle rect = Bounds;
rect = this.Parent.RectangleToScreen(rect);
Point pt = new System.Drawing.Point(rect.Left, rect.Bottom);
//tell it that we want the ColorChanged event
popupWnd.ColorChanged += new ColorChangedHandler(OnColorChanged);
//show the popup
popupWnd.Show(pt);
//disable the button so that the user can't click it
//while the popup is being displayed
this.Enabled = false;
}
//event handler for the color change event from the popup window
//simply relay the event to the parent control
protected void OnColorChanged(object sender, ColorChangeArgs e)
{
//if a someone wants the event, and the color has actually changed
//call the event handler
if (ColorChanged != null && e.color != this.selectedColor)
{
this.selectedColor = e.color;
ColorChanged(this, e);
}
else //otherwise simply make note of the new color
{
this.selectedColor = e.color;
}
}
//This is the timer call back function. It checks to see
//if the popup went from a visible state to an close state
//if so then it will uncheck and enable the button
private void OnCheckStatus(Object myObject, EventArgs myEventArgs)
{
if (popupWnd != null && !popupWnd.Visible)
{
this.Checked = false;
this.Enabled = true;
}
}
}
接下来,我们有 ColorPopup
控件,它是一个 User Control,以及 ColorRadioButton
。ColorPopup
只是一个容器,其中包含许多带有颜色的平面单选按钮。ColorRadioButton
继承自 RadioButton
,并执行一些自定义绘制,以便在 ColorPopup
中显示颜色。我会让您自己去发现它们,因为它们非常简单明了。
下一个是 PopupWindow
,它继承自 ToolStripDropDown
。这个类有两个方法,一个构造函数和一个 Close
事件处理程序。构造函数创建一个 ToolStripControlHost
,它将托管 PopupColor
User Control,并将其作为一项添加到 ToolStripDropDown
的列表中。Close
事件处理程序只是触发 ColorChanged
事件。
private class PopupWindow : ToolStripDropDown
{
public PopupWindow(ColorPopup content)
{
if (content == null)
{
throw new ArgumentNullException("content");
}
this.content = content;
this.AutoSize = false;
this.DoubleBuffered = true;
this.ResizeRedraw = true;
//create a host that will host the content
host = new ToolStripControlHost(content);
this.Padding = Margin = host.Padding = host.Margin = Padding.Empty;
this.MinimumSize = content.MinimumSize;
content.MinimumSize = content.Size;
MaximumSize = new Size(content.Size.Width + 1,
content.Size.Height + 1);
content.MaximumSize = new Size(content.Size.Width + 1,
content.Size.Height + 1);
Size = new Size(content.Size.Width + 1, content.Size.Height + 1);
content.Location = Point.Empty;
//add the host to the list
Items.Add(host);
}
protected override void OnClosed(ToolStripDropDownClosedEventArgs e)
{
//when the window close tell the parent that the color changed
if (ColorChanged != null)
{
ColorChanged(this, new ColorChangeArgs(this.SelectedColor));
}
}
}
使用代码
该控件的使用非常简单。我没有创建类库,因为它对于单个控件来说有点大材小用。因此,只需将 ColorComboBox.zip 中的三个文件复制并粘贴到您的项目目录中,然后将它们添加到您的项目中。您可能需要先进行一次生成,控件才会显示在控件工具箱中。一旦出现在那里,您就可以简单地将其拖放到 WinForm 中。
该控件有两个额外的属性,SelectedColor
和 Extended
。SelectedColor
属性用于获取和设置 ColorComboBox
中选定的颜色。Extended
属性将下拉框的内容从基本颜色集更改为扩展颜色集。
该控件还公开了一个事件,ColorChanged
,用于通知用户已更改颜色选择。
//setup the event handler
private void InitializeComponent()
{
...
this.colorComboBox1.ColorChanged +=
new ColorComboTestApp.ColorChangedHandler(this.OnColorChanged);
...
}
//the event handler method
protected void OnColorChanged(object sender, ColorChangeArgs e)
{
MessageBox.Show(this,e.color.ToString(),"Selected color",
MessageBoxButtons.OK, MessageBoxIcon.Information);
}
玩得开心!