设置 DisplayMember 时 DataGridViewComboBoxColumn 会发生啥?

Posted

技术标签:

【中文标题】设置 DisplayMember 时 DataGridViewComboBoxColumn 会发生啥?【英文标题】:What happen to DataGridViewComboBoxColumn when DisplayMember is set?设置 DisplayMember 时 DataGridViewComboBoxColumn 会发生什么? 【发布时间】:2013-11-08 14:27:21 【问题描述】:

当我有一个充满绑定值的DataGridViewComboBoxColumn,并且如果我设置了DisplayMember 属性,我会得到DataError 引发的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://***.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 事件? 问题只出现在DataGridViewComboBoxColumn 上,而不是普通的ComboBox

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

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

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

重新编辑:

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

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

有人有关于内部出现问题部分的任何信息吗?

【问题讨论】:

什么是 Exception.Message?如果您使用 DisplayMember,我认为您还必须设置 ValueMember。 对不起。你有没有 -1ed 我的答案?你能解释一下原因吗? 告诉我你无法理解的确切点:有一个一维数据源,你不需要引用任何列(只要只有 1 列);如果要引用列,请使用带有列的 2D 数据源。请告诉我哪一部分让你感到困惑。 您现在可以删除这个问题(这就是你们人们的行为方式,不是吗?):您已经拥有信息(1D 和 2D 数据源之间的差异;如果发现 DataGridView 存在问题依赖DataTable;类的属性名称不能被视为列(MSDN 可以松散地引用属性,但如前所述,真正支持列和DataGridViews)),您可以在需要其他内容时返回并返回。 【参考方案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 之前分配数据源。

【讨论】:

以上是关于设置 DisplayMember 时 DataGridViewComboBoxColumn 会发生啥?的主要内容,如果未能解决你的问题,请参考以下文章

ComboBox.ValueMember 和 DisplayMember

easyui------设置datagrid('getEditor')时焦点问题

ComboBox 中 DisplayMember 和 ValueMember有何区别

如何设置combobox 下拉框的内容

CheckedListbox Displaymember 和 ValueMember

具有 Datagridviewcombobox 列的单元格显示 ValueMember 而不是 DisplayMember