如何将 DataGridViewComboBoxColumn 绑定到对象?

发布于 2024-07-15 00:23:48 字数 746 浏览 12 评论 0原文

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

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 值无效

什么想法吗?

I'm trying to bound a DataGridViewComboBoxColumn to an instance of Foo, but when i set a value on the grid i got a ArgumentException telling me that i can not convert from String to 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

Am i missing something? is it possible to databind to a complex object?

UPDATE:

I implemented a TypeConverter and overrided CanConvertFrom, CanConvertTo, ConvertTo, ConvertFrom. Now i'm getting

FormatException: The DataGridViewComboBoxCell value is not valid

Any ideas?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

零度℉ 2024-07-22 00:23:48

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

希望它有帮助。

the DataGridViewComboBoxColumn should always have all the possible values at the combobox Items list or it will throw "FormatException: The DataGridViewComboBoxCell value is not valid".

If you are trying to get back values chosen from one combobox column, you can handle the DataGridView CellParsing event, and get the selected item from DataGridView.EditingControl cause it will be set for editing control from the edited column. Here is a exemple:

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

You also can customize the way your objects are show on each cell by handling the cell Formatting Event, here is a code that display toString for any object or interface.

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

Handles this two events should be enough for show and edit data within any bussiness object and its easer then write type converters. For this work set you DataGridView and you combobox column as follow:

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 ();

No DisplayMember or ValueMember Property need to be set, just make sure your combobox data source list has all the possible values for Foo.

Hope its helps.

仅冇旳回忆 2024-07-22 00:23:48

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

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

You are missing a possible piece.

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;

UPDATE:

Actually, after reading your question again, I think you are facing that noted bug. There is unfortunately no way to make it return the bound object without using a custom TypeDescriptor/TypeConverter/BindingSource.

Answer for binding to a complex object. No by default. I wrote quite a nice one for my current project. This involves making a custom TypeDescriptor/TypeConverter/BindingSource that returns all the nested properties. Another 'bug', you cant use '.' for a member separator, I had to resort to ':' instead.

方觉久 2024-07-22 00:23:48

实际上,您可以在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;
}

Actually, you can use a complex type in DataGridViewComboBoxColumn.

For example:

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

Self is:

public ValueModeItem Self
{
    get
    {
        return this;
    }
}

Very important - need to override 'Equals' method of a complex type.
In my case:

public override bool Equals(object obj)
{
    if (obj is ValueModeItem && obj != null)
    {
        if (...)
            return true;
    }
    return false;
}
滥情稳全场 2024-07-22 00:23:48

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

您的模型是 Foo,并且您当然希望 ComboBox 的值是项目本身。 为此,最简单的方法是在 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 的 Value 应该是预期的 Foo 类型。

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

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

I was constantely hitting the same problem until I discovert that you cannot set the DisplayMember of the DataGridViewComboBoxCell without setting the ValueMember too.
In the same way, setting the ValueMember and not the DisplayMember is a fail too, you have to define none or both.

Your model is Foo, and you certainly want that the Value of the ComboBox be the item itself. For doing this, the simplest way is too create a Property in your foo, returning itself.

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

Then bindings becomes:

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

This should work, and the Value of the Cell should be of type Foo as expected.

An interesting reference: Problems with the DataGridViewComboBoxColumn

However, the DataGridViewComboBoxColumn doesn't work like this,
although it will display the ToString value if you don't set the
DisplayMember, something internally goes wrong when it tries to look
up the SelectedItem, you have to set DisplayMember to a public
property of your class. Even worse, the default behaviour if you don't
set the ValueMember property is to return the DisplayMember, there's
no way of getting actual item itself. The only work around is to add a
property to your class that returns itself and set that property to
the ValueMember. Of course, if your item isn't something you are able
to change (such as one of the framework classes) you'll have to cludge
together a container object that holds a reference to your item.

旧伤慢歌 2024-07-22 00:23:48

我也遇到了这个问题。 我想要一个 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());
    }
}

I was having an issue with this as well. I wanted a ComboBoxColumn filled with the IssueNoteType from my class but when I selected the value it was trying to pass a string to the DataBoundItem. To solve this problem I captured the cell change event grabbed the correct object from the selected name and applied it to the modified row's 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());
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文