之前用C++的时候,后台线程与UI之间基本都是发送消息,用SendMessage或者PostMessage来实现的,用PostMessage最多,因为SendMessage要等到消息处理完才返回,而PostMessage将消息发送到窗口消息队列之后就立即返回了。
C#如也采用这种方式,则要通过以下声明方式进行引入:[DllImport("user32.dll", EntryPoint = "SendMessage")]等来引入此两个函数,我们看一下函数参数:SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam),PostMessage和SendMessage函数在参数上一样,hWnd-窗口句柄(Form.Handle),Msg-消息ID,wParam--消息参数1, LParam--消息参数2。重点就在后面两个参数上,都是int类型的,如果只是传整数,这两个方法都没有问题,但更多情况下都是传递比较复杂的数据,因为C#没有明确的指针,传递对象数据的时候需要传递引用类型的,而引用类型都是new出来的,C#在调用PostMessage时,还没等处理就将对象销毁了,这个函数用不成,用SendMessage也要将数据封装到struct内才可以,用class也是不行的。
简单来说,对于C#通过SendMessage和PostMessage来进行线程和窗口间的通信时,只能采用SendMessage发送Struct结构数据的方式,但这个方法不是立刻返回的,也能用,不理想。而且用这两个方法的时候还要采用DllImport进行外部引入。C#有没有自带的方法来进行线程和窗口间的通讯呢,答案是有的,而且不仅可以进行线程和窗口间的通信,也可以进行线程间的通讯。具体是采用 SynchronizationContext 异步上下文的方式,其他还有什么 事件处理,异步委托调用 等的方法,我觉得原理都差不多,可以自行百度一下。
以下示例是:后台线程每隔1秒钟,发送一个字符串到前台,用SynchronizationContext 异步上下文的方式.
前台Form
1 public partial class Form1 : Form 2 { 3 public Form1() 4 { 5 InitializeComponent(); 6 } 7 8 //线程调用函数 9 void ThreadCallBack(object str) 10 { 11 label1.Text = (string)str; 12 } 13 14 private void Form1_Load(object sender, EventArgs e) 15 { 16 CMyThread myThread = new CMyThread(WindowsFormsSynchronizationContext.Current, ThreadCallBack); 17 myThread.StartThread(); 18 } 19 }
后台线程 CMyThread.cs
1 class CMyThread 2 { 3 System.Action<string> _callback; 4 SynchronizationContext _parentContext; 5 6 public CMyThread(SynchronizationContext context, System.Action<string> callback) 7 { 8 _parentContext = context; 9 _callback = callback; 10 } 11 12 void Work() 13 { 14 int index = 0; 15 while(true) 16 { 17 string sInfo = index++.ToString(); 18 _parentContext.Post(new SendOrPostCallback((o)=> { _callback(sInfo); }), null); //重点是这个地方。之前里面的参数怎么都没填明白,后来查半天,找到了一个方法。这个函数参数可能也有别的写法。 19 Thread.Sleep(1000); 20 } 21 } 22 23 public void StartThread() 24 { 25 Thread myThread = new Thread(Work); 26 myThread.IsBackground = true; 27 myThread.Start(); 28 } 29 30 }