我试图使用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)
你需要在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)
async / await这是关于在处理I / O时不阻塞线程(任何线程)的全部内容。将阻塞的 I / O调用放入内部Task.Run()(就像您在中所做的那样Copy())并不能避免阻塞-它只是创建一个Task,稍后其他线程将拾取该Task,只是发现它撞到blocking CopyFileEx.FileRoutines.CopyFile()方法时本身就被阻塞了。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)
| 归档时间: |
|
| 查看次数: |
21473 次 |
| 最近记录: |