65.9K
CodeProject 正在变化。 阅读更多。
Home

ColorComboBox

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.58/5 (16投票s)

2008年7月3日

CPOL

4分钟阅读

viewsIcon

85213

downloadIcon

3746

使用 ToolStripDropDown 的 ColorComboBox 颜色选择器。

带有扩展颜色集

ExtendedColors.JPG

带有基本颜色集

引言

这是使用 ToolStripDropDown 类创建颜色选择器组合框的演示。说实话,我很惊讶 .NET 框架没有提供这个控件,因为任何富文本编辑器应用程序都会在它们的工具栏中需要一个这样的控件。

背景

由于这是我第一次尝试 C# 编程,我最初的想法是创建一个继承自 CheckBox 的控件来完成创建 ColorComboBox 的任务,当选中时,它会创建一个不带标题栏的窗体并显示它,该窗体将包含代表颜色的平面单选按钮。当弹出窗口显示时,必须检测到任何在窗口外部的鼠标点击才能关闭弹出窗口。我很快了解到,要在弹出窗口外部捕获鼠标点击的唯一方法是使用 Windows Hook(我们都知道捕获鼠标会阻止用户点击子按钮)。但是,这会将此控件绑定到 Windows。所以,我必须找到一种 .NET 方法来做同样的事情,这让我找到了 ToolStripDropDown 类。

这个思路的另一个问题是,我将复选框的属性暴露给了外部世界。复选框需要是扁平的,没有自动调整大小,并且 Text 属性必须为空。如果前两个设置不正确,将会导致灾难性的后果。所以,我将整个东西封装在一个继承自 UserControl 的类中,以隐藏 CheckBox 的属性,使其不对用户可见。

还有一个障碍需要克服。当下拉列表显示时,如果用户点击下拉按钮来关闭它,它会关闭,然后立即重新打开。我发现解决这个问题的唯一方法是在下拉列表显示时禁用下拉按钮。这是借助 Timer 完成的。这不是一个完美的解决方案,但这是我能想到的唯一一个。

因此,最终结果包括一个 ColorComboBox(继承自 UserControl),其中包含一个 ColorComboButton(继承自 CheckBox),其中包含一个 PopupWindow(继承自 ToolStripDropDown),其中包含一个 ColorPopup(继承自 UserControl),其中包含一个 ColorRadioButton(继承自 RadioButton)。

让我们来详细介绍一下。

我们从 ColorChangedHandler 事件开始。ColorComboBoxPopupWindowColorComboButton 都拥有 ColorChangedHandlerPopupWindowColorComboButton 中的那些对类用户是不可见的;它们在内部用于将颜色更改事件向下传递。

//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,以及 ColorRadioButtonColorPopup 只是一个容器,其中包含许多带有颜色的平面单选按钮。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 中。

该控件有两个额外的属性,SelectedColorExtendedSelectedColor 属性用于获取和设置 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);
}

玩得开心!

© . All rights reserved.