前言
先说明一下,本人不太做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(); }
下面是运行的效果图: