4

我试图将 a 绑定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 值无效

有任何想法吗?

4

4 回答 4

7

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 的所有可能值。

希望它有所帮助。

于 2011-08-11T20:21:41.270 回答
6

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

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。另一个“错误”,您不能使用“。” 对于成员分隔符,我不得不求助于“:”。

于 2009-03-10T16:38:39.397 回答
5

实际上,您可以在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;
}
于 2013-11-29T11:21:37.807 回答
3

我一直在遇到同样的问题,直到我发现如果不设置 the 就无法DisplayMember设置DataGridViewComboBoxCellthe ValueMember
同样,设置 theValueMember而不是 theDisplayMember也是失败的,您必须定义 none 或同时定义两者。

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

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 类型,如预期的那样。

一个有趣的参考:DataGridViewComboBoxColumn 的问题

但是,DataGridViewComboBoxColumn 不是这样工作的,尽管如果您不设置 DisplayMember,它将显示 ToString 值,但当它尝试查找 SelectedItem 时出现内部问题,您必须将 DisplayMember 设置为的公共属性你的班。更糟糕的是,如果您不设置 ValueMember 属性,则默认行为是返回 DisplayMember,无法获取实际项目本身。唯一的解决方法是向您的类添加一个返回自身的属性并将该属性设置为 ValueMember。当然,如果您的项目不是您能够更改的东西(例如框架类之一),您将不得不将一个容器对象聚集在一起,该容器对象包含对您的项目的引用。

于 2013-11-08T16:05:15.533 回答