现在的位置: 首页 > 综合 > 正文

在DataGridView中的CellEndEdit事件中删除当前行报错

2012年07月17日 ⁄ 综合 ⁄ 共 1329字 ⁄ 字号 评论关闭

写在前面,老婆问我一个UI的问题。我开始以为很简单,后来弄了一下,发觉挺难。找了不少资料才解决。在这个过程中学到不少东西,记录下来,以便以后复习。

 

症状

===========

在DataGridView中的CellEndEdit事件中删除当前行报错,信息如下:

Operation is not valid because it results in a reentrant call to the SetCurrentCellAddressCore function

 

分析

===========

想要在一个控件的事件中删除掉控件本身,这个恐怕就是问题的根本原因了。我的第一感觉还是挺准的,可惜技术基础不扎实,没能贯彻下去。我最开始想:如果在这个事件处理函数中做不到,那老子再起一个线程,活生生等你这个事件执行结束了之后,再回来把你干掉总可以了吧。谁知又遇到了非创建控件的线程访问控件报exception的问题。

已经是半夜十二点多了,头已经有点昏了。没关系,脑子不好使,有google。

 

找到了如下的经典解决方案。

 

//事件处理函数
//不直接删掉该行,而是将要删掉的行存入数组,待另起的线程处理
private void m_dataGridView_CellEndEdit(object sender, DataGridViewCellEventArgs e)
{
    PushDelIndex(e.RowIndex);
    Thread delTh = new Thread(new ThreadStart(delRowThread));
    delTh.Start();
}


private int[] delIndex = null;//待删行号的数组
private bool delFlag = true;//是否要不间断尝试删除数组中的行
private bool deling = false;//是否有线程正在执行删除操作的锁变量

private void PushDelIndex(int _index)
{
    if(delIndex==null)
    {
        delIndex=new int[]{_index};
    }
    else
    {
        Array.Resize(ref delIndex,delIndex.Length+1);//展示如何扩充数组
        delIndex[delIndex.Length - 1] = _index;
    }
}

void delRowThread()
{
    while (delFlag)
    {
        if (delIndex != null)
        {
            if (deling == false)
            {
                delRow();
            }
        }
        Thread.Sleep(100);
    }
}

//此处展现了如何在非创建控件的线程里去修改控件的方法
private delegate void delRowCallBack();
void delRow()
{
    if (PlayList.InvokeRequired)
    {
        deling = true;
        delRowCallBack o = new delRowCallBack(delRow);
        this.Invoke(o);
    }
    else
    {
        for (int i = 0; i < delIndex.Length; i++)
        {
            PlayList.Rows.RemoveAt(delIndex[i]);
        }
        deling = false;
        delIndex = null;
    }
}
}

抱歉!评论已关闭.