C#跨线程访问

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

C#跨线程访问
在C# 的应⽤程序开发中,我们经常要把UI线程和⼯作线程分开,防⽌界⾯停⽌响应。

同时我们⼜需要在⼯作线程中更新UI界⾯上的控件,
下⾯介绍⼏种常⽤的⽅法
阅读⽬录
1.
2.
3.
4.
5.
6.
线程间操作⽆效
界⾯上有⼀个button和⼀个label, 点击button会启动⼀个线程来更新Label的值
private void button1_Click(object sender, EventArgs e)
{
Thread thread1 = new Thread(new ParameterizedThreadStart(UpdateLabel));
thread1.Start("更新Label");
}
private void UpdateLabel(object str)
{
bel1.Text = str.ToString();
}
运⾏后,程序会报错 "跨线程操作⽆效,从不是创建"label1"的线程访问它"
这是因为.NET禁⽌了跨线程调⽤控件,否则谁都可以操作控件,最后可能造成错误。

下⾯介绍⼏种跨线程调⽤控件的⽅法
第⼀种办法:禁⽌编译器对跨线程访问做检查
这是最简单的办法,相当于不检查线程之间的冲突,允许各个线程随便乱搞,最后Lable1控件的值是什么就难以预料了 (不推荐使⽤这种⽅
法)
public Form1()
{
InitializeComponent();
// 加⼊这⾏
Control.CheckForIllegalCrossThreadCalls = false;
}
第⼆种办法: 使⽤delegate和invoke来从其他线程中调⽤控件
调⽤控件的invoke⽅法,就可以控制控件了,例如
private void button2_Click(object sender, EventArgs e)
{
Thread thread1 = new Thread(new ParameterizedThreadStart(UpdateLabel2));
thread1.Start("更新Label");
}
private void UpdateLabel2(object str)
{
if (label2.InvokeRequired)
{
// 当⼀个控件的InvokeRequired属性值为真时,说明有⼀个创建它以外的线程想访问它
Action<string> actionDelegate = (x) => { bel2.Text = x.ToString(); };
// 或者
// Action<string> actionDelegate = delegate(string txt) { bel2.Text = txt; };
bel2.Invoke(actionDelegate, str);
}
else
{
bel2.Text = str.ToString();
}
}
第三种办法: 使⽤delegate和BeginInvoke来从其他线程中控制控件
只要把上⾯的 bel2.Invoke(actionDelegate, str); 中的 Invoke 改为BeginInvoke⽅法就可以了
Invoke⽅法和BeginInvoke⽅法的区别是
Invoke⽅法是同步的,它会等待⼯作线程完成,
BeginInvoke⽅法是异步的,它会另起⼀个线程去完成⼯作线程
form.Invoke((Action)(() =>
{
form.Text = "数据传送完成,正在写⼊Flash";
}));
第四种办法: 使⽤BackgroundWorker组件(推荐使⽤这个⽅法)
BackgroundWorker是.NET⾥⾯⽤来执⾏多线程任务的控件,它允许编程者在⼀个单独的线程上执⾏⼀些操作。

耗时的操作(如下载和数据库事务)。

⽤法简单
private void button4_Click(object sender, EventArgs e)
{
using (BackgroundWorker bw = new BackgroundWorker())
{
bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
bw.DoWork += new DoWorkEventHandler(bw_DoWork);
bw.RunWorkerAsync("Tank");
}
}
void bw_DoWork(object sender, DoWorkEventArgs e)
{
// 这⾥是后台线程,是在另⼀个线程上完成的
// 这⾥是真正做事的⼯作线程
// 可以在这⾥做⼀些费时的,复杂的操作
Thread.Sleep(5000);
e.Result = e.Argument + "⼯作线程完成";
}
void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) {
//这时后台线程已经完成,并返回了主线程,所以可以直接使⽤UI控件了
bel4.Text = e.Result.ToString();
}。

相关文档
最新文档