将ComboBox DataSource设置为enum并绑定SelectedValue

本文关键字:绑定 SelectedValue enum ComboBox DataSource 设置 | 更新日期: 2023-09-27 18:16:33

我有点绝望,因为昨天它还在工作,但今天这不再工作了,让我解释一下,我想做什么:

我想将ComboBoxDataSource设置为特定枚举中的所有枚举值。就像这样:

cmbType.DataSource = m_addViewPresenter.Types;

,其中Types是一个BindingList,并且像这样初始化:

public BindingList<MyEnum> Types
{
    get { return m_types; }
    set
    {
        m_types = value;
        OnPropertyChanged();
    }
}
[ImportingConstructor]
public AddViewPresenter()
{
    Types = new BindingList<MyEnum>(
              Enum.GetValues(typeof(MyEnum))
                         .Cast<MyEnum>().ToList());
}

进一步,我想将当前选中的项绑定到一个属性。由于ComboBox.SelectedItem不触发INotifyProperty事件,我使用ComboBox.SelectedValue

cmbType.Bind(m_addViewPresenter, c => c.SelectedValue, m => m.SelectedValue);
public static void Bind<TComponent, T>(
    this TComponent component, T value,
    Expression<Func<TComponent, object>> controlProperty, 
    Expression<Func<T, object>> modelProperty)
    where TComponent : IBindableComponent
    where T : INotifyPropertyChanged
{
    var controlPropertyName = PropertyNameResolver.GetPropertyName(controlProperty);
    var modelPropertyName = PropertyNameResolver.GetPropertyName(modelProperty);
    component.DataBindings.Add(new Binding(controlPropertyName, value, modelPropertyName, false, DataSourceUpdateMode.OnPropertyChanged));
}

昨天很好,但是有些东西把事情搞砸了,今天我只得到一个InvalidOperationException:

不能在一个空的列表控件中设置SelectedValueValueMember .

我知道这是在黑暗中挖掘,但是谁能和我一起集思广益,找出问题是什么?提前感谢!

将ComboBox DataSource设置为enum并绑定SelectedValue

选项1

要使用SelectedValue进行数据绑定,请创建一个类DataItem:

public class DataItem
{
    public MyEnum Value { get; set; }
    public string Text { get; set; }
}
然后使用以下代码进行数据绑定:
this.comboBox1.DataSource = Enum.GetValues(typeof(MyEnum)).Cast<MyEnum>()
                                .Select(x => new DataItem() { Value = x, Text = x.ToString() })
                                .ToList();
this.comboBox1.ValueMember = "Value";
this.comboBox1.DisplayMember = "Text";
this.comboBox1.DataBindings.Add(
    new Binding("SelectedValue", yourObjectToBind, "PropertyOfYourObject"));

你可以让通用的DataItem<T>包含public T Value { get; set; },使它在你的项目中更容易重用。

选项2

使用SelectedItem进行数据绑定:

this.comboBox1.DataSource = Enum.GetValues(typeof(MyEnum));
this.comboBox1.DataBindings.Add(
    new Binding("SelectedItem", yourObjectToBind, "PropertyOfYourObject"));

选项3

作为Ivan Stoev建议的另一个选项,使用SelectedValue进行数据绑定,您可以这样执行数据绑定:

this.comboBox1.DataSource = Enum.GetValues(typeof(MyEnum));
this.comboBox1.DataBindings.Add(
    new Binding("SelectedValue", yourObjectToBind, "PropertyOfYourObject",
                true,  DataSourceUpdateMode.OnPropertyChanged));

编辑:Jannik:

选项1的基本通用方法是这样的:

public class ComboBoxItemWrapper<T>
{
    public T Value { get; set; }
    public string Text { get; set; }
}

好的,情况是这样的。您正确地绑定到ComboBox.SelectedValue。问题来自以下行:

component.DataBindings.Add(new Binding(controlPropertyName, value, modelPropertyName, false, DataSourceUpdateMode.OnPropertyChanged));

应该是

component.DataBindings.Add(new Binding(controlPropertyName, value, modelPropertyName, true, DataSourceUpdateMode.OnPropertyChanged));

简而言之,在使用WF数据绑定时,始终将Binding.FormattingEnabled设置为true(就像我的示例中回答您的另一个问题一样),并且您不会有问题。

一个修改后的例子,从我的回答Exchange UserControls在一个表单与数据绑定显示的情况和解决方案:

using System;
using System.Drawing;
using System.Windows.Forms;
namespace Tests
{
    enum MyEnum {  Red, Green, }
    class Controller
    {
        public MyEnum SelectedValue { get; set; }
    }
    static class Program
    {
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            var form = new Form();
            var topPanel = new Panel { Dock = DockStyle.Top, Parent = form };
            var combo = new ComboBox { Left = 8, Top = 8, Parent = topPanel };
            topPanel.Height = combo.Height + 16;
            combo.DataSource = (MyEnum[])Enum.GetValues(typeof(MyEnum));
            var c = new Controller();
            combo.DataBindings.Add(new Binding("SelectedValue", c, "SelectedValue", true, DataSourceUpdateMode.OnPropertyChanged));
            form.BindingContextChanged += (sender, e) =>
            {
                // If you change combo binding formatting enabled parameter to false,
                // the next will throw the exception you are getting
                c.SelectedValue = MyEnum.Red;
            };
            var panel1 = new Panel { Dock = DockStyle.Fill, Parent = form, BackColor = Color.Red };
            var panel2 = new Panel { Dock = DockStyle.Fill, Parent = form, BackColor = Color.Green };
            Bind(panel1, "Visible", combo, "SelectedValue", value => (MyEnum)value == MyEnum.Red);
            Bind(panel2, "Visible", combo, "SelectedValue", value => (MyEnum)value == MyEnum.Green);
            Application.Run(form);
        }
        static void Bind(Control target, string targetProperty, object source, string sourceProperty, Func<object, object> expression)
        {
            var binding = new Binding(targetProperty, source, sourceProperty, false, DataSourceUpdateMode.Never);
            binding.Format += (sender, e) => e.Value = expression(e.Value);
            target.DataBindings.Add(binding);
        }
    }
}

你可能也会发现下面的线程自定义WinForms数据绑定与转换器不工作在可空类型(双?)