使用BackgroundWorker的替代方法,以异步/ TPL(.NET 4.0)(Replaci

2019-07-31 09:30发布

我的问题是很多的。 因为我看到了。 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);

老实说,我已经厌倦了。 这成为一个很大的问题时,有一个逻辑复杂的用户交互。

我想知道,如何简化这个逻辑是什么? (请记住,我有。净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.StartNewDispatcher.Invoke ,但似乎有趣,简单易用罢了。 谁能给我一些启示?

Answer 1:

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

Task.Factory.StartNew(() =>
{
    return ProcessMethod(yourArgument);
})
.ContinueWith(antecedent =>
{
    UpdateView(antecedent.Result);
},
TaskScheduler.FromCurrentSynchronizationContext());

除了一些例外访问前提的,当处理Result的财产,这是所有有过它。 通过使用FromCurrentSynchronizationContext()即来自WPF(即DispatcherSynchronizationContext)环境的SynchronizationContext将被用于执行的延续。 这是与调用Dispatcher.[Begin]Invoke ,但你完全从它抽象出来的。

如果你想获得甚至是“干净”,如果你控制ProcessMethod我真的重写返回一个Task ,让它拥有该如何得到纺达(仍然可以使用StartNew内部)。 这样,你的抽象从ProcessMethod可能要作出自己的,而是他们只担心链接上的延续,等待结果的异步执行决定调用者。

UPDATE 2013年5月22日

应当指出的是,与.NET 4.5在C#中出现和异步语言支持这一规定的技术已经过时,你可以简单地依靠这些功能使用执行特定任务await Task.Run ,然后执行后,将采取地方在调度线程上再次自动地。 因此,像这样:

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

UpdateView(processingResult);


Answer 2:

如何封装,始终是在一个可重用的组件相同的代码? 您可以创建一个可冻结它实现ICommand的,暴露类型DoWorkEventHandler和Result属性的属性。 在ICommand.Executed,它会创建一个BackgroundWorker及导线上的DoWork的代表和完成,使用作为事件处理程序DoWorkEventHandler的价值,并在某种程度上处理完成的,它设置了自己的Result属性在事件返回的结果。

你会配置XAML的部件,使用转换器将DoWorkEventHandler财产上的视图模型的方法(我假设你有一个)进行绑定,并将绑定您查看到组件的结果属性,所以它就会自动的结果时更新做了更改通知。

该方案的优点是:它是可重复使用,而且只用XAML的作品,所以在您的视图模型没有更多的胶水代码只是为了处理BackgroundWorkers。 如果你不需要你的后台进程报告进度,甚至有可能不知道它运行在后台线程,所以你是否要同步或异步调用的方法,你可以在XAML决定。



Answer 3:

几个月过去了,但会这样帮助你吗?
使用异步/无等待的.NET Framework 4.5



文章来源: Replacing methods that use backgroundworker to async / tpl (.NET 4.0)