Updating a Progress Bar from Another Thread

后端 未结 3 1564
故里飘歌
故里飘歌 2020-12-18 12:50

I have a windows form on the main thread and another thread that does some calculations. I\'d like to update the status bar on my form from the work being done in the other

3条回答
  •  北荒
    北荒 (楼主)
    2020-12-18 13:10

    You can use the marshaling techniques like Control.Invoke to execute a delegate on the UI thread where UI elements can be safely manipulated, but that approach is not very good. Actually, it is a terrible approach if all you want to do is update simple progress information.

    By far the best method for doing this is:

    • Have your worker thread publish progress information to a shared variable.
    • Have your UI thread poll for it via a System.Windows.Forms.Timers on an interval that works well for you.

    Here is what it might look like.

    public class Example : Form
    {
      private volatile int percentComplete = 0;
    
      private void StartThreadButton_Click(object sender, EventArgs args)
      {
        StatusBarUpdateTimer.Enabled = true;
        new Thread(
          () =>
          {
            for (int i = 1; i <= 100; i++)
            {
              DoSomeWork();
              percentComplete = i;
            }
          }).Start();
      }
    
      private void StatusBarUpdateTimer_Tick(object sender, EventArgs args)
      {
        yourStatusBarPanel.Text = percentComplete.ToString() + "%";
        StatusBarUpdateTimer.Enabled = percentComplete < 100;
      }
    }
    

    This works well because:

    • The percentComplete field is declared 'volatile' ensuring its value can be reliably read from multiple threads.
    • The UI thread gets to dictate when and how often the UI gets updated...the way it should be!
    • The worker thread does not have to wait for a response from the UI thread before it can proceed as would be the case with Invoke.
    • It breaks the tight coupling between the UI and worker threads that Invoke would impose.
    • It is more efficient...considerably.
    • You get more throughput on both the UI and worker threads.
    • There is no chance of saturating the UI message queue as could be the case with BeginInvoke.
    • You do not have to litter you code with Invoke calls everytime you need to update the UI from the worker thread.

提交回复
热议问题