Async/Await with a WinForms ProgressBar

后端 未结 3 760
天命终不由人
天命终不由人 2020-12-08 22:12

I\'ve gotten this type of thing working in the past with a BackgroundWorker, but I want to use the new async/await approach of .NET 4.5. I may be barking up the wrong tree.

相关标签:
3条回答
  • 2020-12-08 22:21
    private async void button1_Click(object sender, EventArgs e)
    {
        IProgress<int> progress = new Progress<int>(value => { progressBar1.Value = value; });
        await Task.Run(() =>
        {
            for (int i = 0; i <= 100; i++)
                progress.Report(i);
        });
    }
    

    Correct me if I'm wrong, but this seems to be the easiest way to update a progress bar.

    0 讨论(0)
  • 2020-12-08 22:32

    @StephenCleary's answer is correct. Though, I had to make a little modification to his answer to get the behavior what I think OP wants.

    public void GoAsync() //no longer async as it blocks on Appication.Run
    {
        var owner = new Win32Window(Process.GetCurrentProcess().MainWindowHandle);
        _progressForm = new Form1();
    
        var progress = new Progress<int>(value => _progressForm.UpdateProgress(value));
    
        _progressForm.Activated += async (sender, args) =>
            {
                await Go(progress);
                _progressForm.Close();
            };
    
        Application.Run(_progressForm);
    }
    
    0 讨论(0)
  • 2020-12-08 22:40

    The async and await keywords do not mean "run on a background thread." I have an async/await intro on my blog that describes what they do mean. You must explicitly place CPU-bound operations on a background thread, e.g., Task.Run.

    Also, the Task-based Asynchronous Pattern documentation describes the common approaches with async code, e.g., progress reporting.

    class Manager
    {
      private static Form1 _progressForm;
    
      public async Task GoAsync()
      {
        var owner = new Win32Window(Process.GetCurrentProcess().MainWindowHandle);
        _progressForm = new Form1();
        _progressForm.Show(owner);
    
        var progress = new Progress<int>(value => _progressForm.UpdateProgress(value));
        await Go(progress);
    
        _progressForm.Hide();
      }
    
      private Task<bool> Go(IProgress<int> progress)
      {
        return Task.Run(() =>
        {
          var job = new LongJob();
          job.Spin(progress);
          return true;
        });
      }
    }
    
    class LongJob
    {
      public void Spin(IProgress<int> progress)
      {
        for (var i = 1; i <= 100; i++)
        {
          Thread.Sleep(25);
          if (progress != null)
          {
            progress.Report(i);
          }
        }
      }
    }
    

    Note that the Progress<T> type properly handles thread marshaling, so there's no need for marshaling within Form1.UpdateProgress.

    0 讨论(0)
提交回复
热议问题