一、简述
C#中不允许跨线程直接访问界面控件,即一个线程中如主线程创建的控件不允许被其他线程例如子线程直接访问,如果直接访问或设置属性则会爆出"调用线程无法访问此对象,因为另一个线程拥有该对象"等类似错误。
在一个线程中设置其他线程所有的控件属性通常有两种方法,一是设置System.Windows.Forms.Control的CheckForIllegalCrossThreadCalls属性值为false,表示不对错误线程的调用进行捕捉,这种方法只对winforms界面框架有效,在WPF中无法设置该属性,只能使用第二种方法。
第二种方法是通过委托来实现控件属性设置,需要通过Invoke 或BeginInvoke来实现,Invoke表示同步,BeginInvoke表示异步,下面列举了在winforms中和WPF两种界面框架中跨线程访问控件的代码示例。
二、Winforms中跨线程访问控件
一般的委托方法示例代码如下:
csharp
delegate void delegateSetText(string str);//定义一个委托
private void SetText(string str)
{
if (InvokeRequired)//判断是否是被其他线程调用
{
delegateSetText delegatesetText01 = new delegateSetText(SetText);
Invoke(delegatesetText01, new object [] {str});
return;
}
textBox01.Text = str;
}
也可以采用匿名代理的方式,示例代码如下:
csharp
delegate void delegateSetText(string str);//定义一个委托
private void SetText(string str)
{
delegateSetText delegatesetText01 = delegate(string str01)
{
textBox01.Text = str01;
}
Invoke(delegatesetText01, new object [] {str});
}
三、WPF中跨线程访问控件
在WPF中跨线程访问控件需要使用Dispatcher。Dispatcher是WPF中的线程调度管理器,用在子线程刷新主线程(UI线程)(比如绑定的时候,属性更新的时候),在子线程里面起一个dispatcher,将工作项目调度到 UI 线程,让主线程调度刷新UI的代码。示例代码如下:
csharp
private void SetText(string str)
{
if (!Dispatcher.CheckAccess())//判断是否是被其他线程调用
{
Dispatcher.Invoke(() => SetText(str));
return;
}
textBox01.Text = str;
}
【注】
避免"在创建窗口句柄之前,不能在控件上调用 Invoke 或 BeginInvoke。"错误。
一个Form窗体必须完全创建完成,才能调用它自身或它上面控件的Invoke或BeginInvoke。
经测试,窗体的构造函数内的InitializeComponent()的执行完成时,窗体并未创建完成;窗体的构造函数执行完成时,窗体也并未创建完成;
在form.show()后,窗体是已经创建完成了。
另外,可以在调用Invoke()前,判断一下 if (form.Created),以避免此处异常中断。
最后
如果你觉得这篇文章对你有帮助,不妨点个赞支持一下!你的支持是我继续分享知识的动力。如果有任何疑问或需要进一步的帮助,欢迎随时留言。
也可以加入微信公众号 [DotNet技术匠] 社区,与其他热爱技术的同行一起交流心得,共同成长!
优秀是一种习惯,欢迎大家留言学习!
作者:CastleWu
出处:cnblogs.com/castlewu/p/17168964.html
声明:网络内容,仅供学习,尊重版权,侵权速删,歉意致谢!