C#控件回调事件中使用异步操作的方法

注意点

asyncawait 关键字一般成对出现,表示是异步函数。
async 里的代码可能在主线程运行,也可能在新线程运行。
await 里的代码在新线程里运行。
同时,被调用的异步函数返回值类型是Task

[DllImport("kernel32.dll")]
static extern int GetCurrentThreadId();

// 按钮事件
private void BtnTaskAwait_Click(object sender, EventArgs e)
{
  Debug.WriteLine("BtnTaskAwait_Click begin.");
  ExecuteTask(sender, e);
  Debug.WriteLine("BtnTaskAwait_Click end.");
}

// 执行短暂的同步操作,启动异步操作
private async void ExecuteTask(object sender, EventArgs e)
{
  Debug.WriteLine($"{GetCurrentThreadId()}");

// 界面线程执行开始
  Debug.WriteLine("ExecuteClickTaskAsync begin.");
  textBox1.Text = "";
  progressBar1.Visible = true;
  // 界面线程执行结束

  // 在非界面线程执行
  await DoSomethingAsync(sender, e);

  // 界面线程执行开始
  progressBar1.Visible = false;
  Debug.WriteLine("ExecuteClickTaskAsync end.");
  // 界面线程执行结束
}

// 执行耗时的异步操作
private async Task DoSomethingAsync(object sender, EventArgs e)
{
  Debug.WriteLine($"{GetCurrentThreadId()}");
  //await Task.Run(() =>
  //{
  //  //Task.Delay(TimeSpan.FromSeconds(5));
  //  System.Threading.Thread.Sleep(TimeSpan.FromSeconds(5));
  //});

  await Task.Run(() =>
  {
    // 在非界面线程执行,所以不能操作控件
    textBox1.Invoke((MethodInvoker)(() =>
    {
      textBox1.Text = "Task async UI: Sleep 5 second.";
    }));

    var sw = new Stopwatch();
    sw.Start();
    while (sw.Elapsed.TotalSeconds < 5)
    {
      int val = (int)(sw.Elapsed.TotalSeconds / 5 * 100) % 100;

      // 在非界面线程执行,所以不能操作控件
      progressBar1.Invoke((MethodInvoker)(() =>
      {
        progressBar1.Value = val;
      }));
      Task.Delay(TimeSpan.FromMilliseconds(1));
    }

    // 在非界面线程执行,所以不能操作控件
    textBox1.Invoke((MethodInvoker)(() =>
    {
      textBox1.Text = "Task async UI: Finished.";
    }));
  });
}

以下为Debug输出,可以看出是异步执行的。

BtnTaskAwait_Click begin.
ExecuteClickTaskAsync begin.
BtnTaskAwait_Click end.
ExecuteClickTaskAsync end.

posted on 2021-07-18 22:00  OctoberKey  阅读(610)  评论(0)    收藏  举报

导航