philzhou

导航

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

在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 void  UpdateProgressDelegate(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!");
        }
    }

 

其中 this.InvokeRequired 是Control的一个属性,它会去比较当前线程是否是winform主线程,是返回false,不需要invoke,可以直接操作control,不是则需要调用this.BeginInvoke(Delegate,parms object[] args)将更新control的操作转到winform主线程中进行。

[SRDescription("ControlInvokeRequiredDescr")]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    [Browsable(false)]
    [EditorBrowsable(EditorBrowsableState.Advanced)]
    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();
        }
      }
    }

posted on 2012-06-09 12:05  philzhou  阅读(843)  评论(0编辑  收藏  举报