C# 通过在单元格中键入,将项动态添加到DataGridView组合框列

C# 通过在单元格中键入,将项动态添加到DataGridView组合框列,c#,.net,winforms,datagridview,datagridviewcombobox,C#,.net,Winforms,Datagridview,Datagridviewcombobox,我有一个DataGridView,它有一个ComboBox列,当下拉列表显示时,我必须更新每个ComboBox的可能值。我还必须使组合框能够具有自定义类型的值。键入新值时,应将其添加到可能值列表中。问题是我得到了无限多的DataError事件触发器(错误消息框),我知道如何通过更改DataGridViewDataErrorEventArgs对象中的字段来处理它,但我知道这不是正确的处理方法: private void DataGridView1_DataError(object sender,

我有一个
DataGridView
,它有一个
ComboBox
列,当下拉列表显示时,我必须更新每个ComboBox的可能值。我还必须使组合框能够具有自定义类型的值。键入新值时,应将其添加到可能值列表中。问题是我得到了无限多的
DataError
事件触发器(错误消息框),我知道如何通过更改
DataGridViewDataErrorEventArgs
对象中的字段来处理它,但我知道这不是正确的处理方法:

private void DataGridView1_DataError(object sender, DataGridViewDataErrorEventArgs e)
{
    e.Cancel = false;
}
如果我的操作方式不正确,在从下拉列表中选择一个值或键入一个新值后,
CellValueChanged
会被触发,但关闭的
组合框
不会显示当前值,而是显示一个已经存在的值(列表中的第一个)

在下面的代码中,表单子类是
Form2
,初始值存储在
str
字段中,并调用
UpdatePossibleValues
方法来更新数据网格视图中唯一列a
DataGridViewComboBoxColumn
中所有
组合框中的可能值:

public Form2()
{
    InitializeComponent();

    dataGridView1.EditingControlShowing += DataGridView1_EditingControlShowing;

    UpdatePossibleValues();
}

internal List<string> str = new List<string>()
{
    "val1",
    "val2"
};

private void DataGridView1_EditingControlShowing(object sender, 
    DataGridViewEditingControlShowingEventArgs e)
{
    if (dataGridView1.CurrentCell == null ||
        dataGridView1.CurrentCell.OwningColumn == null ||
        dataGridView1.CurrentCell.OwningColumn.Name != "column1")
    {
        return;
    }
    var combo = e.Control as DataGridViewComboBoxEditingControl;
    if (combo == null)
    {
        return;
    }

    var cb = combo as ComboBox;
    UpdatePossibleValues(cb);
    cb.DropDownStyle = ComboBoxStyle.DropDown; // this makes the ComboBoxes editable
    cb.Validating += Cb_Validating;
}

private void Cb_Validating(object sender, System.ComponentModel.CancelEventArgs e)
{
    var cbo = sender as ComboBox;
    string t = cbo.Text;

    var cell = (DataGridViewComboBoxCell)dataGridView1.CurrentCell;

    // add the value to the list if it is not there
    if (!string.IsNullOrEmpty(t) &&
        !cbo.Items.Contains(t))
    {
        str.Add(t);

        UpdatePossibleValues(cbo);

        cell.Value = t;

        e.Cancel = false;
    }
}

private void UpdatePossibleValues(ComboBox cb = null)
{
    if (cb == null)
    {
        var col = dataGridView1.Columns[0] as DataGridViewComboBoxColumn;

        col.Items.Clear();
        foreach (string s in str)
        {
            col.Items.Add(s);
        }
    }
    else
    {
        cb.Items.Clear();
        foreach (string s in str)
        {
            cb.Items.Add(s);
        }
    }
}
public Form2()
{
初始化组件();
dataGridView1.EditingControlShowing+=dataGridView1\u EditingControlShowing;
UpdatePossibleValues();
}
内部列表str=新列表()
{
“val1”,
“val2”
};
私有void DataGridView1_EditingControlShowing(对象发送方,
DataGridViewEditingControlShowingEventArgs(e)
{
如果(dataGridView1.CurrentCell==null||
dataGridView1.CurrentCell.OwningColumn==null||
dataGridView1.CurrentCell.OwningColumn.Name!=“column1”)
{
返回;
}
var combo=e.控件作为DataGridViewComboBoxEditingControl;
if(combo==null)
{
返回;
}
var cb=组合框形式的组合;
更新可允许值(cb);
cb.DropDownStyle=ComboBoxStyle.DropDown;//这使组合框可编辑
cb.Validating+=cb_Validating;
}
私有无效Cb_验证(对象发送方,System.ComponentModel.CancelEventArgs e)
{
var cbo=发送方作为组合框;
字符串t=cbo.Text;
变量单元格=(DataGridViewComboxCell)dataGridView1.CurrentCell;
//如果列表中没有该值,则将其添加到列表中
如果(!string.IsNullOrEmpty(t)&&
!cbo.Items.Contains(t))
{
str.Add(t);
更新可允许值(cbo);
单元值=t;
e、 取消=假;
}
}
私有void updatePassibleValues(组合框cb=null)
{
如果(cb==null)
{
var col=dataGridView1。列[0]作为DataGridViewComboBoxColumn;
col.Items.Clear();
foreach(str中的字符串s)
{
列项目。添加;
}
}
其他的
{
cb.Items.Clear();
foreach(str中的字符串s)
{
cb.项目。添加;
}
}
}
截图:


要将项目动态添加到
DataGridViewComboBoxColumn

public Form2()
{
    InitializeComponent();

    dataGridView1.EditingControlShowing += DataGridView1_EditingControlShowing;

    UpdatePossibleValues();
}

internal List<string> str = new List<string>()
{
    "val1",
    "val2"
};

private void DataGridView1_EditingControlShowing(object sender, 
    DataGridViewEditingControlShowingEventArgs e)
{
    if (dataGridView1.CurrentCell == null ||
        dataGridView1.CurrentCell.OwningColumn == null ||
        dataGridView1.CurrentCell.OwningColumn.Name != "column1")
    {
        return;
    }
    var combo = e.Control as DataGridViewComboBoxEditingControl;
    if (combo == null)
    {
        return;
    }

    var cb = combo as ComboBox;
    UpdatePossibleValues(cb);
    cb.DropDownStyle = ComboBoxStyle.DropDown; // this makes the ComboBoxes editable
    cb.Validating += Cb_Validating;
}

private void Cb_Validating(object sender, System.ComponentModel.CancelEventArgs e)
{
    var cbo = sender as ComboBox;
    string t = cbo.Text;

    var cell = (DataGridViewComboBoxCell)dataGridView1.CurrentCell;

    // add the value to the list if it is not there
    if (!string.IsNullOrEmpty(t) &&
        !cbo.Items.Contains(t))
    {
        str.Add(t);

        UpdatePossibleValues(cbo);

        cell.Value = t;

        e.Cancel = false;
    }
}

private void UpdatePossibleValues(ComboBox cb = null)
{
    if (cb == null)
    {
        var col = dataGridView1.Columns[0] as DataGridViewComboBoxColumn;

        col.Items.Clear();
        foreach (string s in str)
        {
            col.Items.Add(s);
        }
    }
    else
    {
        cb.Items.Clear();
        foreach (string s in str)
        {
            cb.Items.Add(s);
        }
    }
}
  • Hanlde
    EditingControlShowing
    并获取
    datagridviewcomboxeditingcontrol
  • 将编辑控件
    DropDownStyle
    设置为
    DropDown
  • 处理编辑控件的
    验证
    事件,并确保只附加一次事件处理程序
  • 检查编辑控件的
    文本是否不存在于以下项目中:
    
    • 将其添加到列的数据源
    • 然后通过将列的数据源设置为null并再次分配数据源来重置该列的数据源
  • 注:

    • 如果有多个组合框,请确保对组合框使用不同的数据源,并在验证事件中更新相应的数据源

    • 如果使用匿名方法处理事件,请确保对捕获的变量有正确的假设。为了简单起见,可以使用普通方法处理事件

    示例

    下面的示例显示了一个
    DataGridView
    具有两个
    datagridviewcomboxcolumn
    的视图,对于第二个视图,可以在运行时通过在组合框中键入来添加新值

    要运行该示例,请创建一个
    表单
    ,并将一个
    DataGridView
    放到一个新表单上,然后在表单中复制并粘贴以下代码:

    private List<String> comboSource1;
    private List<String> comboSource2;
    protected override void OnLoad(EventArgs e)
    {
        base.OnLoad(e);
        comboSource1 = new List<string> { "A", "B" };
        comboSource2 = new List<string> { "1", "2" };
    
        var dt = new DataTable();
        dt.Columns.Add("C1");
        dt.Columns.Add("C2");
        dt.Rows.Add("A", "1");
        dt.Rows.Add("B", "2");
    
        var c1 = new DataGridViewComboBoxColumn();
        c1.Name = "C1";
        c1.DataPropertyName = "C1";
        c1.DataSource = comboSource1;
    
        var c2 = new DataGridViewComboBoxColumn();
        c2.Name = "C2";
        c2.DataPropertyName = "C2";
        c2.DataSource = comboSource2;
    
        dataGridView1.Columns.AddRange(c1, c2);
    
        this.dataGridView1.DataSource = dt;
        dataGridView1.EditingControlShowing += dataGridView1_EditingControlShowing;
        dataGridView1.EditMode = DataGridViewEditMode.EditOnEnter;
    }
    
    私有列表comboSource1;
    私人名单2;
    受保护的覆盖无效加载(事件参数e)
    {
    基础荷载(e);
    comboSource1=新列表{“A”,“B”};
    comboSource2=新列表{“1”,“2”};
    var dt=新数据表();
    dt.列添加(“C1”);
    dt.列添加(“C2”);
    增加(“A”、“1”);
    增加(“B”、“2”);
    var c1=新的DataGridViewComboxColumn();
    c1.Name=“c1”;
    c1.DataPropertyName=“c1”;
    c1.DataSource=comboSource1;
    var c2=新的DataGridViewComboxColumn();
    c2.Name=“c2”;
    c2.DataPropertyName=“c2”;
    c2.DataSource=comboSource2;
    dataGridView1.Columns.AddRange(c1,c2);
    this.dataGridView1.DataSource=dt;
    dataGridView1.EditingControlShowing+=dataGridView1\u EditingControlShowing;
    dataGridView1.EditMode=DataGridViewEditMode.Editonner;
    }
    
    private void dataGridView1\u编辑控制显示(对象发送方,
    DataGridViewEditingControlShowingEventArgs(e)
    {
    var dataGridView=发送方为dataGridView;
    如果(dataGridView?.CurrentCell?.ColumnIndex!=1)返回;
    var comboBox=e.控件作为DataGridViewComboBox编辑控件;
    if(comboBox==null)返回;
    comboBox.DropDownStyle=ComboBoxStyle.DropDown;
    如果(!true.Equals(comboBox.Tag))
    {
    comboBox.Tag=true;
    comboBox.Validating+=(对象、参数)=>
    {
    变量列=(DataGridViewComboxColumn)dataGridView.CurrentCell.OwningColumn;
    var list=comboBox.DataSource作为列表;
    if(list==null)返回;
    var txt=combo