我试图使用异步等待根据复制操作更新我的WinForm上的进度条,但进度条只会在复制功能完成时更新,然后抛出一个无法更新的异常,因为它不是在同一个线程上?
虽然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就是在处理I / O时没有阻塞线程 – 任何线程.在Task.Run()中放置一个阻塞I / O调用(就像你在Copy()中所做的那样)并没有避免阻塞 – 它只是创建了一个其他线程稍后会选择的任务,只是发现它本身被阻塞了它命中了阻塞的CopyFileEx.FileRoutines.CopyFile()方法.
>您收到该错误是因为您没有正确使用async / await(无论上述情况如何).考虑哪个线程正在尝试修改UI对象fileProgressBar:随机线程池线程获取您在Task.Run()上创建的任务获取执行fileProgressBar.Value = …,这显然会抛出.
>您收到该错误是因为您没有正确使用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(() => { //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; }