一个自学的C#DataGridView组合框?

一个自学的C#DataGridView组合框?,c#,datagridview,datagridviewcomboboxcell,C#,Datagridview,Datagridviewcomboboxcell,我希望在DataGridView中有一列组合框,它允许用户自由输入一些文本,这些文本收集在下拉菜单中,以便在下一个框中输入相同的文本更快。我不想使用DataGridViewComboxColumn,除非我真的必须这样做 以下代码几乎可以完成此任务,但存在以下问题: 输入一些新文本并点击回车键后,新输入的文本立即替换为旧值 但新文本已成功添加到所有组合框的下拉菜单中 当我在其中一个框中选择这个新添加的文本时,就会出现DataGridView异常,抱怨值无效 出于验证目的,这些框似乎有一个数据源

我希望在DataGridView中有一列组合框,它允许用户自由输入一些文本,这些文本收集在下拉菜单中,以便在下一个框中输入相同的文本更快。我不想使用DataGridViewComboxColumn,除非我真的必须这样做

以下代码几乎可以完成此任务,但存在以下问题:

  • 输入一些新文本并点击回车键后,新输入的文本立即替换为旧值

  • 但新文本已成功添加到所有组合框的下拉菜单中

  • 当我在其中一个框中选择这个新添加的文本时,就会出现DataGridView异常,抱怨值无效

出于验证目的,这些框似乎有一个数据源的副本,但没有更新

    public partial class Form1 : Form
    {
        List<string> data = new List<string>();     // shared data source for all ComboBoxes

        private void checkData(string s)            // check wether s in the list, add it if not, keep things sorted
        {
            if (data.Contains(s))
                return;
            data.Add(s);
            data.Sort();
        }

        private void addCell(string s)          // add a new cell to the grid
        {
            checkData(s);
            DataGridViewComboBoxCell c = new DataGridViewComboBoxCell();
            c.DataSource = data;
            c.Value = s;
            int i = theGrid.Rows.Add();
            theGrid.Rows[i].Cells[0] = c;
        }

        public Form1()
        {
            InitializeComponent();
            theGrid.ColumnCount = 1;
            addCell("Foo");
            addCell("Bar");
        }

        // handler to enable the user to enter free text
        private void theGrid_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e)
        {
            ComboBox cb = e.Control as ComboBox;
            if (cb != null)
                cb.DropDownStyle = ComboBoxStyle.DropDown;
        }

        // handler which adds the entered text to the data source
        private void theGrid_CellValidating(object sender, DataGridViewCellValidatingEventArgs e)
        { 
            if (e.RowIndex < 0 || e.ColumnIndex < 0)
                return;
            checkData(e.FormattedValue.ToString());
        }
    }
公共部分类表单1:表单
{
List data=new List();//所有组合框的共享数据源
private void checkData(string s)//检查列表中是否有s,如果没有,则添加它,保持排序
{
如果(数据包含)
返回;
数据。添加;
data.Sort();
}
private void addCell(字符串s)//将新单元格添加到网格
{
检查数据;
DataGridViewComboxCell c=新的DataGridViewComboxCell();
c、 数据源=数据;
c、 值=s;
int i=theGrid.Rows.Add();
单元格[0]=c;
}
公共表格1()
{
初始化组件();
grid.ColumnCount=1;
addCell(“Foo”);
addCell(“Bar”);
}
//允许用户输入自由文本的处理程序
private void theGrid_EditingControlShowing(对象发送方、DataGridViewEditingControlShowingEventArgs e)
{
组合框cb=e。控件作为组合框;
如果(cb!=null)
cb.DropDownStyle=ComboBoxStyle.DropDown;
}
//将输入的文本添加到数据源的处理程序
私有void theGrid_CellValidating(对象发送方、DataGridViewCellValidatingEventArgs e)
{ 
如果(e.RowIndex<0 | | e.ColumnIndex<0)
返回;
checkData(例如FormattedValue.ToString());
}
}

经过一些测试后,我猜各个组合框并没有像您认为的那样得到更新。似乎在
checkData
方法中,
数据
用新的
s
更新。这将直观地更新组合框单元格,但是需要更新每个组合的数据源。因此,当选择新的附加值时,
DataError
异常

考虑到每个组合框单元格都是“独立”的,并且不是
DataGridViewComboBoxColumn
的一部分,因此有必要对所有行进行循环以更新每个组合框单元格。我不知道为什么这里不使用
datagridviewcomboxcolumn

private void checkData(string s)            // check wether s in the list, add it if not, keep things sorted
{
  if (data.Contains(s))
    return;
  data.Add(s);
  data.Sort();
  // now because each cell is independent... we have to update each data source! 
  UpdateCombos();
}

private void UpdateCombos() {
  foreach (DataGridViewRow row in theGrid.Rows) {
    if ((!row.IsNewRow) && (row.Cells[0].Value != null)) {
      string currentValue = row.Cells[0].Value.ToString();
      DataGridViewComboBoxCell c = new DataGridViewComboBoxCell();
      c.Value = currentValue;
      c.DataSource = data;
      row.Cells[0] = c;
    }
  }
}
使用发布的代码,对
UpdateCombos
的调用被添加到
checkData
方法中。此方法按预期遍历网格中的所有行,并用更新的数据替换每个组合框。我不反对替换数据源是谨慎的,但是我会使用组合框列,下面的代码就是这样做的。通过此更改,不需要
updatembos
,只需更新组合框列即可

由于数据源经常更新,因此会显示
DataGridViewComboBoxColumn

private List<string> comboData;
private DataGridViewComboBoxColumn comboColumn;

private void Form2_Load(object sender, EventArgs e) {
  comboData = new List<string>();
  comboData.Add("Foo");
  comboData.Add("Bar");
  comboColumn = new DataGridViewComboBoxColumn();
  comboColumn.DataSource = comboData;
  theGrid2.Columns.Add(comboColumn);
  theGrid2.RowCount = 3;
}

private void checkData2(string s) { 
  if (!comboData.Contains(s)) {
    comboData.Add(s);
    comboData.Sort();
    comboColumn.DataSource = null;
    comboColumn.DataSource = comboData;
  }
}
私有列表数据;
私有DataGridViewComboBoxColumn comboColumn;
私有void Form2_加载(对象发送方、事件参数e){
comboData=新列表();
comboData.Add(“Foo”);
组合数据。添加(“条”);
comboColumn=新的DataGridViewComboBoxColumn();
comboColumn.DataSource=comboData;
grid2.Columns.Add(comboColumn);
网格2.RowCount=3;
}
私有void checkData2(字符串s){
如果(!comboData.Contains)){
comboData.Add(s);
comboData.Sort();
comboColumn.DataSource=null;
comboColumn.DataSource=comboData;
}
}

希望对您有所帮助

非常感谢您的工作,这太棒了!作为一个老的C++程序员,我认为数据源应该是一个引用,所以当我改变原始(“数据”变量)时,这个改变应该传播到它所使用的所有实例。在我看来,这种行为就是使用单一数据源的全部意义。我仍然不明白为什么新元素在视觉上出现,但却不能被使用。这可能是我的问题的核心——为什么显示的列表和用于一致性检查的列表之间存在差异。但是,看来我们不能正确回答这个问题。@Batox……我同意,即使从文档来看,它也“应该”起作用,正如你从我所做的少量研究中所描述的那样。当我有机会的时候,我会做更多的研究。如果我发现我们两人似乎都遗漏了什么,我会更新答案。