Windows 形成 RadioButton 列表 - 将枚举 属性 绑定到 RadioButton
Windows Forms RadioButton List - Bind Enum Property to RadioButton
假设我有几个单选按钮和一些自定义对象作为数据源。
举个例子
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
等等等等
还是为此使用事件更好?
P.S。
我知道如何使用事件,但是像 rb1chnaged
、rb2changed
、...、rb100changed
这样的事件一个接一个地创建事件让我不知所措,不是吗?
P.P.S.
圣诞快乐!
对于枚举的每个值,您需要创建一个 RadioButton
并将其 Checked
值绑定到数据源的 Mode
属性。然后,您需要使用 Binding
的 Format
和 Parse
事件将 Mode
值转换为适合 Checked
属性 的值,反之亦然。
示例 - 使用 FlowLayoutPanel 的单选按钮列表
例如,在您的表单上放置一个 FlowLayoutPanel
控件,然后在 Form
的 Load
事件中编写以下代码。该代码将动态添加 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>
或 BindingSource
其 [=31= 中包含 List<MyCustomObject>
].
另一种选择 - 使用所有者绘制列表框的单选按钮列表
作为另一种选择,您可以使用所有者绘制 ListBox
并为项目渲染 RadioButton
。这样,您可以将 ListBox
的 SelectedValue
绑定到对象的 Mode
属性。下面代码中的 dataSourcs
可以像上面的例子一样。在表单上放置一个 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);
};
截图
您可以在下图中看到两种解决方案:
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;
备注
回答完这个问题后,我在这个post中创建并分享了一个RadioButtonList
控件:WinForms RadioButtonList doesn't exist。
它具有数据绑定支持,您可以像 ListBox
一样使用此控件。为此,将它绑定到模型的 属性 就足够了,然后以这种方式简单地设置控件的数据源:
radioButtonList1.DataSource = Enum.GetValues(typeof(YourEnumType));
假设我有几个单选按钮和一些自定义对象作为数据源。
举个例子
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
等等等等
还是为此使用事件更好?
P.S。
我知道如何使用事件,但是像 rb1chnaged
、rb2changed
、...、rb100changed
这样的事件一个接一个地创建事件让我不知所措,不是吗?
P.P.S.
圣诞快乐!
对于枚举的每个值,您需要创建一个 RadioButton
并将其 Checked
值绑定到数据源的 Mode
属性。然后,您需要使用 Binding
的 Format
和 Parse
事件将 Mode
值转换为适合 Checked
属性 的值,反之亦然。
示例 - 使用 FlowLayoutPanel 的单选按钮列表
例如,在您的表单上放置一个 FlowLayoutPanel
控件,然后在 Form
的 Load
事件中编写以下代码。该代码将动态添加 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>
或 BindingSource
其 [=31= 中包含 List<MyCustomObject>
].
另一种选择 - 使用所有者绘制列表框的单选按钮列表
作为另一种选择,您可以使用所有者绘制 ListBox
并为项目渲染 RadioButton
。这样,您可以将 ListBox
的 SelectedValue
绑定到对象的 Mode
属性。下面代码中的 dataSourcs
可以像上面的例子一样。在表单上放置一个 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);
};
截图
您可以在下图中看到两种解决方案:
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;
备注
回答完这个问题后,我在这个post中创建并分享了一个RadioButtonList
控件:WinForms RadioButtonList doesn't exist。
它具有数据绑定支持,您可以像 ListBox
一样使用此控件。为此,将它绑定到模型的 属性 就足够了,然后以这种方式简单地设置控件的数据源:
radioButtonList1.DataSource = Enum.GetValues(typeof(YourEnumType));