今天在做一個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))時程式還是會有停止反應的假死狀態的。