我完全不熟悉C#5的新async/ await关键字,我对实现进度事件的最佳方式感兴趣.
现在我更喜欢它,如果一个Progress事件Task<>本身.我知道我可以把事件放在包含异步方法的类中,并在事件处理程序中传递某种状态对象,但对我而言,这似乎更像是一种解决方法而不是解决方案.我可能还想要不同的任务来触发不同对象中的事件处理程序,这听起来很混乱.
有没有办法可以做类似以下的事情?:
var task = scanner.PerformScanAsync();
task.ProgressUpdate += scanner_ProgressUpdate;
return await task;
Run Code Online (Sandbox Code Playgroud)
Ste*_*ary 48
基于任务的异步模式文档中描述了推荐的方法,该文档为每个异步方法提供了自己的方法IProgress<T>:
public async Task PerformScanAsync(IProgress<MyScanProgress> progress)
{
...
if (progress != null)
progress.Report(new MyScanProgress(...));
}
Run Code Online (Sandbox Code Playgroud)
用法:
var progress = new Progress<MyScanProgress>();
progress.ProgressChanged += ...
PerformScanAsync(progress);
Run Code Online (Sandbox Code Playgroud)
笔记:
progress参数可能是null调用者不需要进度报告,因此请务必在async方法中检查.Progress.Progress<T>类型将捕获构造上的当前上下文(例如,UI上下文)并将ProgressChanged在该上下文中引发其事件.因此,在调用之前,您不必担心编组返回UI线程Report.Jon*_*eet 45
简单地说,Task 不支持进展.但是,使用IProgress<T>界面已经有了传统的方法.基于任务的异步模式基本上建议重载异步方法(在有意义的地方)允许客户端传入IProgess<T>实现.然后,您的异步方法将通过该方法报告进度.
Windows运行时(WinRT)API 确实具有内置的进度指示器,在IAsyncOperationWithProgress<TResult, TProgress>和IAsyncActionWithProgress<TProgress>类型中...所以如果您实际上正在为WinRT编写,那些值得研究 - 但也请阅读下面的注释.
我不得不把几个帖子中的这个答案拼凑起来,因为我试图弄清楚如何使这项工作适用于不那么简单的代码(即事件通知更改).
我们假设您有一个同步项目处理器,它将宣布它即将开始工作的项目编号.对于我的示例,我只是操纵Process按钮的内容,但您可以轻松更新进度条等.
private async void BtnProcess_Click(object sender, RoutedEventArgs e)
{
BtnProcess.IsEnabled = false; //prevent successive clicks
var p = new Progress<int>();
p.ProgressChanged += (senderOfProgressChanged, nextItem) =>
{ BtnProcess.Content = "Processing page " + nextItem; };
var result = await Task.Run(() =>
{
var processor = new SynchronousProcessor();
processor.ItemProcessed += (senderOfItemProcessed , e1) =>
((IProgress<int>) p).Report(e1.NextItem);
var done = processor.WorkItWorkItRealGood();
return done ;
});
BtnProcess.IsEnabled = true;
BtnProcess.Content = "Process";
}
Run Code Online (Sandbox Code Playgroud)
关键是要关闭Progress<>变量内部ItemProcessed订阅.这允许一切Just works ™.
| 归档时间: |
|
| 查看次数: |
28618 次 |
| 最近记录: |