Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

EnumButtonGroup: An Alternative for Binding Enumerated Values to Buttons

0.00/5 (No votes)
12 Dec 2008 1  
A Windows Forms user-control that allows binding of enumerated values to a group of buttons, both at design-time and run-time.
runtime-horizontal.png

runtime-vertical-dayofweek.png

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
    {
        // Make sure value is an enumerated type
        if (value != null && !value.IsEnum)
        {
            throw new ArgumentException("Argument must be an enumerated type");
        }

        this.valueType = value;
        if (this.valueType == null)
        {
            // Reset
            this.Controls.Clear();
            this.Controls.Add(this.placeholderLabel);
            this.selectedValue = null;
            RaiseSelectedValueChangedEvent();
        }
        else
        {
            // Create button controls based on new valueType
            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
    {
        // Don't bother setting if valueType is unknown
        if (this.valueType != null)
        {
            this.selectedValue = value;

            // If we are here as a result of a button CheckedChanged event
            // then there is no need to check the button
            if (!this.alreadyChecked)
            {
                CheckButton();
            }
            else
            {
                // Tell everyone the selected value has changed
                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.

designtime-vertical.png

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.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here