异步进度条更新

Bal*_*i C 8 c# async-await

我试图使用an async await来更新我的WinForm基于复制操作的进度条,但进度条只会在Copy函数完成时更新,然后抛出一个异常,它无法更新,因为它不在同一个线?

复制功能不需要与UI交互,但Progress功能可以.

虽然UI没有被阻止,但是看起来异步部分正在按预期工作,它只是与UI线程进行交互.

long fileProgress = 0;
long totalProgress = 0;
bool complete = false;

CopyFileEx.CopyFileCallbackAction callback(FileInfo source, FileInfo destination, object state, long totalFileSize, long totalBytesTransferred)
{
      fileProgress = totalBytesTransferred;
      totalProgress = totalFileSize;
      return CopyFileEx.CopyFileCallbackAction.Continue;
}

async Task Progress()
{
      await Task.Run(() =>
      {
           while (!complete)
           {
                if (fileProgress != 0 && totalProgress != 0)
                {
                     fileProgressBar.Value = (int)(fileProgress / totalProgress) * 100;
                }
           }
      });
}

private async void startButton_Click(object sender, EventArgs e)
{
      Copy();
      await Progress();
      MessageBox.Show("Done");
}

void Copy()
{
      Task.Run(() =>
      {
           CopyFileEx.FileRoutines.CopyFile(new FileInfo(@"C:\_USB\Fear.rar"), new FileInfo(@"H:\Fear.rar"), CopyFileEx.CopyFileOptions.All, callback, null);
           complete = true;
      });
}
Run Code Online (Sandbox Code Playgroud)

Ehs*_*jad 8

你需要在IProgress<T>这里使用:

private async void startButton_Click(object sender, EventArgs e)
{
      var progress = new Progress<int>(percent =>
      {
         fileProgressBar.Value = percent;
      });

      await Copy(progress);

      MessageBox.Show("Done");
}

void Copy(IProgress<int> progress)
{
      Task.Run(() =>
      {
           CopyFileEx.FileRoutines.CopyFile(new FileInfo(@"C:\_USB\Fear.rar"), new FileInfo(@"H:\Fear.rar"), CopyFileEx.CopyFileOptions.All, callback, null,progress);
           complete = true;
      });
}
Run Code Online (Sandbox Code Playgroud)

并且您的回调方法可以报告IProgress<T>喜欢的进度:

CopyFileEx.CopyFileCallbackAction callback(FileInfo source, FileInfo destination, object state, long totalFileSize, long totalBytesTransferred,IProgress<int> progress)
{
      fileProgress = totalBytesTransferred;
      totalProgress = totalFileSize;
      progress.Report(Convert.ToInt32(fileProgress/totalProgress));
      return CopyFileEx.CopyFileCallbackAction.Continue;
}
Run Code Online (Sandbox Code Playgroud)

你可以看看Stephen Cleary的这篇非常好的文章


sha*_*y__ 5

  1. async / await这是关于在处理I / O时不阻塞线程(任何线程)的全部内容。将阻塞的 I / O调用放入内部Task.Run()(就像您在中所做的那样Copy())并不能避免阻塞-它只是创建一个Task,稍后其他线程将拾取该Task,只是发现它撞到blocking CopyFileEx.FileRoutines.CopyFile()方法时本身就被阻塞了。
  2. 由于没有async / await正确使用(不管上述情况如何),您将收到该错误。考虑一下哪个线程正在尝试修改UI对象fileProgressBar:拾取您在其上创建的Task的随机线程池线程Task.Run()将执行fileProgressBar.Value = ...,显然该线程将抛出该线程。

这是避免这种情况的一种方法:

async Task Progress()
{
      await Task.Run(() =>
      {
           //A random threadpool thread executes the following:
           while (!complete)
           {
                if (fileProgress != 0 && totalProgress != 0)
                { 
                    //Here you signal the UI thread to execute the action:
                    fileProgressBar.Invoke(new Action(() => 
                    { 
                        //This is done by the UI thread:
                        fileProgressBar.Value = (int)(fileProgress / totalProgress) * 100 
                    }));
                }
           }
      });
}

private async void startButton_Click(object sender, EventArgs e)
{
      await Copy();
      await Progress();
      MessageBox.Show("Done");  //here we're on the UI thread.
}

async Task Copy()
{
    //You need find an async API for file copy, and System.IO has a lot to offer.
    //Also, there is no reason to create a Task for MyAsyncFileCopyMethod - the UI
    // will not wait (blocked) for the operation to complete if you use await:
    await MyAsyncFileCopyMethod();
    complete = true;
}
Run Code Online (Sandbox Code Playgroud)

  • 指出`fileProgressBar.Invoke(()=&gt; {...});`不会编译,您需要使用一个委托类型,例如:`fileProgressBar.Invoke(new Action(()=&gt; {.. 。}));` (2认同)