【问题标题】:updating datagridview from within a thread causes error c# winform从线程内更新datagridview会导致错误c#winform
【发布时间】:2013-10-13 08:23:15
【问题描述】:

我正在编写一个使用 datagridview 对象的 C# winform。在程序的某个时刻,我需要从线程内更新所述数据网格视图。这会导致程序抛出未处理的异常,指出对象引用未设置为对象的实例,并使 datagridview 变成带有红色 X 的白框的错误图像。

在这种情况下,我具体要做的是更新行中的值,方法是删除行并更新统计值并重新插入行。

我在线程调用的单独函数中执行此操作,它每次都会更新 datagridview 中的两行。

这是我的更新功能的代码:

private void updateStats(int binNumber)
    {
        binNumber *= 2;//has to multiply by 2 because every bin has two rows in this table
        if (statsData.Rows.Count >= (binNumber + 1))
        {
            statsData.Rows.RemoveAt(binNumber);
            //number does not change because the index was just decreased by one
            statsData.Rows.RemoveAt(binNumber);//because every bin requires two rows
        }
        Bin bin = bins[binNumber / 2];
        List<double> realETempData = new List<double>();
        List<double> imagETempData = new List<double>();
        List<double> realAlphaTempData = new List<double>();
        List<double> imagAlphaTempData = new List<double>();
        //updates average and std dev values
        foreach (MinSearchData dataPoint in bin.binData)
        {
            realETempData.Add(dataPoint.RealE);
            imagETempData.Add(dataPoint.ImagE);
            realAlphaTempData.Add(dataPoint.RealAlpha);
            imagAlphaTempData.Add(dataPoint.ImagAlpha);
        }
        bin.AverageRealE = realETempData.Average();
        bin.AverageImagE = imagETempData.Average();
        bin.StdDevRealE = calculateStandardDeviation(realETempData);
        bin.StdDevImagE = calculateStandardDeviation(imagETempData);
        bin.AverageRealAlpha = realAlphaTempData.Average();
        bin.AverageImagAlpha = imagAlphaTempData.Average();
        bin.StdDevRealAlpha = calculateStandardDeviation(realAlphaTempData);
        bin.StdDevImagAlpha = calculateStandardDeviation(imagAlphaTempData);
        realETempData.Clear();
        imagETempData.Clear();
        realAlphaTempData.Clear();
        imagAlphaTempData.Clear();
        DataRow myRow = statsData.NewRow();

        myRow[0] = bin.BinName;
        myRow[1] = "Real";
        myRow[2] = bin.AverageRealAlpha;
        myRow[3] = bin.StdDevRealAlpha;
        myRow[4] = bin.AverageRealE;
        myRow[5] = bin.StdDevRealE;
        statsData.Rows.InsertAt(myRow, binNumber);

        DataRow myRow2 = statsData.NewRow();
        myRow2[0] = "";
        myRow2[1] = "Imaginary";
        myRow2[2] = bin.AverageImagAlpha;
        myRow2[3] = bin.StdDevImagAlpha;
        myRow2[4] = bin.AverageImagE;
        myRow2[5] = bin.StdDevImagE;
        statsData.Rows.InsertAt(myRow2, binNumber + 1);
    }

其中奇怪的部分是我似乎无法捕获异常,并且它的发生不一致,因为有时它在第一次尝试更新时失败,而其他时候它在第一次尝试时失败。

任何帮助将不胜感激,

谢谢,

-杰克

【问题讨论】:

    标签: c# multithreading winforms datagridview


    【解决方案1】:

    这可能是由于race 问题引起的。换句话说,一个线程(可能是主线程)尝试根据其当前的行列表绘制网格,而另一个线程推断和操作它。此外,我猜你已经关闭了CheckForIllegalCrossThreadCalls 以便能够直接通过线程操作网格。如果是,这就是问题的主要原因。无论如何,可能的解决方案是使用BeginInvoke 来间接使用控件:

    private void updateStats(int binNumber)
    {
      datagridview1.BeginInvoke(new MethodInvoker(() =>
      {
            binNumber *= 2;//has to multiply by 2 because every bin has two rows in this table
            if (statsData.Rows.Count >= (binNumber + 1))
              ....
              ....
              ....        
            myRow2[5] = bin.StdDevImagE;
            statsData.Rows.InsertAt(myRow2, binNumber + 1);
       }
    }
    

    编辑:

    我认为statsDataDataGridView。根据 OP 的评论,它是 DataTable。因此,我调整了答案以反映这一事实。

    【讨论】:

    • statData 是一个 dataTable 对象,没有 BeginInvoke 方法。你认为我应该对使用 statData 作为其绑定数据的 datagridview 对象本身进行尝试吗?
    • 我使用了我正在使用的datagridviews的调用程序,并且只是围绕这个函数调用进行了调用以使其更简单,并且它起作用了!谢谢,我认为这与同时编写线程有关,但我没有意识到我可以用这个来解决它。我在应用程序的其他部分使用了调用,但我从未想过以这种方式尝试它。再次感谢!
    • @JakeGearhart 感谢您的澄清。我刚刚更新了答案以反映您所强调的内容。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-02
    • 2020-05-08
    • 1970-01-01
    相关资源
    最近更新 更多