[
Advertise | Submit Code | About us | Contact us | Link us
]
Go!
Membership Services
Login
Register

Home
C# General

General

C# Language

Design & Architecture

Algorithms

Database

Security

Active Directory

COM Interop

Remoting
C# Windows Forms

General

Combo and List boxes

Miscellaneous Controls

Button Controls

Edit Controls
Cutting Edge

ASP.NET 2.0

Visual Studio 2005

Windows Longhorn

SQL Server 2005
C# Multimedia and GDI+

General

DirectX

GDI+

Audio
Internet & Web

General

Images and multimedia

Database

Utilities

Security

ASP.NET Controls

Design and Architecture

Webservices
.NET

General

Design & Architecture

Algorithms

Database

Security

Active Directory

COM Interop

Remoting

ADO.NET

XML.NET

Tools

Enterprise

IDE
Visual Basic .NET

VB.NET General

VB.NET Controls
General Reading

.NET Books Review

Product Showcase

Book Chapters

Business Design & Strategy
Community

Discuss

Job Board

Discussion

CodeXchange
DeveloperLand

Advertise

Submit Code

About us

Contact us

Link us
Miscellaneous

Favorite Links

Downloads

Programming Sites

Top Stories
Regular Expressions

E-Mail

Date/Time
Home > Visual Basic .NET > VB.NET Controls
The ColorPicker WinForms Control
Posted by on Tuesday, October 05, 2004 (EST)

Developing a simple ColorPicker WinForms control by implementing the IWindowsFormsEditorService interface and leveraging the WinForms design-time infrastructure.

This article has been viewed: 3,547 times
Technology: VB.NET Controls.

15_colorpicker.zip (42.88 KB)

Contents

Introduction

Although the .NET framework provides quite a rich collection of UI controls and components for WinForms development, there is one particular control that's been missing. I'm talking about a color-picker control with drop-down color selection capabilities, just like the one used within the Visual Studio .NET property browser for editing Color-typed properties.

Of course, there is the standard ColorDialog component, but the drop-down color selector is more user-friendly, IMHO. (Should I say cool?)

Based on these observations, I've decided to implement a ColorPicker control with the following features:
  • The control should look and act like a button.
  • The button should be colored with the currently selected color and, optionally, it should display the currently selected color's name.
  • Clicking the button should drop-down the built-in WinForms color selector and the control should change its appearance to a "pushed down" look.
The main design goals were implementation simplicity and the ability to reuse the control in either binary, or in source code form (VB.NET source code; just include the ColorPicker.vb file into your project and you're done).

The following is the important part of the ColorPicker's public contract (the semantics should be self-explanatory):

Namespace LaMarvin.Windows.Forms
Public Class ColorPicker
  Inherits Control
  Public Event ColorChanged As EventHandler
  Public Property Color() As Color
For those of you in a hurry, you can download the control along with an accompanying demo application
here [^].

But wait!

If you want to learn something about the inner workings of the WinForms design-time support, as well as some undocumented .NET framework tricks, please, read on.

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.

In fact, this implementation of UITypeEditor.EditValue method is common. If you've ever implemented your own drop-down UITypeEditor, it is highly likely that you've implemented it according to the above-described pattern.

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.

There were several other minor issues that I had to solve and I've described them in the ColorPicker.vb source file.

There was one issue, however, that I'd like to discuss here in more detail.

When the drop-down color selector is displayed by calling the IWindowsFormsEditorService.DropDownControl method, it is expected not to return only until after the user either selects a new color or she cancels the selection. The cancellation can be performed in a variety of ways: by pressing the Esc key, by clicking outside of the drop-down box, by pressing the Ctrl+Esc system key combination or by clicking the ColorPicker button once again.

In other words, the DropDownControl method implementation should block while dispatching windows messages caused by the user interaction with Windows (including the drop-down color selector).

Do you remember the old pal, DoEvents?

This time, however, it is exposed as the DoEvents method of the System.Windows.Forms.Application class. Calling the method causes processing of all the Windows messages in the current thread's message queue.

Here is a pseudocode for my first DropDownControl implementation, which uses the DoEvents method:

Namespace LaMarvin.Windows.Forms
...
Public Class ColorPicker
...
  Private Class EditorService
    Public Sub DropDownControl(ByVal control As Control) _
      Implements IWindowsFormsEditorService.DropDownControl
 
      ' Display the drop-down color selector, which
      ' is hosted within a _DropDownHolder Form instance.
    
      ' Wait until the drop-down is closed.
      Do While _DropDownHolder.Visible
        Application.DoEvents()
      Loop
   ...
End Sub
The code shows the drop-down UI and then it enters a loop calling Application.DoEvents until the drop-down form is closed. This way, the DropDownControl method blocks (ignoring the possible reentrancy issues for the moment) while Windows messages are still being dispatched.

It worked fine this way until I realized that when the drop-down color selector is displayed, the process hosting the ColorPicker control eats 100% of the CPU.

Too bad!

Once again, I've turned to the .NET Reflector tool in order to see how the DropDownControl method is implemented within the PropertyGrid itself (which, obviously, doesn't eat 100% CPU while displaying the color selector).

Here is what I found out:

Namespace System.Windows.Forms.PropertyGridInternal
  Private Class PropertyGridView
   Private Class DropDownHolder
      Public Sub DoModalLoop()
        Do While MyBase.Visible
         Application.DoEvents
         UnsafeNativeMethods.MsgWaitForMultipleObjects( _
           1, 0, 1, 250, 255)
        Loop
      End Sub
...
The same code as above plus the MsgWaitForMultipleObjects function call. The function is a standard part of the Win32 API. Here is the function's prototype taken from the MSDN documentation (comments mine):
DWORD MsgWaitForMultipleObjects(
  DWORD nCount,  // number of handles pointed to by the
     // pHandles argument
  const HANDLE* pHandles, // pointer to an array of object
     // handles whose signaled state is checked
  BOOL bWaitAll,  // all object handles should be
     // signaled (TRUE) or any one of them (FALSE)
  DWORD dwMilliseconds, // wait timeout
  DWORD dwWakeMask  // which input events (messages)
     // should cause the function to return (in addition
     // to signaling objects pointed to by pHandles)
);
The purpose of the function is to suspend the calling thread until one or all of the object handles become signaled, OR, until a message appears in the thread's input queue according to the dwWakeMask value.

The weird thing is that .NET framework calls the function with the number of object handles equal to ONE, while the pointer to the array of handles is ZERO (Nothing in VB nomenclature).

This way of calling the function is not documented (AFAIK). One can only guess that such a call is used to suspend the calling thread until a message has to be processed WITHOUT checking the signaled state of any object handle.

Nevertheless, because the call is used within WinForms implementation itself, I find it quite safe to use it within your own applications.

I've used it with ColorPicker and the problem with the drop-down form consuming 100% CPU cycles disappeared.

Enjoy!

Top Go to Table of Contents

About Palo Mraz

Click here if you want to know more about .

Other articles that may interest you

  • Write a Word Add-In – Part 0
  • Write a Word Add-In – Part I
  • Lengthy Operations on Single Thread in .NET Application
  • Learning Draughts
  • Exceptions and Performance
  • Average Rating :

    Discussion Forums
    Got a programming related question? Hopefully someone has the answer... Want to help out other developers? Visit our discussion forums.

    Sponsored by:

    New Articles

  • Exceptions and Performance
    Almost every time exceptions are mentioned in mailing lists and newsgroups, people say they're really expensive.Let's examine that claim, shall we?

  • Creating multilingual websites - Part 1
    Extend the existing globalization capabilities of .NET to create flexible and powerful multilingual web sites. First, create a custom ResourceManager, and then create custom localized-capable server controls to easily deploy multilingual functionality.

  • Parameter passing in C#
    Many people have become fairly confused about how parameters are passed in C#, particularly with regard to reference types. This page should help to clear up some of that confusion

  • Most Popular Articles

  • LDAP, IIS and WinNT Directory Services
    This article explains how to use .NET Directory Services to retrieve and search directory objects, create new directory objects and edit or delete existing directory objects. Describes Active Directory Application Mode (ADAM) and how to use the IIS, WinNT and LDAP directory (ADSI) provider.

  • An in-depth look at WMI and instrumentation, Part II
    WMI stands for Windows Management Instrumentation and, as the name indicates, is about managing your IT infrastructure this article is the second part of a two-part series.

  • An in-depth look at WMI and instrumentation, Part I
    WMI stands for Windows Management Instrumentation and, as the name indicates, is about managing your IT infrastructure this article provides an in-depth look at WMI and MOM 2005

  • New Books

  • Murach's ASP.NET 2.0 Upgrader's Guide: VB Edition
    What’s new and how to use it! That’s what this book delivers if you’re a VB developer who’s interested in upgrading from ASP.NET 1.x to ASP.NET 2.0.

  • C# in easy steps
    Learn to program with Microsoft’s premier programming language. No previous programming knowledge is assumed. With numerous easy-to-follow examples, this title explains the essentials of object-oriented programming with C#.

  • Murach's ASP.NET web programming with VB.NET
    Murach's ASP.NET web programming with VB.NET by Doug Lowe and Anne Prince is a in depth training and reference book for ASP.NET programming using VB.NET. The book builds upon Murach's previous books and covers more advanced concepts for programming ASP.NET pages.

  • Got Code?

    if you have any article , source code , or anything else you'd like to share with this community that you think others might find useful, please submit it here and we will gladly make it available on this site. submit@developerland.com.
    Partners

    All articles are copyrighted by their individual authors unless otherwise specified , everything else Copyright ©2004-2006 DeveloperLand