Windows Forms单选按钮列表 - 将枚举属性绑定到RadioButton

3

假设我有几个单选按钮和一些自定义对象作为数据源。

例如:

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));
        }
    }
}

如何将该对象属性(如果可能的话)绑定到3个不同的单选按钮,例如:
如果选中radiobuttonOne,则对象属性mode设置为firstMode 如果选中radiobuttonTwo,则对象属性mode设置为secondMode 如果选中radiobuttonThree,则对象属性mode设置为thirdMode 等等。
还是更好使用事件来处理?
注:我知道如何使用事件,但一次一次地创建事件(例如rb1changed、rb2changed,..., rb100changed),会很麻烦。
附注:圣诞快乐!

当你声明枚举类型时,它只是一个条目。你需要一个集合来绑定到单选按钮列表。尝试声明List<SomeModeType>为属性,并用枚举的每个成员填充它。 - Anup Sharma
@AnupSharma 但这有什么帮助呢? 我的意思是,为什么不像这样绑定单选按钮 - 如果您选择第一个,则字段值变为“firstMode”,如果选择第二个,则将字段值重写为“secondMode” - DanilGholtsman
我在这里分享了一个 RadioButtonList 控件 链接 - Reza Aghaei
它具有数据绑定支持,您可以像使用 ListBox 一样使用此控件。为此,只需将其绑定到模型的属性,然后以这种简单的方式设置控件的数据源即可:radioButtonList1.DataSource = Enum.GetValues(typeof(YourEnumType)); - Reza Aghaei
1个回答

3
对于枚举的每个值,您需要创建一个RadioButton并将其Checked值绑定到数据源的Mode属性。然后,您需要使用BindingFormatParse事件将Mode值转换为适合Checked属性的值,反之亦然。 示例 - 使用FlowLayoutPanel的RadioButton列表 例如,在表单上放置一个FlowLayoutPanel控件,然后在FormLoad事件中编写以下代码。该代码将动态向流式布局面板添加RadioButton控件并执行数据绑定。
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);
});

在上面的例子中,dataSource 可以是一个 MyCustomObject 或者一个 BindingList<MyCustomObject> 或者一个包含 List<MyCustomObject>BindingSource另一种选择 - 使用自定义绘制的 RadioButton List 作为另一种选择,您可以使用自定义绘制的 ListBox 并为项目渲染 RadioButton。这样,您可以将 ListBoxSelectedValue 绑定到对象的 Mode 属性。在以下代码中,dataSource 可以像上面的例子一样。在窗体上放置一个 ListBox 并在窗体的 Load 事件中编写以下代码:
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);
};

屏幕截图

您可以在以下图片中看到两种解决方案:

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;

注意

在回答这个问题后,我创建了并分享了一个RadioButtonList控件在这篇文章中:WinForms RadioButtonList doesn't exist

它支持数据绑定,你可以像使用ListBox一样使用该控件。要做到这一点,只需将其绑定到模型的属性上,然后设置控件的数据源即可:

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

很好,有趣,但是没有更简单的方法吗?._. - DanilGholtsman
很遗憾,除非您将所有逻辑封装在单个控件中并将其命名为“RadioButtonList”,否则没有更简单的方法。 - Reza Aghaei
另一种选择(并不更简单)是使用自绘 Listbox。我也会分享它。 - Reza Aghaei
哦,谢谢!目前我只有两种不同的模式情况,所以我会在我的当前应用程序中保持所有事情简单,但这是一个有趣的方法,我会记住的! - DanilGholtsman

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接