如何将DataGridViewComboBoxCell转换为DataGridViewTextBoxCell

时间:2015-03-13 08:50:30

标签: c# datagridview datagridviewcomboboxcell datagridviewtextboxcell

我搜索了很多这个错误很多同样的问题已被问到,但它没有解决我的问题。 我正在

  

操作无效,因为它导致对SetCurrentCellAddressCore函数的可重入调用。

方案是datagridview TextboxColumn CellBeginEdit我使用ComboBoxColumn将其转换为CellValidatee.RowIndex = 2之后我再次将ComboBoxColumn更改为TextboxColumn 。这些代码适用于所有人。但是在确切的行CellBeginEdit中获得所述错误会引发此异常,但其他行的剂量不会显示错误。如果我省略此错误并继续,则e.RowIndex = 2单元格值为空,其他行值为有效。

以下是 if (e.ColumnIndex == 2 && e.RowIndex >= 0) { try { string s = Convert.ToString(_dgvCoarseAggegateTest[e.ColumnIndex, e.RowIndex].Value); string s1 = Convert.ToString(_dgvCoarseAggegateTest[e.ColumnIndex, 0].Value); DataGridViewComboBoxCell c = new DataGridViewComboBoxCell(); string _SizeName = _cGetParrent._mGetParentCellValue(ref _dgvCoarseAggegateTest, e.RowIndex, 1); _mFillSieveSizeGridCombo(_mGetMetalSizeID(_SizeName), ref c); // Here My Combo Will GetValues from SQL and it Returning Value _dgvCoarseAggegateTest[e.ColumnIndex, e.RowIndex] = c; // Heres the error When e.RowIndex == 2 and if e.RowIndex != 2 then no error _dgvCoarseAggegateTest[e.ColumnIndex, e.RowIndex].Value = s; _dgvCoarseAggegateTest[e.ColumnIndex, 0].Value = s1; } catch (Exception ex) { MessageBox.Show(ex.Message); } }

的代码
testTable
1      A
2      B
3      C
4      D
5      E
6      F
7      G
8      H
9      I

如何解决此问题。

更新: 没有行用户将添加新行和选择值,基本的东西是我想显示组合和填充数据库中的值,填充值取决于条件,所以每次新值都会到来,

样本数据

_mFillSieveSizeGridCombo

在第1列中,我添加了一个值为1到9的组合,在Combo.Item.Add(x)中我将id传递给sql server 2008并使用{{1}}方法填充组合。

3 个答案:

答案 0 :(得分:2)

SetCurrentCellAddressCore()内有一个标记,可防止任何重入调用损坏DataGridView的内部值。 Usaully引发了一个事件,其中flag = true并在事件结束时重置。

要解决此问题,您只需在事件中添加BeginInvoke()的包装,即可在事件发生后使用异步运行。

修改

问题可以在EditOnEnter模式下重现,BeginInvoke中事件之外的单元格设置器会导致无限循环

private bool _suppressCellBeginEdit = false;
private void dgv_CellBeginEdit(object sender, DataGridViewCellCancelEventArgs e)
{
    var dgv = sender as DataGridView;
    if (_suppressCellBeginEdit)
        return;

    if (e.ColumnIndex == 2 && e.RowIndex >= 0)
    {
        string s = Convert.ToString(dgv[e.ColumnIndex, e.RowIndex].Value);
        string s1 = Convert.ToString(dgv[e.ColumnIndex, 0].Value);
        DataGridViewComboBoxCell c = new DataGridViewComboBoxCell();

        c.Items.Add(string.Format("x{0}:y{1} {2}", e.RowIndex, e.ColumnIndex, 0));
        c.Items.Add(string.Format("x{0}:y{1} {2}", e.RowIndex, e.ColumnIndex, 1));
        c.Items.Add(string.Format("x{0}:y{1} {2}", e.RowIndex, e.ColumnIndex, 2));

        // special handling
        if (e.RowIndex == e.ColumnIndex)
        {
            this.BeginInvoke(new Action(() =>
            {
                _suppressCellBeginEdit = true;
                this.Invoke(new Action(() => 
                    {
                        c.Value = s;
                        dgv[e.ColumnIndex, e.RowIndex] = c;
                        dgv[e.ColumnIndex, 0].Value = s1;
                    }));
                _suppressCellBeginEdit = false;
            }));
        }
        else
        {
            c.Value = s;
            dgv[e.ColumnIndex, e.RowIndex] = c;
            dgv[e.ColumnIndex, 0].Value = s1;
        }
    }
}

答案 1 :(得分:2)

正如您可以从实现此问题的麻烦中看出来的那样,DataGridView对您试图拉动地垫感到非常不满。它明确禁止在关键时刻更改单元对象。虽然处理事件本身就是一个关键时刻。事件的一般问题,称为 re-entrancy 。你使用@Eric的方法遇到的麻烦表明这确实是一个棘手的问题。

所以想要做的是修改单元格类型或引用。密切关注球,你真正想要做的是修改下拉列表的内容。那不是问题。返回设计器并将列的ColumnType属性更改为DataGridViewComboBoxColumn。并使用CellBeginEdit事件动态更改组合框项集合。一个简单的例子:

    private void _dgvCoarseAggegateTest_CellBeginEdit(object sender, DataGridViewCellCancelEventArgs e) {
        var dgv = (DataGridView)sender;
        if (e.ColumnIndex == 2) {
            var cell = (DataGridViewComboBoxCell)dgv.Rows[e.RowIndex].Cells[e.ColumnIndex];
            cell.Items.Clear();
            // Run your dbase query here to fill cell.Items
            //...
            // We'll just fake it here for demo purposes:
            cell.Items.Add(e.RowIndex.ToString());
            cell.Items.Add((e.RowIndex+1).ToString());
            cell.Items.Add((e.RowIndex+2).ToString());
        }
    }

答案 2 :(得分:1)

以下是解决方法:在CellBeginEdit事件中首先检查ColumnType是否为DataGridViewComboBoxCell。如果不是我们cancel事件,请调用一个更改列类型的函数,然后再次调用该事件:

void switchCellType(object sender, DataGridViewCellCancelEventArgs e)
{
    DataGridViewComboBoxCell c = new DataGridViewComboBoxCell();
    // prepare the cell:
    //..
    // fill the drop down items..
    c.Items.Add("1");  // use
    c.Items.Add("2");  // your 
    c.Items.Add("3");  // code here!
    DGV[e.ColumnIndex, e.RowIndex] = c;  // change the cell
    DGV_CellBeginEdit(sender, e);        // restart the edit with the original parms  
}


private void DGV_CellBeginEdit(object sender, DataGridViewCellCancelEventArgs e)
{

    DataGridViewCell cell = DGV[e.ColumnIndex, e.RowIndex];
    if (!(cell is DataGridViewComboBoxCell))
    {
        e.Cancel = true;
        switchCellType(sender, e);
        return;
    }
    //..

现在您的代码可以继续,显然没有单元格更改。可能你想传入文本值来设置..

注意您必须确保CellEndEdit事件未在其时间之前恢复更改!也许一面旗帜,也许在Tag中会有所帮助。如果您愿意,我可以查看您的CellEndEdit代码,如果有的话......