Introduction
Having used Chris Maunder's excellent CColourPicker
MFC
control for a few years and I thought a useful .NET learning exercise would be
to write a look-alike control in C#. I haven't duplicated it exactly and
I've ended up with three controls not one.
I'm quite pleased with the results so far, and have to say that programming
with .NET/C# is a pleasure compared to MFC/C++. If I have time I'm going
to keep adding to the color picker controls. Please let me have any
feature requests you may have and I'll try to incorporate them in future.
The control library code demonstrates:
- Creating .NET controls
-
.NET Control inheritance
-
Custom Events
-
Design time attributes
-
A bit of GDI+
-
XML documentation compiled into a Platform SDK like help file using
X Marks The DOT, an extensible documentation generator.
Creating controls
This section lists a few of the interesting things I discovered when creating
my controls.
Properties and attributes
One very useful feature of .NET languages is the ability to add meta-data to
your code in various places. For controls one interesting place to add
meta-data is on the control's properties.
As an example here's a couple of properties from the ColorPanel
control:
true)>
[Category("ColorPanel")]
[DefaultValue(defaultColorSet)]
[Description("Get/set the palette of colors to be displayed.")]
public PJLControls.ColorSet ColorSet
{
get { ... }
set { ... }
}true)>
[Category("ColorPanel")]
[Description("Get/set the pick color.")]
public System.Drawing.Color Color
{
get { ... }
set { ... }
}
public void ResetColor()
{
Color = defaultColor;
}
public bool ShouldSerializeColor()
{
return Color != defaultColor
}
The items of interest here are the attributes and the ResetColor
/ShouldSerializeColor
methods.
If you add the attribute true)>
to your property, then the property
will appear in the properties window in VS.NET when you select an instance of
the control in the Forms designer. You can also assign a category to the
property using the [Category("your category")]
attribute. If
don't supply the category attribute then the property will appear
in the "Miscellaneous" category .
If you now add the attribute [Description("description here")]
then the
property window displays the description as shown above, when the property is
selected.
The final attribute of interest is [DefaultValue()]
. Supplying this
attribute has two consequences. The first is that if you right click on
the attribute in the Properties window you will get a small pop-up menu with
the "Reset" item enabled. If you select Reset the property will be reset
to the value you have supplied as the default. The other consequence is
that the forms designer now knows whether it needs to add code to change the
property value from the default (i.e. serialize the properties value).
For example this is the initialization code generated by the Forms
designer for the ColorPanel
in the demo.
private void InitializeComponent()
{
...
this.colorPanel.ColorSortOrder = PJLControls.ColorSortOrder.Brightness;
this.colorPanel.CustomColors = new System.Drawing.Color[]
{
System.Drawing.Color.FromArgb(((System.Byte)(255)), ((System.Byte)(192)),
((System.Byte)(192))),
System.Drawing.Color.FromArgb(((System.Byte)(255)), ((System.Byte)(128)),
((System.Byte)(128))),
System.Drawing.Color.Red,
...
}
...
}
The properties highlighted in bold are the ones that the Forms designer knows
don't have default values, so it initialises them and no others.
However, the DefaultValue
attribute constructor only appears to accept simple
types, so if you have a complex type you need to implement two methods instead
- Reset
PropertyName
and ShouldSerialize
PropertyName
.
These two methods are fairly self explanatory and there's an example
above. The Forms designer recognises these methods which then
produce the same effects as the DefaultValue
attribute.
IsInputKey
When you want to receive keyboard events, you just hook up an event handler for
the OnKeyDown
event or override the OnKeyDown
virtual method.
However by default certain keys you may be interested in, such as TAB, the
arrow keys etc aren't sent to you, they're sent to the form hosting the
control for dialog navigation. If you want to see them in
OnKeyDown
override IsInputKey
and return true
for key codes you want to
see. Here's an example.
protected override bool IsInputKey( System.Windows.Forms.Keys keyData )
{
bool bIsInputKey = true;
switch( keyData )
{
case Keys.Left:
break;
case Keys.Right:
break;
case Keys.Down:
break;
case Keys.Up:
break;
default:
bIsInputKey = base.IsInputKey(keyData);
break;
}
return bIsInputKey;
}
The Controls
ColorPicker
Description
The ColorPicker simulates a ComboBox style UI but drops down a palette of
colors (ok I know, it's been done before). The dropdown palette is an
instance of the ColorPanel
control hosted in a modal
form. The control fully supports mouse and keyboard navigation.
Keyboard navigation
Tab to the control and then use the down arrow to drop down the color
panel. Then you can navigate using the arrow keys, select a color
using the Return key or cancel using the Escape key. One problem that
I've just noticed is that you can't tab off the dropped down color panel.
Properties
The ColorPicker supports the following properties all of which except
BorderStyle
are visible in the Visual Studio property browser under the
"ColorPicker" category. BorderStyle
is in the "Appearance" category.
Property name
|
Type
|
Description
|
_Text
|
string
|
Same as the Text property - I can't get the 'Text' property to work
correctly.
|
AutoSize
|
boolean
|
If set to true the the control's height is fixed.
|
BorderStyle
|
System.Windows.Forms.BorderStyle
|
Set/get the controls border style.
|
Color
|
System.Drawing.Color
|
Set/get the pick color.
|
ColorSet
|
PJLControls.ColorSet
|
Select which color palette to use.
|
ColorSortOrder
|
PJLControls.ColorSortOrder
|
Select the order that the color palette is sorted.
|
ColorWellSize
|
System.Drawing.Size
|
Set/get the size of the colors in the color palette.
|
Columns
|
int
|
If set to 0 then the drop down panel has the same width as the picker.
If > 0 then the drop down panel has that many columns.
|
CustomColors
|
System.Drawing.Color[]
|
The user can supply an array of colors to be displayed. The custom color
array is displayed when the ColorSet property is set to ColorSet.Custom
|
DisplayColor
|
bool
|
Indicate whether to display the pick color in the picker combo box.
|
DisplayColorName
|
bool
|
Indicates whether to display the pick color name in the combo box. If
false the value of the _Text property is displayed.
|
PanelBorderStyle
|
System.Windows.Forms.BorderStyle
|
Set/get the border style of the drop down panel.
|
Events
Supports the ColorChanged event which is fired when the user selects a new
color.
ColorPanel
Description
This control shows a grid of colors and is used as the drop down for the
ColorPicker
control. The colors displayed are either derived from the
System.Drawing.Colors
enumeration or are supplied by the user using the
CustomColors property.
Properties
The ColorPanel supports the following properties all of which except
BorderStyle
are visible in the Visual Studio property browser in the
"ColorPanel" category. BorderStyle
is in the "Appearance" category.
Property name
|
Type
|
Description
|
BorderStyle
|
System.Windows.Forms.BorderStyle
|
Set/get the controls border style.
|
Color
|
System.Drawing.Color
|
Set/get the pick color.
|
ColorSet
|
PJLControls.ColorSet
|
Select which color palette to use.
|
ColorSortOrder
|
PJLControls.ColorSortOrder
|
Select the order that the color palette is sorted.
|
ColorWellSize
|
System.Drawing.Size
|
Set/get the size of the colors in the color palette.
|
Columns
|
int
|
If set to 0 then the panel can be resized.
If > 0 then the panel has that many columns.
|
CustomColors
|
System.Drawing.Color[]
|
The user can supply an array of colors to be displayed. The custom color
array is displayed when the ColorSet property is set to ColorSet.Custom
|
Events
Supports the ColorChanged
event which is fired when the user selects a new
color.
CustomColorPicker
Description
Inspired by Peter McMahon's
ColorPicker.NET.
This controls allows you to select any RGB value. It displays one slice
through the RGB color cube. You select the z-axis as red, green or blue
and the control then displays the x-y axis at the appropriate z-axis value in
the cube. You can continuously scroll through the Z axis and see the
color palette change, but this will only probably work smoothly on a 500MHz+
processor.
Properties
The CustomColorPicker
supports the following properties all of which are
visible in the Visual Studio property browser in the "ColorPicker"
category.
Property name
|
Type
|
Description
|
Color
|
System.Drawing.Color
|
Set/get the pick color.
|
EnableContinuousScrollZ
|
bool
|
Select which color palette to use.
|
Events
Supports the ColorChanged
event which is fired when the user selects a new
color.
Release History
v1.0, 23 October 2001
v1.1, 07 November 2001
-
Added more design time support in the form of the DefaultValue attribute, ResetPropertyName/ShouldSerializePropertyName
method pair, and the Description attributes.
-
Added the Columns property to allow the user to set the width of the color
panel.
-
Added the CustomColors property to allow the use of a custom color palette.
-
Various bug fixes.
-
Improved/smoother resizing of the ColorPanel at design time.
Compatibility
Requires VS.NET beta 2 to build the code. Requires .NET beta 2
runtime to run the compiled sample.
Known bugs
Can't tab away from drop down of color picker.