IMZRH的日志

努力成为一个有用的人

导航

Winform中跨线程更新控件的内容

Posted on 2012-03-29 14:43  张荣华  阅读(1680)  评论(2编辑  收藏  举报

今天在做一个Winform的项目时遇到了一个问题需要跨线程更新GUI,Winform默认是不允许跨线程更新GUI控件的,如果你这样做会报错,所以需要做一下变通,在我的解决方法中借鉴了Updating Your Form from Another Thread without Creating Delegates for Every Type of Update的代码,代码如下:

 // 新建一个放扩展方法的类
public static class ExtensionMethod
{
public static TResult SafeInvoke<T, TResult>(this T isi, Func<T, TResult> call) where T : ISynchronizeInvoke
{
if (isi.InvokeRequired) {
IAsyncResult result = isi.BeginInvoke(call, new object[] { isi });
object endResult = isi.EndInvoke(result); return (TResult)endResult;
}
else
{
return call(isi);
}
}

public static void SafeInvoke<T>(this T isi, Action<T> call) where T : ISynchronizeInvoke
{
if (isi.InvokeRequired)
{
isi.BeginInvoke(call, new object[] { isi });
}
else
{
call(isi);
}
}
}

// 在类里这样应用
private void button1_Click(object sender, EventArgs e)
{

Thread thread = new Thread(new ThreadStart(startCalculation));
thread.Start();
}

private void startCalculation()
{
button1.SafeInvoke(d => d.Enabled = false);

for (double i = 0; i <= 10000000000; i++)
{
string textForLabel = (i) + "%";

lblProcent.SafeInvoke(d => d.Text = textForLabel);
var i1 = i;
progressBar1.SafeInvoke(d => d.Value = 10);
string labelText = lblProcent.SafeInvoke(d => d.Text);

}
this.SafeInvoke(d => d.refreshTree());
button1.SafeInvoke(d => d.Enabled = true);
}

private void refreshTree()
{
Thread.Sleep(10000);
this.treeView1.ExpandAll();
this.treeView1.Nodes[0].Nodes[1].Remove();
}

需要注意的startCalculation方法是在新线程里执行的,但SafeInvoke里调用的方法(如refreshTree)仍是在主线程里执行的,如果你在这些方法里有耗费资源的代码(如这里的Thread.Sleep(10000))时程序还是会有停止反应的假死状态的。