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.