欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

C#实现窗体与子线程的交互的方法

程序员文章站 2024-02-19 22:21:04
本文实例简述了c#实现窗体与子线程间通讯的方法,对于c#初学者有一定的借鉴价值。具体方法如下: 一般来说窗体上的ui在默认情况下不允许使用子线程(或者其它非创建控件的ui...

本文实例简述了c#实现窗体与子线程间通讯的方法,对于c#初学者有一定的借鉴价值。具体方法如下:

一般来说窗体上的ui在默认情况下不允许使用子线程(或者其它非创建控件的ui线程)去控制(这在net2.0以下是允许的,但是考虑到安全性等问题,从2.0开始就禁止使用这个功能,除非form的checkforillegalcrossthreadcalls=true,不推荐这样使用)。

那么如何实现c#窗体与子线程的交互呢?具体方法如下:

一、使用invoke或者begininvoke方法:

用一个线程,里边调用invoke或者begininvoke方法即可:

public partial class form1 : form
{
public void processing(int num)
{
int answer = 2;
task t = new task(() =>
{
for (int i = 3; i <= num; i++)
{
answer *= i;
}
this.begininvoke(new methodinvoker(() => { thread.sleep(3000); messagebox.show("finished!") }));
messagebox.show("ok");
});
t.start();
}
public form1()
{
initializecomponent();

}
private void button1_click(object sender, eventargs e)
{
messagebox.show("first!");
processing(10);
}
}

这里值得注意:
1)begininvoke:这里的“异步”并不是针对ui线程,而是说当control的begininvoke在某个子线程中调用时,子线程中begininvoke后面的代码(弹出“finished”框框)会先执行,然后等到begininvoke中的那个委托方法完全执行完毕之后label才会被赋值。如果改成invoke,那么“ok”永远在invoke的委托代码彻底执行完毕之后才被执行。
所以begininvoke=invoke(在ui主线程中,所以不建议在主线程中直接这样调用)

二、线程同步synchronizedcontext:

public partial class form1 : form
{
public void processing(int num,synchronizationcontext context)
{
int answer = 2;
task t = new task(() =>
{
for (int i = 3; i <= num; i++)
{
answer *= i;
}
synchronizationcontext.setsynchronizationcontext(context);
synchronizationcontext.current.post((obj) => { thread.sleep(3000); messagebox.show("finished"); }, null);
messagebox.show("last");
});
t.start();
}
public form1()
{
initializecomponent();

}
private void button1_click(object sender, eventargs e)
{
messagebox.show("first!");
processing(10,synchronizationcontext.current);
}
}

和begininvoke、invoke类似,需要注意:

1)synchronizationcontext:唯独在ui窗体线程中会自动初始化(button1_click事件中synchronizationcontext.current为当前窗体),其它线程与线程要交互,必须通过new synchronizationcontext()实现)。
2)post方法等同于begininvoke作用,send等同于invoke作用。

大家如果仔细实验代码,还会发现无论何种情况,弹出“finished”框框总是界面“假死”3秒,是的,证明了以上4个方法都是在ui线程上执行的(只不过是同步或者异步向窗体消息泵发送信息而已)。所以应该“一次性地把数据在子线程中先全部处理干净(在invoke,begininvoke,send或者post前得出结果,写代码),然后一次性发送通知给窗体,更新界面即可)。

此外还需要注意:

任何委托(delegate)也有begininvoke方法,它是真正的异步,一旦invoke一定是开辟一个线程去执行的。