如何将 DataGridViewComboBoxColumn 绑定到对象?

问题描述 投票:0回答:5

我正在尝试将

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
5个回答
10
投票

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

希望有帮助。


7
投票

你可能漏掉了一块。

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


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

3
投票

我不断遇到同样的问题,直到我发现如果不设置

DisplayMember
,则无法设置
DataGridViewComboBoxCell
ValueMember

同样,设置
ValueMember
而不是
DisplayMember
也是失败的,你必须不定义或两者都定义。

您的模型是 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";

这应该可行,并且 Cell 的值应为预期的 Foo 类型。

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

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


0
投票

我也遇到了这个问题。我想要一个 ComboBoxColumn 填充我的类中的 IssueNoteType,但是当我选择该值时,它试图将字符串传递给 DataBoundItem。为了解决这个问题,我捕获了单元格更改事件,从所选名称中抓取了正确的对象,并将其应用于修改后的行的 DataBoundItem。

private void notesDGV_CellValueChanged(object sender, DataGridViewCellEventArgs e)
{
    if (notesDGV.CurrentCell == null) { return; }
    if (notesDGV.CurrentCell.OwningColumn is DataGridViewComboBoxColumn)
    {
       IssueNote isn = (IssueNote)notesDGV.Rows[e.RowIndex].DataBoundItem;
       isn.NoteType = _productionIssuer.GetIssueNoteTypes.GetIssueNoteType(notesDGV.Rows[e.RowIndex].Cells[e.ColumnIndex].Value.ToString());
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.