Introduction
You can do an awful lot of cool stuff with the Windows Forms controls that come bundled with Visual Studio. Unfortunately, the binding of enumerated values to a group of buttons isn't one of them. This article introduces a control designed to do just that.
Background
I was slapping together a quick prototype at work the other day when I realized what I need was a control that I could use to display enumerated values as radio buttons. I didn't remember there being anything built into Visual Studio that would do the trick, so I did a quick online search. The closest thing I found to what I was looking for was this article by Jay Andrew Allen. However, his control didn't allow me to specify the enumerated type I wanted to display and have the control automatically create the buttons for me. A couple of hours later, I had created the control I wanted.
Using the Code
The EnumButtonGroup
control is a Windows Forms UserControl
that exposes the additional properties ValueType
and SelectedValue
and a SelectedValueChanged
event.
The ValueType
property is used to specify the .NET Type
that represents the enumerated values that will be displayed in the control.
[TypeConverter(typeof(StringToTypeConverter))]
public Type ValueType
{
get
{
return (this.valueType);
}
set
{
if (value != null && !value.IsEnum)
{
throw new ArgumentException("Argument must be an enumerated type");
}
this.valueType = value;
if (this.valueType == null)
{
this.Controls.Clear();
this.Controls.Add(this.placeholderLabel);
this.selectedValue = null;
RaiseSelectedValueChangedEvent();
}
else
{
CreateButtons();
}
}
}
When this property is set, the control first checks to see if it represents an enumerated type. If so, it automatically creates the buttons that represent the values of that enumerated type. The SelectedValue
property is then set to the first enumerated value and any subscribers are notified via the SelectedValueChanged
event.
The SelectedValue
property is used to specify which of the enumerated values displayed in the control will be selected (checked).
[Editor(typeof(EnumButtonGroupSelectedValueEditor), typeof(UITypeEditor))]
public object SelectedValue
{
get
{
return (this.selectedValue);
}
set
{
if (this.valueType != null)
{
this.selectedValue = value;
if (!this.alreadyChecked)
{
CheckButton();
}
else
{
RaiseSelectedValueChangedEvent();
}
}
}
}
When the SelectedValue
property is set automatically in response to a CheckChanged
event from one of the buttons, the control simply notifies any subscribers of the change via the SelectedValueChanged
event. If the property is set directly then the appropriate button's Checked
property is set to true
, which in turn causes the SelectedValueChanged
event to be raised.
Applications that want to be notified when the SelectedValue
property changes should register to receive SelectedValueChanged
events.
public void MainForm_Load(object sender, EventArgs e)
{
this.enumButtonGroup1.SelectedValueChanged +=
new EventHandler(enumButtonGroup1_SelectedValueChanged);
}
...
private void enumButtonGroup1_SelectedValueChanged(object sender, EventArgs e)
{
this.propertyGrid1.SelectedObject = sender;
}
Design-Time Considerations
I wanted the ValueType
property to be editable at design-time as well as run-time. To enable this, I needed to add a type converter (StringToTypeConverter
) to convert a string
to a Type
, allowing ValueType
to be specified in string
format.
One point of special note: The Type.GetType()
method will return null
if the type isn't in an assembly loaded by the application or in the mscorlib.dll assembly.
I also wanted the SelectedValue
property to be editable at design-time. This meant I needed to add a UI type editor (EnumButtonGroupSelectedValueEditor
) to display drop-down list of possible values from which to select.
Points of Interest
You may have noticed that I also added some other properties:
Orientation
is an enumerated value that allows the buttons to be oriented either horizontally or vertically within the control
ShowDescriptions
is a boolean property that controls whether enumerated values marked with the DescriptionAttribute
will have their description displayed
HideObsoleteValues
is a boolean property that controls whether enumerated values marked with the ObsoleteAttribute
will be displayed
Some possible additions that would make this control more useful are:
- Specifying different layouts that would allow the buttons to be arranged in rows and columns
- Displaying enumerated values marked with the
FlagsAttribute
as check boxes
The attached project is a Visual Studio 2008 / .NET 3.5 project. If anyone would like a Visual Studio 2005 / .NET 2.0 version, please let me know and I'll upload one.
History
- 6th December, 2008: Initial submission
- 9th December, 2008: Added Visual Studio 2005 version. Renamed
ShowObsoleteValues
to HideObsoleteValues
to correct inverse logic bug.
This is my first article submission. I will appreciate any feedback.