前言
先說明一下,本人不太做winform的項目,工作10年以來,一直奮斗在webform的舞台上,今天有機會也接觸了一下winform,下面對工作中用到的BeginInvoke方法作一下說明,和大家也一起學習一下,呵呵。
BeginInvoke產生的原因
首先一個winform程序運行后,會有一個主線程(UI),我們看到的頁面上的元素,表單,列表框等等都運行在主線程上的,主線程一阻塞,這些東西就都點不了了,呵呵,所以,在我們運行一些耗時的功能時,通常會開啟一個新的線程去干這事,這是和乎情理的,想像一下,當我們在新線程里工作時,主線程不被阻塞(不假死),用戶體驗是多么好呀,當在新線程里干完事后,把消息返回給主線程,就OK了!
美中不足
想的挺好,可惜在新線程里,干完事后,運行程序,在為主窗體元素賦值時,出錯了,說是不能訪問主線程的元素,這到是正常的,線程與線程本來就是獨立的,所以只能找其它方法了(可以使用這個方法解決上面的問題,但不推薦: Control.CheckForIllegalCrossThreadCalls = false;)
BeginInvoke出來了
微軟為了解決上面的線程之間信息相互訪問的問題,封裝了BeginInvoke方法,它允許我們傳入一個委托,在委托方法中干這件時,這時你的主線程元素是可以被訪問的,當處理完成后,可以操縱主線程的元素,即主線程元素重新賦值。
下面是一個簡單的例子:
/// <summary> /// 批量添加 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void button1_Click(object sender, EventArgs e) { message.Text = "程序正在處理..."; var beginInvokeThread = new Thread(() => { var result = userBll.GeneratorUserData(dateTimePicker1.Value);//耗時工作 #region BeginInvoke Func<ReturnMsg, string> funDelegate = new Func<ReturnMsg, string>(InvodeGeneratorUserData); IAsyncResult aResult = this.BeginInvoke(funDelegate, result); aResult.AsyncWaitHandle.WaitOne(-1); if (aResult.IsCompleted)//這里不可以訪問主線程的信息 MessageBox.Show(this.EndInvoke(aResult).ToString()); #endregion }); beginInvokeThread.Start(); }
委托方法如下:
/// <summary> /// 一個委托,把消息返回並填充到主窗體(主線程)的頁面元素上 /// </summary> /// <param name="month"></param> /// <returns></returns> private string InvodeGeneratorUserData(ReturnMsg res) { this.message.Text = res.GetDescription();//這里可以訪問主線程的信息 return res.GetDescription(); }
下面是運行的效果圖: