2

当我有一个DataGridViewComboBoxColumn填充绑定值时,如果我设置了DisplayMember属性,我会DataError用 a 引发事件FormatException

DataGridViewComboBoxCell 值无效

如果DisplayMember未设置,则视图显示 的结果.ToString(),所有工作都按预期工作。

这是一个完整的例子:

public partial class Form1 : Form
{
    public Form1() { InitializeComponent(); }

    private void Form1_Load(object sender, EventArgs e)
    {
        var categories = new[] { CustomerCategory.Cat1, CustomerCategory.Cat2, CustomerCategory.Cat3 };
        this.dataGridView1.AutoGenerateColumns = false;
        this.dataGridView1.DataError += new DataGridViewDataErrorEventHandler(dataGridView1_DataError);
        this.dataGridView1.CellParsing += new DataGridViewCellParsingEventHandler(dataGridView1_CellParsing);
        this.dataGridView1.Columns.Add(new DataGridViewComboBoxColumn()
        {
            DataSource = categories,
            HeaderText = "Category",
            DataPropertyName = "Category",
            DisplayMember = "Name" // if we omit this line, there is not DataError event raised
        });

        this.dataGridView1.DataSource = new[] 
        { 
              new Customer() { Category = CustomerCategory.Cat1 } 
            , new Customer() { Category = CustomerCategory.Cat2 } 
            , new Customer() { Category = CustomerCategory.Cat3 } 
        }.ToList();
    }

    void dataGridView1_DataError(object sender, DataGridViewDataErrorEventArgs e)
    {
        var value = this.dataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex].Value;
        var type = value != null ? value.GetType() : null;
        string message = "Error"
            + Environment.NewLine + " - Column : " + e.ColumnIndex
            + Environment.NewLine + " - Line  : " + e.RowIndex
            + Environment.NewLine + " - Value : " + Convert.ToString(value) + " (" + type + ")"
            + Environment.NewLine + " - Exception : " + e.Exception.Message;
        Debug.Fail(message);
    }

    void dataGridView1_CellParsing(object sender, DataGridViewCellParsingEventArgs e)
    {
        //http://stackoverflow.com/questions/631126/how-to-bound-a-datagridviewcomboboxcolumn-to-a-object
        if (this.dataGridView1.CurrentCell.OwningColumn is DataGridViewComboBoxColumn)
        {
            var editingControl = (DataGridViewComboBoxEditingControl)this.dataGridView1.EditingControl;
            e.Value = editingControl.SelectedItem;
            e.ParsingApplied = true;
        }
    }
}

该模型:

public class CustomerCategory
{
    public static readonly CustomerCategory Cat1 = new CustomerCategory { Name = "Cat1" };
    public static readonly CustomerCategory Cat2 = new CustomerCategory { Name = "Cat2" };
    public static readonly CustomerCategory Cat3 = new CustomerCategory { Name = "Cat3" };

    public string Name { get; set; }
    public override string ToString() { return this.Name; }
}
public class Customer { public CustomerCategory Category { get; set; } }

如何在不引发DisplayMember这个烦人的事件的情况下指定我自己的? 该问题仅出现在 . 中,而不出现在常规. 中。DataError
DataGridViewComboBoxColumnComboBox

编辑:经过几次测试,我可以说:

[DisplayMember + Not ValueMember] = FAIL
[Not DisplayMember + ValueMember] = FAIL
[DisplayMember + ValueMember] = WIN

所以我的问题可以改写为:是否有任何文件可以准确解释什么可行,什么不可行?以及DisplayMember+ValueMember是如何像看起来那样连接在一起的?

重新编辑:

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

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

有人有关于内部出错部分的任何信息吗?

4

1 回答 1

1

以下逻辑可以帮助您解决问题。

我认为问题出在代码行的顺序上。在分配显示成员属性后分配数据源可能会导致错误。

改变这一行;

this.dataGridView1.Columns.Add(new DataGridViewComboBoxColumn()
{
    DataSource = categories,
    HeaderText = "Category",
    DataPropertyName = "Category",
    DisplayMember = "Category" // if we omit this line, there is not DataError event raised
});

DataGridViewComboBoxColumn col = new DataGridViewComboBoxColumn();
col.HeaderText = "Category";
col.DataSource = categories;
col.DisplayMember = "Category";
col.DataPropertyName = "Category";
this.dataGridView1.Columns.Add(col);

必须在 DisplayMember 和 ValueMember 之前分配数据源。

于 2014-02-26T08:15:56.280 回答