C# 访问数据网格时的跨线程通信
我正在尝试显示datagridview,然后动态填充这些行。如果我在UI线程上填充,datagrid将冻结,直到加载所有数据,然后显示datagrid。因此,我创建了另一个线程,Iam在其中向datagrid添加数据。但它向我展示了错误。跨线程通信 我的代码如下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
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+“:”+
,但最后一行是不完整的。如果您需要更多关于如何转换这些的帮助,我将在下一次机会查看此问题,如果您提出更多问题,其他人也会回答您的问题。