Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/279.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 异步进度条更新_C#_Async Await - Fatal编程技术网

C# 异步进度条更新

C# 异步进度条更新,c#,async-await,C#,Async Await,我正试图使用异步等待根据复制操作更新WinForm上的进度条,但进度条只会在复制函数完成后更新,然后抛出一个无法更新的异常,因为它不在同一线程上 复制函数不需要与UI交互,但进度函数需要 但是UI并没有被阻止,所以异步部分看起来像预期的那样工作,它只是在与UI线程交互,而不是 long fileProgress = 0; long totalProgress = 0; bool complete = false; CopyFileEx.CopyFileCallbackAction callba

我正试图使用
异步等待
根据复制操作更新WinForm上的进度条,但进度条只会在
复制
函数完成后更新,然后抛出一个无法更新的异常,因为它不在同一线程上

复制函数不需要与UI交互,但进度函数需要

但是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;
      });
}

当使用async/await时,我使用IProgress和Progress实现,它们抽象掉了一些回调细节

我很确定你的程序不起作用,因为它是通过Task.run()调用在后台线程中运行的,所以它不能真正访问UI线程上下文中的UI控件

查看这篇关于使用async/await报告进度的文章,我认为这会有所帮助


在您当前的实现中,如果您希望它与回调一起工作,我想我应该直接在回调方法中更新进度条,而不是检查循环中进度变量的状态,当您将UI从后台线程中取出以实际访问进度条时,它将阻止您的UI。

您需要在此处使用
IProgress

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;
      });
}
private async void startButton_单击(对象发送方,事件参数e)
{
变量进度=新进度(百分比=>
{
fileProgressBar.Value=百分比;
});
等待副本(进度);
MessageBox.Show(“完成”);
}
无效副本(i进度)
{
Task.Run(()=>
{
CopyFileEx.FileRoutines.CopyFile(新文件信息(@“C:\\U USB\Fear.rar”)、新文件信息(@“H:\Fear.rar”)、CopyFileEx.CopyFileOptions.All、回调、空、进度);
完整=正确;
});
}
您的回调方法可以报告
IProgress
的进度,如:

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;
}
CopyFileEx.CopyFileCallbackAction回调(FileInfo源、FileInfo目标、对象状态、long totalFileSize、long TotalByTestTransfered、IProgress进度)
{
fileProgress=TotalByTestTransfered;
totalProgress=totalFileSize;
进度报告(转换为32(文件进度/总进度));
返回CopyFileEx.CopyFileCallbackAction.Continue;
}
你可以看看

  • async/await
    就是在处理I/O时不阻塞线程——任何线程。在
    Task.Run()
    (就像您在
    Copy()
    中所做的那样)内放置阻塞I/O调用并不能避免阻塞——它只是创建了一个其他线程稍后将拾取的任务,只是发现当它点击blocking
    CopyFileEx.FileRoutines.CopyFile()
    方法时,它自己被阻塞了
  • 您之所以会出现此错误,是因为您没有正确使用
    async/await
    (无论上述情况如何)。想想哪个线程正在试图修改UI对象
    fileProgressBar
    :随机线程池线程拾取您在
    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;
    }
    

    指出
    fileProgressBar.Invoke(()=>{…})不编译,您需要使用委托类型,例如:
    fileProgressBar.Invoke(新操作(()=>{…}))