之前用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     }