【问题标题】:How to bound a DataGridViewComboBoxColumn to a object?如何将 DataGridViewComboBoxColumn 绑定到对象?
【发布时间】:2009-03-10 16:34:39
【问题描述】:

我正在尝试将 DataGridViewComboBoxColumn 绑定到 Foo 的一个实例,但是当我在网格上设置一个值时,我得到一个 ArgumentException 告诉我我无法从 String 转换为 Foo。

var data = (from item in someTable
            select new { Foo = item.foo, Bar = item.Bar }).ToList();
grid.DataSource = data;
column.DataPropertyName = "Foo";
column.DataSource = (from foo in Foo select foo).ToList (); //foo is an instance of Foo
column.DisplayMember = "SomeNameField"; //Foo.SomeNameField contains a description of the instance

我错过了什么吗?是否可以将数据绑定到复杂对象?

更新:

我实现了一个 TypeConverter 并覆盖了 CanConvertFrom、CanConvertTo、ConvertTo、ConvertFrom。现在我得到了

FormatException:DataGridViewComboBoxCell 值无效

有什么想法吗?

【问题讨论】:

    标签: c# winforms data-binding datagridview datagridviewcombobox


    【解决方案1】:

    DataGridViewComboBoxColumn 应始终在组合框项列表中包含所有可能的值,否则将抛出“FormatException:DataGridViewComboBoxCell 值无效”。

    如果您试图取回从一个组合框列中选择的值,您可以处理 DataGridView CellParsing 事件,并从 DataGridView.EditingControl 获取选定项,因为它将设置为从已编辑列中编辑控件。这是一个例子:

    private void dataGridView1_CellParsing(object sender, 
     DataGridViewCellParsingEventArgs e) {
       if (dataGridView1.CurrentCell.OwningColumn is DataGridViewComboBoxColumn) {
           DataGridViewComboBoxEditingControl editingControl = 
                    (DataGridViewComboBoxEditingControl)dataGridView1.EditingControl;
           e.Value = editingControl.SelectedItem;
           e.ParsingApplied = true;
       }
    }
    

    您还可以通过处理单元格格式化事件来自定义对象在每个单元格上的显示方式,这里有一段代码可以为任何对象或界面显示 toString。

    private void dataGridView1_CellFormatting(object sender, 
        DataGridViewCellFormattingEventArgs e) {
            if (e.Value != null) {
                e.Value = e.Value.ToString();
                e.FormattingApplied = true;
            }
        } 
    

    处理这两个事件应该足以显示和编辑任何业务对象中的数据,然后编写类型转换器。对于这项工作,您将 DataGridView 和您的组合框列设置如下:

    var data = (from item in someTable
            select new { Foo = item.foo, Bar = item.Bar }).ToList();
    grid.DataSource = data;
    column.DataPropertyName = "Foo";
    column.DataSource = (from foo in Foo select foo).ToList ();
    

    无需设置 DisplayMember 或 ValueMember 属性,只需确保您的组合框数据源列表包含 Foo 的所有可能值。

    希望对您有所帮助。

    【讨论】:

    • 有趣的是,这是唯一对我有用的东西,同时也是最简单的。我看不出它是如何只获得 4 票并且很难找到的。知道为什么默认实现会尝试 Convert 所选项目的字符串表示为数据源的类型(对于自定义类型失败并且很难使用自定义转换器进行自定义),而不是仅仅设置所选项目(可用!),就像标准组合框一样??
    【解决方案2】:

    你错过了一个可能的部分。

    column.DataPropertyName = "Foo";
    column.DisplayMember = "SomeNameField"; 
    column.ValueMember = "Bar"; // must do this, empty string causes it to be 
                                // of type string, basically the display value
                                // probably a bug in .NET
    column.DataSource = from foo in Foo select foo;
    grid.DataSource = data;
    

    更新:

    实际上,在再次阅读您的问题后,我认为您正面临着那个注意到的错误。不幸的是,如果不使用自定义 TypeDescriptor/TypeConverter/BindingSource,就无法让它返回绑定的对象。

    绑定到复杂对象的答案。默认没有。我为我当前的项目写了一个相当不错的。这涉及制作一个返回所有嵌套属性的自定义 TypeDescriptor/TypeConverter/BindingSource。另一个“错误”,您不能使用“。”对于成员分隔符,我不得不求助于 ':'。

    【讨论】:

    • 如何制作 TypeConverter?
    • 您从 TypeConverter 继承并覆盖 GetProperties/GetPropertiesSupported 方法。然后将该类型应用于所需目标类型的 TypeConverterAttribute。学科范围非常大。谷歌寻找更多方向。
    • 我实现了一个 TypeConverter 并覆盖了 CanConvertTo、CanConvertFrom、ConvertTo 和 ConvertFrom,现在我在设置值后收到错误“FormatException:DataGridViewComboBoxCell 的值无效”
    【解决方案3】:

    其实你可以在DataGridViewComboBoxColumn中使用复杂类型。

    例如:

    DataGridViewComboBoxColumn.DataPropertyName = "ValueMode";
    DataGridViewComboBoxColumn.DisplayMember = "Label";
    DataGridViewComboBoxColumn.ValueMember = "Self"; *
    DataGridViewComboBoxColumn.ValueType = typeof(ValueModeItem);
    

    Self 是:

    public ValueModeItem Self
    {
        get
        {
            return this;
        }
    }
    

    非常重要 - 需要重写复杂类型的 'Equals' 方法。 就我而言:

    public override bool Equals(object obj)
    {
        if (obj is ValueModeItem && obj != null)
        {
            if (...)
                return true;
        }
        return false;
    }
    

    【讨论】:

      【解决方案4】:

      我一直在遇到同样的问题,直到我发现如果不设置 ValueMember 就无法设置 DataGridViewComboBoxCell 的 DisplayMember。
      同样,设置ValueMember 而不是DisplayMember 也是失败的,您必须定义一个或两者都没有。

      您的模型是 Foo,您当然希望 ComboBox 的 Value 是项目本身。为此,最简单的方法是在您的 foo 中创建一个 Property,然后返回自身。

      public class Foo
      {
          ...
          public Foo This { get {return this; } }
      }
      

      那么绑定就变成了:

      column.DataPropertyName = "Foo";
      column.DataSource = (from foo in Foo select foo).ToList (); //foo is an instance of Foo
      column.DisplayMember = "SomeNameField"; //Foo.SomeNameField contains a description of the instance
      column.ValueMember = "This";
      

      这应该可以工作,并且单元格的值应该是 Foo 类型,正如预期的那样。

      一个有趣的参考:Problems with the DataGridViewComboBoxColumn

      但是,DataGridViewComboBoxColumn 不能这样工作, 虽然如果你不设置它会显示 ToString 值 DisplayMember,尝试查看时出现内部问题 上 SelectedItem,您必须将 DisplayMember 设置为公共 你班级的财产。更糟糕的是,如果你不这样做,默认行为 设置ValueMember属性就是返回DisplayMember,有 无法获得实际物品本身。唯一的解决方法是添加一个 属性到您的类,该类返回自身并将该属性设置为 价值成员。当然,如果你的物品不是你能做的 要更改(例如框架类之一),您必须坚持 一个包含对您的项目的引用的容器对象。

      【讨论】:

        猜你喜欢
        • 2017-01-02
        • 1970-01-01
        • 2012-07-01
        • 1970-01-01
        • 1970-01-01
        • 2013-10-21
        • 2019-08-04
        • 2010-10-27
        • 1970-01-01
        相关资源
        最近更新 更多