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

C# 访问数据网格时的跨线程通信,c#,winforms,c#-4.0,c#-3.0,C#,Winforms,C# 4.0,C# 3.0,我正在尝试显示datagridview,然后动态填充这些行。如果我在UI线程上填充,datagrid将冻结,直到加载所有数据,然后显示datagrid。因此,我创建了另一个线程,Iam在其中向datagrid添加数据。但它向我展示了错误。跨线程通信 我的代码如下 private void btnStartTest_Click(object sender, EventArgs e) { tbCtrl.Visible = true; viewData.Show

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

我的代码如下

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);

        }
    }
private void btnStartTest_单击(对象发送方,事件参数e)
{
tbCtrl.Visible=true;
view data.Show();
viewData.ScrollBars=滚动条.None;
//tbCtrl.Size=最大尺寸;
线程thr=新线程(加载数据);
thr.Start();
}
公共void LoadData()
{
对于(int i=0;i<20;i++)
{
int firstDisplayed=viewData.FirstDisplayedScrollingRowIndex;
int DISPLATED=viewData.DisplayedRowCount(真);
int lastVisible=(firstDisplayed+displayed)-1;
int lastIndex=viewData.RowCount-1;
viewData.Rows.Add();
if(lastVisible==lastIndex)
{
viewData.FirstDisplayedScrollingRowIndex=firstDisplayed+1;
}
viewData.Rows[i]。单元格[0]。值=System.DateTime.Now.Hour+“:”+
对于(int j=1;j<7;j++)
{
viewData.Rows[i].Cells[j].Value=(i+j).ToString();
}
睡眠(1000);
}
}

请告诉我如何在不挂UI的情况下实现这一点。我不是从数据库中提取数据。没有要做的计算

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

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
静态部分类MyExtensions
{
公共静态TResult SafeInvoke(此T isi,Func callFunction),其中T:ISynchronizeInvoke
{
如果(isi.invokererequired)
{
IAsyncResult result=isi.BeginInvoke(调用函数,新对象[]{isi});
object endResult=isi.EndInvoke(result);return(TResult)endResult;
}
其他的
返回调用函数(isi);
}
/// 
///这可以在C#中使用,包括:
///SafeInvoke(d=>d.Text=“这是我的新文本值。”);
///或:
///安全调用(d=>d.Text=myTextStringVariable);
/// 
/// 
/// 
/// 
公共静态void SafeInvoke(此T isi,Action callFunction),其中T:ISynchronizeInvoke
{
if(isi.invokererequired)isi.BeginInvoke(callFunction,新对象[]{isi});
其他的
调用函数(isi);
}
}//静态类MyExtensions
然后,每次访问LoadData()方法中的
viewData
变量时,都需要使用这些方法来访问它。这些方法以“安全”的方式调用这些方法。所以
viewData.Rows.Add()将替换为
viewData.SafeInvoke(d=>d.Rows.Add())


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

在多线程环境中使用datagrid很棘手。理想情况下,您应该:

  • 创建后台线程以处理数据并向其引发事件 更新数据网格
  • 仅在UI线程中更新UI控件
  • 可以有多个UI控件一起工作以 实现整体功能(进度条、按钮等)。做 不在不同线程中传递控件引用
  • datagrid将绑定到的数据源不应为 可由任何其他类修改
  • 我在这里发布了一个模板,涵盖了这些问题。。。对我来说很好。。。

    这是初学者经常遇到的问题。你查过类似的问题吗?您将无法访问工作线程内的
    viewData
    。代码的哪一部分导致应用程序冻结?将数据添加到gridview会导致应用程序冻结,直到加载数据为止。我寻找类似的问题,并尝试使用后台线程,但我仍然面临同样的问题。我想在datagridview.viewData.Rows.Add()中显示数据加载;正在导致问题。使用线程安全方法可能不需要只读属性,但可能需要。我不确定。但我确信,实际设置值的属性需要使用线程安全的方法,例如这个安全调用方法(或者我认为更复杂的许多其他方式)。code>需要转换,我相信是:
    viewData.SafeInvoke(d=>d.FirstDisplayedScrollingRowIndex=firstDisplayed+1)(我想)和
    viewData.Rows[i].Cells[j].Value=(i+j).ToString()也需要转换,以及
    viewData.Rows[i].Cells[0].Value=System.DateTime.Now.Hour+“:”+
    ,但最后一行是不完整的。如果您需要更多关于如何转换这些的帮助,我将在下一次机会查看此问题,如果您提出更多问题,其他人也会回答您的问题。