c# - 访问数据网格时的跨线程通信

标签 c# winforms c#-4.0 c#-3.0

我正在尝试显示 datagridview,然后动态填充行。如果我在 UI 线程上填充,数据网格将卡住,直到加载所有数据,然后显示数据网格。因此,我创建了另一个线程,将数据添加到数据网格中。但它向我显示错误。跨线程通信。

我的代码如下。

private void btnStartTest_Click(object sender, EventArgs e)
    {
        tbCtrl.Visible = true;
        viewData.Show();
        viewData.ScrollBars = ScrollBars.None;
        //tbCtrl.Size = MaximumSize;
        Thread thr = new Thread(LoadData);
        thr.Start();
    }

   public void LoadData()
    {

        for (int i = 0; i < 20; i++)
        {
            int firstDisplayed = viewData.FirstDisplayedScrollingRowIndex;
            int displayed = viewData.DisplayedRowCount(true);
            int lastVisible = (firstDisplayed + displayed) - 1;
            int lastIndex = viewData.RowCount - 1;
            viewData.Rows.Add();
            if (lastVisible == lastIndex)
            {
                viewData.FirstDisplayedScrollingRowIndex = firstDisplayed + 1;
            }
            viewData.Rows[i].Cells[0].Value = System.DateTime.Now.Hour + ":" + 

            for (int j = 1; j < 7; j++)
            {
                viewData.Rows[i].Cells[j].Value = (i + j).ToString();
            }

            Thread.Sleep(1000);

        }
    }

请告诉我如何在不挂起 UI 的情况下实现这一目标。我没有从数据库中提取数据。无需进行任何计算。

最佳答案

您可以在工作线程内访问 viewData,但并非没有可能(且不确定)的问题。简而言之:这样做并不安全。我知道的最简单的方法是创建一个新的公共(public)静态类,例如这个(类的名称并不重要,实际上可以是您想要的任何名称,因为它仅用于扩展方法),然后将这两个方法放入该类中如下:

static partial class MyExtensions
{
    public static TResult SafeInvoke<T, TResult>(this T isi, Func<T, TResult> callFunction) where T : ISynchronizeInvoke
    {
        if (isi.InvokeRequired)
        {
            IAsyncResult result = isi.BeginInvoke(callFunction, new object[] { isi });
            object endResult = isi.EndInvoke(result); return (TResult)endResult;
        }
        else
            return callFunction(isi);
    }

    /// <summary>
    /// This can be used in C# with:
    /// txtMyTextBox.SafeInvoke(d => d.Text = "This is my new Text value.");
    /// or:
    /// txtMyTextBox.SafeInvoke(d => d.Text = myTextStringVariable);
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="isi"></param>
    /// <param name="callFunction"></param>
    public static void SafeInvoke<T>(this T isi, Action<T> callFunction) where T : ISynchronizeInvoke
    {
        if (isi.InvokeRequired) isi.BeginInvoke(callFunction, new object[] { isi });
        else
            callFunction(isi);
    }
} // static class MyExtensions

然后每次您在 LoadData() 方法中访问 viewData 变量时,您都需要使用这些方法来访问它。这些方法以“安全”的方式调用这些方法。因此 viewData.Rows.Add(); 将替换为 viewData.SafeInvoke(d => d.Rows.Add());

要了解发生了什么,您可以阅读扩展方法和 lambda 表达式。但这是我见过的最干净的方法。我见过很多其他方法,但大多数都复杂两倍以上。我几年前复制了这段代码,因为这并不是一个罕见的问题。快乐编码! :)

关于c# - 访问数据网格时的跨线程通信,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20062869/

相关文章:

c# - 收据打印的中心文本

wpf - MVVM 中的事件绑定(bind)

c# - c# - 如何在任何有异常的情况下向线程发出停止信号

c# - 反序列化来自 firebase 的响应

c# - 使用列表项内容作为字符串名称

C# GetFunctionPointerForDelegate cdecl 而不是 stdcall

c# - 改变枚举的数量是一个重大变化吗?

c# - 如何从 C# 中的 WinForm.Opacity 中排除控件

c# - 如何将我自己的主题应用到我的 Windows 窗体应用程序中?

asp.net - 查询中的 Linq 子查询