首页 > 解决方案 > C# 使用 task 和 yield 让 UI 了解正在运行的进程

问题描述

编写这样的代码是不好的做法。我想要完成的是用户可以按下控件上的按钮。该按钮启动某种分析过程,并且对于完成的每个项目,它都会向用户显示结果。

private IEnumerable<int> AnalyzeItems() {
  for(int i = 0; i < 1000; i++) {
    Thread.Sleep(500);
    yield return i;
  }
}


private void PerformTask_Click(object sender, EventArgs e) {
  Task.Run(() => {
    foreach (var item in AnalyzeItems()) {
      ResultLog.Invoke((Action)delegate() { ResultLog.Text += item.ToString(); });
    }
  });
}

标签: c#winformsasynchronoustaskyield

解决方案


为什么不使用Backgroundworker

首先将 backgroundworker 属性设置为:

  • WorkerReportsProgress = true
  • WorkerSupportsCancellation = true

这是代码:

public partial class Form1 : Form {
    public Form1() {
        InitializeComponent();
    }

    private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) {
        for (int i = 0; i < 1000; i++) {
            Thread.Sleep(500);
            if (backgroundWorker1.CancellationPending) {
                e.Cancel = true;
                break;
            }
            backgroundWorker1.ReportProgress(i / 10, "step " + i);
        }
    }

    private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e) {
        label1.Text = e.UserState.ToString();
        progressBar1.Value = e.ProgressPercentage;
    }

    private void button1_Click(object sender, EventArgs e) {
        cancelButton.Focus();
        button1.Enabled = false;
        backgroundWorker1.RunWorkerAsync();
    }
    private void cancelButton_Click(object sender, EventArgs e) {
        backgroundWorker1.CancelAsync();
    }

    private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) {
        button1.Enabled = true;
        if (e.Error != null) {
            MessageBox.Show(e.Error.Message, "Unexpected error");
        }
        if (e.Cancelled) {
            MessageBox.Show("Process stopped by the user", "Cancelled");
        }
        label1.Text = "Press start";
        progressBar1.Value = progressBar1.Minimum;
    }

}

推荐阅读