03.浅谈在Windows窗口跨线程使用控件遇到“线程间操作无效: 从不是创建控件“textBox1”的线程访问它”异常的处理方法
在使用C#进行跨线程操作窗体控件时会遇到如下图中的异常:
异常起因:
在程序进程中windows框体处于一个独立的线程(下文称:主线程),当一个外部线程操作主线程中的控件或其他内容时,由于系统稳定性的限制不能直接进行跨线程操作的,便会出现以上异常信息。
可以通俗的如下理解:
有A,B两家公司,如果A公司需要使用B公司的专利B1,一般情况下是不能直接免费的使用B1的。如果A公司未经B公司同意使用B1就会引起B公司的反制
解决方法(以WinForm为例):
1):关闭跨线程检查
直接将窗体的CheckForIllegalCrossThreadCalls(跨线程检查)属性设置为false,默认此设置是true
CheckForIllegalCrossThreadCalls = false;
2):使用异步上下文的方式进行跨线程操作(需要引用System.Threading;)
使用步骤:
a.获取窗体的操作线程的同步上下文
SynchronizationContext syncontext = SynchronizationContext.Current;
b.使用 SynchronizationContext 的Post函数进行异步操作
syncontext.Post(_ => {…TODO…}, null);
实例代码:
syncontext.Post(_ => { textBox1.Text = $"当前跨线程检查是否启动:{CheckForIllegalCrossThreadCalls}{Environment.NewLine}使用SynchronizationContext的post方式进行跨线程显示"; }, null);
补充知识->Post和Send的区别:
Post:将跨线程的进行的操作同步到主线程中,相当于 BeginInvoke
Send:将同线程的操作同步到控件中,相当于Invoke
实际使用中要注意区分,否则仍可能会出现跨线程异常
3):使用控件自带的异步方法
使用步骤:
a.根据控件的InvokeRequired属性来判断是否是跨线程对控件的操作(以TextBox控件为例)
bool isCrossThreadCalls= textBox1.InvokeRequired);//是否是跨线程的,true为跨线程
b.使用控件的异步Inovke方法
textBox1.Invoke(new Action(() => { textBox1.Text = $"当前跨线程检查是否启动:{CheckForIllegalCrossThreadCalls}{Environment.NewLine}使用Invoke方式进行跨线程显示"; }));
实例代码:
if (textBox1.InvokeRequired)
textBox1.Invoke(new Action(() => { textBox1.Text = $"当前跨线程检查是否启动:{CheckForIllegalCrossThreadCalls}{Environment.NewLine}使用Invoke方式进行跨线程显示"; }));
补充知识:
如果在主线程中使用控件的In方法会出现如下异常,因此必须要区分主线程操作和跨线程操作:
水平有限,欢迎大家交流指正!!!
实例项目代码