我的问题很多。从我看到。 NET 4.5,我印象非常深刻。不幸的是我的所有项目都是.NET 4.0,我不考虑迁移。所以我想简化我的代码。
目前,我的大多数代码通常需要足够的时间来冻结屏幕,我会执行以下操作:
BackgroundWorker bd = new BackgroundWorker();
bd.DoWork += (a, r) =>
{
r.Result = ProcessMethod(r.Argument);
};
bd.RunWorkerCompleted += (a, r) =>
{
UpdateView(r.Result);
};
bd.RunWorkerAsync(args);
老实说,我已经厌倦了。当存在逻辑复杂的用户交互时,这就成了一个大问题。
我想知道,如何简化这种逻辑? (请记住,我在.Net 4.0)我注意到谷歌的一些事情,但没有找到任何易于实施和适合我的需求。
我认为这个解决方案如下:
var foo = args as Foo;
var result = AsyncHelper.CustomInvoke<Foo>(ProcessMethod, foo);
UpdateView(result);
public static class AsyncHelper
{
public static T CustomInvoke<T>(Func<T, T> func, T param) where T : class
{
T result = null;
DispatcherFrame frame = new DispatcherFrame();
Task.Factory.StartNew(() =>
{
result = func(param);
frame.Continue = false;
});
Dispatcher.PushFrame(frame);
return result;
}
}
我不确定影响是否会影响调度程序框架。 但我知道它可以很好地工作,例如,我可以在所有控件事件中使用它而不必费心冻结屏幕。 我对泛型类型,协方差,逆变的知识是有限的,也许这个代码可以改进。
我想到了使用Task.Factory.StartNew
和Dispatcher.Invoke
的其他内容,但没有任何看似有趣且易于使用的内容。谁能给我一些启示?
答案 0 :(得分:15)
您应该使用任务并行库(TPL)。关键是为更新UI的任何延续时间指定当前TaskScheduler
的{{1}}。例如:
SynchronizationContext
除了访问前提条件Task.Factory.StartNew(() =>
{
return ProcessMethod(yourArgument);
})
.ContinueWith(antecedent =>
{
UpdateView(antecedent.Result);
},
TaskScheduler.FromCurrentSynchronizationContext());
属性时的一些异常处理,这就是它的全部内容。通过使用Result
,来自WPF的环境SynchronizationContext(即DispatcherSynchronizationContext)将用于执行延续。这与调用FromCurrentSynchronizationContext()
相同,但您完全从中抽象出来。
如果你想要“更干净”,如果你控制ProcessMethod,我实际上会重写它以返回Dispatcher.[Begin]Invoke
并让它拥有如何旋转(仍然可以在内部使用Task
) 。这样你就可以从ProcessMethod可能想要自己做的异步执行决策中抽象调用者,而只需要担心链接继续等待结果。
更新2013年5月22日
应该注意的是,随着.NET 4.5的出现和C#中的异步语言支持,这种规定的技术已经过时,您可以简单地依靠这些功能来使用StartNew
执行特定任务,然后执行这将自动在Dispatcher线程上再次发生。所以像这样:
await Task.Run
答案 1 :(得分:1)
如何封装在可重用组件中始终相同的代码?您可以创建一个实现ICommand的Freezable,公开Type DoWorkEventHandler的属性和Result属性。在ICommand.Executed上,它将创建一个BackgroundWorker并使用DoWorkEventHandler的值作为事件处理程序连接DoWork和Completed的委托,并以一种方式处理Completed,它将自己的Result属性设置为事件中返回的结果
您在XAML中配置组件,使用转换器将DoWorkEventHandler属性绑定到ViewModel上的方法(我假设您有一个),并将View绑定到组件的Result属性,以便更新当Result执行更改通知时自动。
此解决方案的优点是:它可重用,并且仅适用于XAML,因此ViewModel中不再需要用于处理BackgroundWorkers的粘合代码。如果您不需要后台进程来报告进度,它甚至可能不知道它在后台线程上运行,因此您可以在XAML中决定是要同步还是异步调用方法。
答案 2 :(得分:0)
几个月过去了,但这对你有帮助吗? Using async/await without .NET Framework 4.5