我第一次碰到跨线程访问可视化控件的问题是在写串口通讯程序的时候。
我不会再举出那个例子,有点麻烦。我们用下面这个例子,制造这个现象。
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; using System.Threading; namespace WindowsFormsApplication6 { public { public Form1() { InitializeComponent(); } private { ThreadStart ts = new Thread th = new th.Start(); } private { this.label1.Text = “跨线程访问控件了!“; } } } |
在.NET 2.0之前是允许跨线程访问可视化控件的,后续就不允许了,可能是基于界面跨线程访问容易造成混乱的原因吧。比如界面在刷新,突然插入个新的程序要更改界面的数据,容易造成混乱。
最简单的解决办法就是添加一条语句,加粗的那一句。
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; using System.Threading; namespace WindowsFormsApplication6 { public { public Form1() { Control.CheckForIllegalCrossThreadCalls = false; InitializeComponent(); } private { ThreadStart ts = new Thread th = new th.Start(); } private { this.label1.Text = “跨线程访问控件了!“; } } } |
但是官方并不鼓励我们这么做,要不他们也不会费这么大劲了。
窗体是由UI线程创建的,这个UI线程拥有一个消息队列和相应的操作函数,负责接收操作系统发过来的各种消息并做处理,比如鼠标点击,键盘输入等等。
官方提供了相应的法案,把对可视化控件的访问转有UI线程负责。
Control.Invoke 同步方式
Control.BeginInvoke 异步方式
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; using System.Threading; namespace WindowsFormsApplication6 { public { public public Form1() { InitializeComponent(); } private { MyInvoke myIvoke = new label1.Invoke(myIvoke); } private { this.label1.Text = “跨线程访问控件了!“; } } } |
跨线程访问
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; using System.Threading; namespace test { public { public Form1() { InitializeComponent(); } static private { Thread th = new th.Start(“button1”); } void showmsg(Object s) { if(this.textBox1.InvokeRequired) { mydelegate d = show; this.textBox1.Invoke(d,s); } else { show(s.ToString()); } } delegate void show(string s) { this.textBox1.AppendText(s.ToString() + “\r\n”); this.textBox1.AppendText(i.ToString() + “\r\n”); i++; } private { showmsg(“button2”); } } } |