轉(zhuǎn)帖|其它|編輯:郝浩|2011-05-03 14:49:24.000|閱讀 884 次
概述:本文主要介紹在WinForm/Silverlight多線程編程中如何更新UI控件的值,希望對(duì)大家有幫助。
# 界面/圖表報(bào)表/文檔/IDE等千款熱門軟控件火熱銷售中 >>
單線程的winfom程序中,設(shè)置一個(gè)控件的值是很easy的事情,直接 this.TextBox1.value = "Hello World!";就搞定了,但是如果在一個(gè)新線程中這么做,比如:
private void btnSet_Click(object sender, EventArgs e)
{
Thread t = new Thread(new ParameterizedThreadStart(SetTextBoxValue));
//當(dāng)然也可以用匿名委托寫成Thread t = new Thread(SetTextBoxValue);
t.Start( "Hello World");
}
void SetTextBoxValue(object obj)
{
this.textBox1.Text = obj.ToString();
}
運(yùn)行時(shí),會(huì)報(bào)出一個(gè)無情的錯(cuò)誤:
線程間操作無效: 從不是創(chuàng)建控件“textBox1”的線程訪問它。
究其原因,winform中的UI控件不是線程安全的,如果可以隨意在任何線程中改變其值,你創(chuàng)建一個(gè)線程,我創(chuàng)建一個(gè)線程,大家都來搶著更改"TextBox1"的值,沒有任何秩序的話,天下大亂...
解決辦法:
1.掩耳盜鈴法(Control.CheckForIllegalCrossThreadCalls = false;)--僅Winform有效
using System;
using System.Threading;
using System.Windows.Forms;
namespace ThreadTest
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
Control.CheckForIllegalCrossThreadCalls = false;//這一行是關(guān)鍵
}
private void btnSet_Click(object sender, EventArgs e)
{
Thread t = new Thread(new ParameterizedThreadStart(SetTextBoxValue));
t.Start( "Hello World");
}
void SetTextBoxValue(object obj)
{
this.textBox1.Text = obj.ToString();
}
}
}
設(shè)置Control.CheckForIllegalCrossThreadCalls為false,相當(dāng)于不檢測(cè)線程之間的沖突,允許各路線程隨便亂搞,當(dāng)然最終TextBox1的值到底是啥難以預(yù)料,只有天知道,不過這也是最省力的辦法
2.利用委托調(diào)用--最常見的辦法(僅WinForm有效)
using System;
using System.Threading;
using System.Windows.Forms;
namespace ThreadTest
{
public partial class Form1 : Form
{
delegate void D(object obj);
public Form1()
{
InitializeComponent();
}
private void btnSet_Click(object sender, EventArgs e)
{
Thread t = new Thread(new ParameterizedThreadStart(SetTextBoxValue));
t.Start( "Hello World");
}
void SetTextBoxValue(object obj)
{
if (textBox1.InvokeRequired)
{
D d = new D(DelegateSetValue);
textBox1.Invoke(d,obj);
}
else
{
this.textBox1.Text = obj.ToString();
}
}
void DelegateSetValue(object obj)
{
this.textBox1.Text = obj.ToString();
}
}
}
3.利用SynchronizationContext上下文 -- 最神秘的方法(Winform/Silverlight能用)
之所以說它神秘,是因?yàn)閙sdn官方對(duì)它的解釋據(jù)說也是不清不楚
using System;
using System.Threading;
using System.Windows.Forms;
namespace ThreadTest
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void btnSet_Click(object sender, EventArgs e)
{
Thread t = new Thread(new ParameterizedThreadStart(Run));
MyPram _p = new MyPram() { context = SynchronizationContext.Current, parm = "Hello World" };
t.Start(_p);
}
void Run(object obj)
{
MyPram p = obj as MyPram;
p.context.Post(SetTextValue, p.parm);
}
void SetTextValue(object obj)
{
this.textBox1.Text = obj.ToString();
}
}
public class MyPram
{
public SynchronizationContext context { set; get; }
public object parm { set; get; }
}
}
4.利用BackgroundWorker --最偷懶的辦法(Winform/Silverlight通用)
BackgroundWorker會(huì)在主線程之外,另開一個(gè)后臺(tái)線程,我們可以把一些處理放在后臺(tái)線程中處理,完成之后,后臺(tái)線程會(huì)把結(jié)果傳遞給主線程,同時(shí)結(jié)束自己。
using System;
using System.ComponentModel;
using System.Windows.Forms;
namespace ThreadTest
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void btnSet_Click(object sender, EventArgs e)
{
//MessageBox.Show(Thread.CurrentThread.ManagedThreadId.ToString());
using (BackgroundWorker bw = new BackgroundWorker())
{
bw.RunWorkerCompleted +=
new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
bw.DoWork += new DoWorkEventHandler(bw_DoWork);
bw.RunWorkerAsync( "Hello World");
}
}
void bw_DoWork(object sender, DoWorkEventArgs e)
{
//MessageBox.Show(Thread.CurrentThread.ManagedThreadId.ToString());
e.Result = e.Argument;//這里只是簡(jiǎn)單的把參數(shù)當(dāng)做結(jié)果返回,當(dāng)然您也可以在這里做復(fù)雜的處理后,再返回自己想要的結(jié)果(這里的操作是在另一個(gè)線程上完成的)
}
void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
//這時(shí)后臺(tái)線程已經(jīng)完成,并返回了主線程,所以可以直接使用UI控件了
this.textBox1.Text = e.Result.ToString();
//MessageBox.Show(Thread.CurrentThread.ManagedThreadId.ToString());
}
}
}
5.Dispatcher.BeginInvoke--Silverlight的獨(dú)門秘籍
代碼
using System.Threading;
using System.Windows.Controls;
using System.Windows.Input;
namespace ThreadTest
{
public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();
}
private void LayoutRoot_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
Thread t = new Thread(SetTextValue);
t.Start( "Hello World");
}
void SetTextValue(object text)
{
this.Dispatcher.BeginInvoke(() = > { this.txt.Text = text.ToString(); });
}
}
}
本站文章除注明轉(zhuǎn)載外,均為本站原創(chuàng)或翻譯。歡迎任何形式的轉(zhuǎn)載,但請(qǐng)務(wù)必注明出處、不得修改原文相關(guān)鏈接,如果存在內(nèi)容上的異議請(qǐng)郵件反饋至chenjj@ke049m.cn
文章轉(zhuǎn)載自:博客園