philzhou 发表于 2012-12-18 18:58:24

winform应用程序:非控件创建线程无法操作控件

winform应用程序:非控件创建线程无法操作控件

<div id="cnblogs_post_body">在winform中常常会有耗时的操作,需要有进度条来与用户进行交互,告诉用户当前操作的进度状况。
在这种情况下,为避免耗时操作阻塞UI主线程,会为操作单独开一个工作线程。但是当工作线程去更新Form上的ProgressBar的进度时,异常抛出了:线程间操作无效: 从不是创建控件“progressBarUpdate”的线程访问它。
这是因为progressBarUpdate这个控件是由UI主线程创建并维护的,而工作线程直接去操作UI线程创建的控件显然是不被允许的,但是工作线程确实需要通知progressBarUpdate去更新状态,如何解决这个问题呢?
我们可以使用Control 中的方法public IAsyncResult BeginInvoke(Delegate method, params object[] args) 来优雅的解决。
public partial class frmProduct : Form    {      public frmProduct()      {            InitializeComponent();      }      public delegate void WorkDelegate();      private void button1_Click(object sender, EventArgs e)      {            var workThread = new Thread(new ThreadStart(DoSomeLongTermWork));            workThread.Start();      }      private void DoSomeLongTermWork()      {            for (int i = 0; i <= 100; i++)            {                Thread.Sleep(100);                UpdateProgressStatus(i);            }      }      public delegate voidUpdateProgressDelegate(int progress);      public void UpdateProgressStatus(int progress)      {            if(this.InvokeRequired)            {                this.BeginInvoke(new UpdateProgressDelegate(UpdateProgressStatus),progress);                return;            }            progressBarUpdate.Value = progress;      }      private void button2_Click(object sender, EventArgs e)      {            MessageBox.Show("the main ui thread is blocked!");      }    }.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }
其中 this.InvokeRequired 是Control的一个属性,它会去比较当前线程是否是winform主线程,是返回false,不需要invoke,可以直接操作control,不是则需要调用this.BeginInvoke(Delegate,parms object[] args)将更新control的操作转到winform主线程中进行。
                public bool InvokeRequired    {      get      {      using (new Control.MultithreadSafeCallScope())      {          HandleRef hWnd;          if (this.IsHandleCreated)          {            hWnd = new HandleRef((object) this, this.Handle);          }          else          {            Control marshalingControl = this.FindMarshalingControl();            if (!marshalingControl.IsHandleCreated)            return false;            hWnd = new HandleRef((object) marshalingControl, marshalingControl.Handle);          }          int lpdwProcessId;          return System.Windows.Forms.SafeNativeMethods.GetWindowThreadProcessId(hWnd, out lpdwProcessId) != System.Windows.Forms.SafeNativeMethods.GetCurrentThreadId();      }      }    }.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }
页: [1]
查看完整版本: winform应用程序:非控件创建线程无法操作控件