Windows Forms RadioButton List - Bind Enum Property to RadioButton

2.5k views Asked by At

Let's say I got few radiobuttons and some custom object as datasource.

As example

public enum SomeModeType
{
    firstMode = 10,
    secondMode = 20,
    thirdMode = 30
}

public class MyCustomObject:INotifyPropertyChanged
{

    private SomeModeType _mode;
    public SomeModeType Mode
    {
        set { _mode = value; }
        get { return _mode; }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged(string propertyName)
    {
        var handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

How to bind this object property (if its possible) to 3 different radiobuttons with something like:

If radiobuttonOne checked - object property mode sets to firstMode

If radiobuttonTwo checked - object property mode sets to secondMode

If radiobuttonThree checked - object property mode sets to thirdMode

etc etc

Or its better to use events for this?

P.S. I know how to use events but its overwhelmed to create event by event like rb1chnaged, rb2changed, ..., rb100changed, isnt it?

P.P.S.

MerryXmas!

1

There are 1 answers

4
Reza Aghaei On BEST ANSWER

For each value of the enum, you need to create a RadioButton and bind its Checked value to Mode property of data source. Then you need to use Format and Parse event of Binding to convert Mode value to suitable value for Checked property and vise versa.

Example - RadioButton List using FlowLayoutPanel

For example put a FlowLayoutPanel control on your form and then in Load event of Form write following code. The code will add RadioButton controls to the flow layout panel dynamically and performs data-binding:

var enumValues = Enum.GetValues(typeof(SomeModeType)).Cast<object>()
    .Select(x => new { Value = x, Name = x.ToString() }).ToList();
enumValues.ForEach(x =>
{
    var radio = new RadioButton() { Text = x.Name, Tag = x.Value };
    var binding = radio.DataBindings.Add("Checked", dataSource,
        "Mode", true, DataSourceUpdateMode.OnPropertyChanged);
    binding.Format += (obj, ea) =>
    { ea.Value = ((Binding)obj).Control.Tag.Equals(ea.Value); };
    binding.Parse += (obj, ea) =>
    { if ((bool)ea.Value == true) ea.Value = ((Binding)obj).Control.Tag; };
    flowLayoutPanel1.Controls.Add(radio);
});

In above example, dataSource can be a MyCustomObject or a BindingList<MyCustomObject> or a BindingSource which contains a List<MyCustomObject> in its DataSource.

Another alternative - RadioButton List using Owner-draw ListBox

As another option you can use an owner-draw ListBox and render RadioButton for items. This way, you can bind SelectedValue of ListBox to Mode property of your object. The dataSourcs in following code can be like above example. Put a ListBox on form and write following code in Load event of form:

var enumValues = Enum.GetValues(typeof(SomeModeType)).Cast<object>()
    .Select(x => new { Value = x, Name = x.ToString() }).ToList();
this.listBox1.DataSource = enumValues;
this.listBox1.ValueMember = "Value";
this.listBox1.DisplayMember = "Name";
this.listBox1.DataBindings.Add("SelectedValue", dataSource,
        "Mode", true, DataSourceUpdateMode.OnPropertyChanged);
this.listBox1.DrawMode = DrawMode.OwnerDrawFixed;
this.listBox1.ItemHeight = RadioButtonRenderer.GetGlyphSize(
    Graphics.FromHwnd(IntPtr.Zero),
            RadioButtonState.CheckedNormal).Height + 4;
this.listBox1.DrawItem += (obj, ea) =>
{
    var lb = (ListBox)obj;
    ea.DrawBackground();
    var text = lb.GetItemText(lb.Items[ea.Index]);
    var r = ea.Bounds;
    r.Offset(ea.Bounds.Height, 0);
    RadioButtonRenderer.DrawRadioButton(ea.Graphics, 
        new Point(ea.Bounds.Location.X, ea.Bounds.Location.Y + 2), r, text,
        lb.Font, TextFormatFlags.Left, false,
        (ea.State & DrawItemState.Selected) == DrawItemState.Selected ?
        RadioButtonState.CheckedNormal : RadioButtonState.UncheckedNormal);
};

Screenshot

You can see both solutions in following image:

enter image description here

var list = new List<MyCustomObject>() { 
    new MyCustomObject(){ Mode= SomeModeType.firstMode},
    new MyCustomObject(){ Mode= SomeModeType.secondMode},
    new MyCustomObject(){ Mode= SomeModeType.thirdMode},
};
this.myCustomObjectBindingSource.DataSource = list;
var dataSource = myCustomObjectBindingSource;

Note

After answering this question, I created and shared a RadioButtonList control in this post: WinForms RadioButtonList doesn't exist.

It has data-binding support and you can use this control like a ListBox. To do so, it's enough to bind it to the property of your model, and then set the data-source of the control simply this way:

radioButtonList1.DataSource = Enum.GetValues(typeof(YourEnumType));