The ColorPicker WinForms Control

The ColorEditor

The core requirement for the ColorPicker control was to display the same drop-down color selector that is used within the WinForms' PropertyGrid control. For more information about the PropertyGrid control and its use of attributes, see the Shawn Burke's article at MSDN. The built-in color selector is implemented inside a ColorEditor class, which is designated as the EditorAttribute for the Color structure:

Namespace System.Drawing

<EditorAttribute("System.Drawing.Design.ColorEditor"), _
    GetType(System.Drawing.Design.UITypeEditor))> _
Public Structure Color

Unfortunately, the ColorEditor class is currently undocumented. The only thing one can learn from the official documentation is the infamous sentence - "This type supports the .NET Framework infrastructure and is not intended to be used directly from your code."

Nevertheless, with some help of ILDASM and the Lutz Roeder's .NET Reflector, I was able to find out how a ColorEditor instance is hosted within the PropertyGrid. Moreover, I was also able to emulate the hosting within the ColorPicker control, which is the focus of the remainder of this article.

To better understand the process of hosting the ColorEditor, let's quickly recap how the PropertyGrid control uses the EditorAttribute when editing properties of a given object:

When a row within the PropertyGrid gets focus, the grid looks first at the property itself, then at the property's type in order to see, if there is an EditorAttribute applied to one of them. The EditorAttribute specifies the System.Type that should be used as the editor for the given property. In theory, a type can have more than one editor. However, currently only one 'type' of editors are supported - the ones that derive (directly or indirectly) from the System.Drawing.Design.UITypeEditor class.) In the case of a Color-typed property, the PropertyGrid finds the System.Drawing.Design.ColorEditor class to be used as the editor. The grid then calls the overridden ColorEditor.GetEditStyle method:

Namespace System.Drawing.Design
Public Class UITypeEditor
Public Overridable Function GetEditStyle( _
    ByVal context As ITypeDescriptorContext _
) As UITypeEditorEditStyle

The ColorEditor implementation of this method returns always UITypeEditorEditStyle.DropDown. This causes the PropertyGrid to display a drop-down button on the right side of the property row. When the user clicks the drop-down button, the PropertyGrid calls another overridden method - ColorEditor.EditValue:

Namespace System.Drawing.Design
Public Class UITypeEditor
Public Overridable Function EditValue( _
    ByVal context As ITypeDescriptorContext, _
    ByVal provider As IServiceProvider, _
    ByVal value As Object _
) As Object

The ColorEditor implementation of this method does the following:

  • Queries the passed in IServiceProvider instance for an IWindowsFormEditorService implementation.
  • Stores the IWindowsFormEditorService in a member variable.
  • Creates an instance of a private ColorUI class, which implements the actual user interface and interacts with the user.
  • Calls the IWindowsFormEditorService.DropDownControl method passing it the custom control instance.
  • When the user selects a new color, the ColorEditor calls the IWindowsFormEditorService.CloseDropDown method, which (you guessed that) closes the drop-down UI and causes the IWindowsFormEditorService.DropDownControl method to return.
Because the ColorEditor doesn't use the ITypeDescriptorContext arguments, all I had to do to host it was to implement just two interfaces:
Namespace System

Public Interface IServiceProvider
  Public Function GetService( _
    ByVal serviceType As Type) As Object
End Interface

...

Namespace System.Windows.Forms.Design

Public Interface IWindowsFormsEditorService
  Public Sub CloseDropDown()
  Public Sub DropDownControl(ByVal control As Control)
  Public Function ShowDialog( _
    ByVal dialog As Form) As DialogResult
End Interface

Because the ColorEditor queries the passed in IServiceProvider just for the IWindowsFormsEditorService, I've implemented both interfaces in one class - the EditorService class, which is nested within the ColorPicker control class.

You might also like...

Comments

About the author

Palo Mraz

Palo Mraz United States

I live in Slovakia with my wife, two sons (fulltime), one daughter (occasionally) and a dog. I've been doing Microsoft Windows development since 1988; primarily in VB. I'm a big fan of the MS .N...

Interested in writing for us? Find out more.

Contribute

Why not write for us? Or you could submit an event or a user group in your area. Alternatively just tell us what you think!

Our tools

We've got automatic conversion tools to convert C# to VB.NET, VB.NET to C#. Also you can compress javascript and compress css and generate sql connection strings.

“Hofstadter's Law: It always takes longer than you expect, even when you take into account Hofstadter's Law.”