Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/design-patterns/2.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
Wpf 将使用backgroundworker的方法替换为异步/tpl(.NET 4.0)_Wpf_Design Patterns_Pattern Matching_Task Parallel Library_Backgroundworker - Fatal编程技术网

Wpf 将使用backgroundworker的方法替换为异步/tpl(.NET 4.0)

Wpf 将使用backgroundworker的方法替换为异步/tpl(.NET 4.0),wpf,design-patterns,pattern-matching,task-parallel-library,backgroundworker,Wpf,Design Patterns,Pattern Matching,Task Parallel Library,Backgroundworker,我的问题很多。自从我看到。NET4.5,给我留下了深刻的印象。不幸的是,我所有的项目都是.NET4.0,我没有考虑迁移。所以我想简化我的代码 目前,我的大多数代码通常需要足够的时间来冻结屏幕,我执行以下操作: BackgroundWorker bd = new BackgroundWorker(); bd.DoWork += (a, r) => { r.Result = ProcessMethod(r.Argument); }; bd.RunWorkerCo

我的问题很多。自从我看到。NET4.5,给我留下了深刻的印象。不幸的是,我所有的项目都是.NET4.0,我没有考虑迁移。所以我想简化我的代码

目前,我的大多数代码通常需要足够的时间来冻结屏幕,我执行以下操作:

BackgroundWorker bd = new BackgroundWorker();
bd.DoWork += (a, r) =>
    {
        r.Result = ProcessMethod(r.Argument);
    };
bd.RunWorkerCompleted += (a, r)  =>
    {
        UpdateView(r.Result);
    };

bd.RunWorkerAsync(args);
老实说,我已经厌倦了。当存在逻辑复杂的用户交互时,这就成了一个大问题

我想知道,如何简化这个逻辑?(请记住,我使用的是.NET4.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;
    }
}
var foo=args作为foo;
var result=AsyncHelper.CustomInvoke(ProcessMethod,foo);
更新视图(结果);
公共静态类AsyncHelper
{
公共静态T CustomInvoke(Func Func,T param),其中T:class
{
T结果=null;
DispatcherFrame=新DispatcherFrame();
Task.Factory.StartNew(()=>
{
结果=函数(参数);
frame.Continue=false;
});
调度员.推架(框架);
返回结果;
}
}
我不确定对操纵dispatcher帧的影响。 但我知道它会工作得很好,例如,我可以在控件的所有事件中使用它,而不用费心冻结屏幕。 我对泛型类型、协方差、逆变换的了解有限,也许这段代码可以改进


我想到了使用
Task.Factory.StartNew
Dispatcher.Invoke
的其他方法,但没有什么有趣和简单的方法。谁能给我点启发吗?

你应该使用任务并行库(TPL)。关键是为当前的
SynchronizationContext
指定
TaskScheduler
,用于更新UI的任何延续。例如:

Task.Factory.StartNew(() =>
{
    return ProcessMethod(yourArgument);
})
.ContinueWith(antecedent =>
{
    UpdateView(antecedent.Result);
},
TaskScheduler.FromCurrentSynchronizationContext());
除了访问antecedent的
Result
属性时的一些异常处理之外,它还有其他功能。通过使用
FromCurrentSynchronizationContext()
来自WPF的环境同步上下文(即DispatchersSynchronizationContext)将用于执行延续。这与调用
调度程序相同。[Begin]Invoke
,但您完全脱离了它

如果你想变得更“干净”,如果你控制ProcessMethod,我实际上会重写它以返回一个
任务
,并让它知道如何旋转(仍然可以在内部使用
StartNew
)。这样,您就可以将调用方从ProcessMethod可能希望自己做出的异步执行决策中抽象出来,取而代之的是,调用方只需担心链接到一个continuation以等待结果

更新日期:2013年5月22日

应该注意的是,随着.NET 4.5的出现和C#中的异步语言支持,这种规定的技术已经过时,您可以简单地依靠这些功能使用
wait task执行特定任务。运行
,然后在调度程序线程上自动执行。比如说:

MyResultType processingResult = await Task.Run(() =>
{
    return ProcessMethod(yourArgument);
});

UpdateView(processingResult);

在可重用组件中封装始终相同的代码如何?您可以创建一个Freezable,它实现ICommand,公开DoWorkEventHandler类型的属性和结果属性。在ICommand.Executed上,它将创建一个BackgroundWorker,并将DoWork和Completed的委托关联起来,使用DoWorkEventHandler的值作为事件处理程序,并以将自己的Result属性设置为事件中返回的结果的方式处理Completed

您可以在XAML中配置组件,使用转换器将DoWorkEventHandler属性绑定到ViewModel上的方法(我假设您已经有了一个),并将视图绑定到组件的Result属性,这样当Result发出更改通知时,它会自动更新


此解决方案的优点是:它是可重用的,并且仅适用于XAML,因此ViewModel中不再有仅用于处理BackgroundWorkers的粘合代码。如果您不需要后台进程来报告进度,它甚至可能不知道它在后台线程上运行,因此您可以在XAML中决定是同步还是异步调用方法

几个月过去了,但这能帮到你吗?

似乎是简化代码的好选择,我已经可以想象如何使用它了。虽然,没有一个解决方案可以在相同的方法执行中继续?@J.Lennon我对您当前的工作队列实现了解不够,但是您肯定可以让相同的概念在任何情况下都可以使用。如果您可以控制实现,我建议使用TPL数据流API(ActionBlock)作为您的排队机制。不过,这是一篇完整的独立文章,可以解决所有这些问题。:)