如何在 DataGridView 显示对象的值中自定义控件?

How to have custom control in DataGridView display object's value?

我有一个示例项目位于 here

该项目有一个主窗体 Form1,用户可以在其中在数据网格视图中输入客户。 CustomerType 列是一个自定义控件,当用户单击该按钮时,会弹出一个搜索表单 Form2

搜索表单填充了 CustomerType 类型的列表。用户可以通过双击行来select一条记录,这个对象应该在自定义控件中设置。然后 DataGridView 应该显示 Description 属性 但在背景中每个单元格都应该保存值(即 CustomerType 实例)。

相关代码位于以下classes:

第class列:

public class DataGridViewCustomerTypeColumn : DataGridViewColumn
{
    public DataGridViewCustomerTypeColumn()
        : base(new CustomerTypeCell())
    { }

    public override DataGridViewCell CellTemplate
    {
        get { return base.CellTemplate; }
        set
        {
            if (value != null && !value.GetType().IsAssignableFrom(typeof(CustomerTypeCell)))
            {
                throw new InvalidCastException("Should be CustomerTypeCell.");
            }

            base.CellTemplate = value;
        }
    }
}

单元格class:

public class CustomerTypeCell : DataGridViewTextBoxCell
{
    public CustomerTypeCell()
        : base()
    { }

    public override void InitializeEditingControl(int rowIndex, object initialFormattedValue, DataGridViewCellStyle dataGridViewCellStyle)
    {
        base.InitializeEditingControl(rowIndex, initialFormattedValue, dataGridViewCellStyle);

        CustomerTypeSearch ctl = DataGridView.EditingControl as CustomerTypeSearch;

        if (this.Value == null)
            ctl.Value = (CustomerType)this.DefaultNewRowValue;
        else
            ctl.Value = (CustomerType)this.Value;
    }

    public override Type EditType
    {
        get { return typeof(CustomerTypeSearch); }
    }

    public override Type ValueType
    {
        get { return typeof(CustomerType); }
    }

    public override object DefaultNewRowValue
    {
        get { return null; }
    }
}

和自定义控件:

public partial class CustomerTypeSearch : UserControl, IDataGridViewEditingControl
{
    private DataGridView dataGridView;
    private int rowIndex;
    private bool valueChanged = false;
    private CustomerType value;

    public CustomerTypeSearch()
    {
        InitializeComponent();
    }

    public CustomerType Value
    {
        get { return this.value; }
        set 
        { 
            this.value = value;

            if (value != null)
                textBoxSearch.Text = value.Description;
            else
                textBoxSearch.Clear();
        }
    }

    private void buttonSearch_Click(object sender, EventArgs e)
    {
        Form2 f = new Form2();

        DialogResult dr = f.ShowDialog(this);

        if (dr == DialogResult.OK)
        {
            Value = f.SelectedValue;
        }
    }

    #region IDataGridViewEditingControl implementation

    public object EditingControlFormattedValue
    {
        get 
        {
            if (this.value != null)
                return this.value.Description;
            else
                return null;
        }
        set 
        { 
            if (this.value != null)
                this.value.Description = (string)value; 
        }
    }

    public object GetEditingControlFormattedValue(DataGridViewDataErrorContexts context)
    {
        return EditingControlFormattedValue;
    }

    public void ApplyCellStyleToEditingControl(DataGridViewCellStyle dataGridViewCellStyle)
    {
        this.BorderStyle = BorderStyle.None;
        this.Font = dataGridViewCellStyle.Font;
    }

    public int EditingControlRowIndex
    {
        get { return rowIndex; }
        set { rowIndex = value; }
    }

    public bool EditingControlWantsInputKey(Keys key, bool dataGridViewWantsInputKey)
    {
        return false;
    }

    public void PrepareEditingControlForEdit(bool selectAll)
    {
        //No preparation needs to be done 
    }

    public bool RepositionEditingControlOnValueChange
    {
        get { return false; }
    }

    public DataGridView EditingControlDataGridView
    {
        get { return dataGridView; }
        set { dataGridView = value; }
    }

    public bool EditingControlValueChanged
    {
        get { return valueChanged; }
        set { valueChanged = value; }
    }

    public Cursor EditingPanelCursor
    {
        get { return base.Cursor; }
    }

    #endregion

    private void CustomerTypeSearch_Resize(object sender, EventArgs e)
    {
        buttonSearch.Left = this.Width - buttonSearch.Width;
        textBoxSearch.Width = buttonSearch.Left;
    }
}

但是,DataGridView 没有显示文本,也没有保留每个单元格的 CustomerType 值。

我错过了什么?

首先,将 ToString() 方法覆盖到您的 CustomerType class。

其次,为避免解析错误,修改CustomerTypeSearch中的如下方法class:

public CustomerType Value
{
    get { return this.value; }
    set
    {
        this.value = value;

        if (value != null)
            textBoxSearch.Text = value.Description;
        else
            textBoxSearch.Clear();

        valueChanged = true;
        if ((EditingControlDataGridView.CurrentCell as CustomerTypeCell) != null)
            (EditingControlDataGridView.CurrentCell as CustomerTypeCell).Value = value;
    }
}

然后,将此函数添加到 CustormerTypeCell class :

protected override bool SetValue(int rowIndex, object value)
{
    if (value != null)
        return base.SetValue(rowIndex, value);
    return false;
}

最后,添加这个来处理数据错误:

private void dataGridView_DataError(object sender, DataGridViewDataErrorEventArgs e)
{
    e.Cancel = false;
}