Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Replacing methods that use backgroundworker to async / tpl (.NET 4.0)

My questions are many. Since I saw. NET 4.5, I was very impressed. Unfortunately all my projects are .NET 4.0 and I am not thinking about migrating. So I would like to simplify my code.

Currently, most of my code that usually take enough time to freeze the screen, I do the following:

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

bd.RunWorkerAsync(args);

Honestly, I'm tired of it. And that becomes a big problem when there is a logic complex user interaction.

I wonder, how to simplify this logic? (Remember that I'm with. Net 4.0) I noticed a few things by google, but not found anything easy to implement and suitable for my needs.

I thought this solution below:

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;
    }
}

I am not sure about the impact is on manipulating the dispatcher frame. But I know That it would work very well, for example, I could use it in all the events of controls without bothering to freeze the screen. My knowledge about generic types, covariance, contravariance is limited, maybe this code can be improved.

I thought of other things using Task.Factory.StartNew and Dispatcher.Invoke, but nothing that seems interesting and simple to use. Can anyone give me some light?

like image 662
J. Lennon Avatar asked Sep 06 '12 03:09

J. Lennon


People also ask

Why we use BackgroundWorker class in c#?

As the name suggests the Background Worker Class allows you to set a thread continuously running in the background and communicating with the main thread whenever required. BackgroundWorker makes the implementation of threads in Windows Forms. Intensive tasks need to be done on another thread so the UI does not freeze.

What is the difference between BackgroundWorker and thread?

A BackgroundWorker is a ready to use class in WinForms allowing you to execute tasks on background threads which avoids freezing the UI and in addition to this allows you to easily marshal the execution of the success callback on the main thread which gives you the possibility to update the user interface with the ...

What is BackgroundWorker in vb net?

BackgroundWorker handles long-running tasks. It does not freeze the entire program as this task executes. The BackgroundWorker type provides an excellent solution. It enables a simple multithreaded architecture for VB.NET programs. To begin, you will need a VB.NET Windows Forms project open.


2 Answers

You should just use the Task Parallel Library (TPL). The key is specifying the TaskScheduler for the current SynchronizationContext for any continuations in which you update the UI. For example:

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

Aside from some exception handling when accessing the antecedent's Result property, that's all there is too it. By using FromCurrentSynchronizationContext() the ambient SynchronizationContext that comes from WPF (i.e. the DispatcherSynchronizationContext) will be used to execute the continuation. This is the same as calling Dispatcher.[Begin]Invoke, but you are completely abstracted from it.

If you wanted to get even "cleaner", if you control ProcessMethod I would actually rewrite that to return a Task and let it own how that gets spun up (can still use StartNew internally). That way you abstract the caller from the async execution decisions that ProcessMethod might want to make on its own and instead they only have to worry about chaining on a continuation to wait for the result.

UPDATE 5/22/2013

It should be noted that with the advent of .NET 4.5 and the async language support in C# this prescribed technique is outdated and you can simply rely on those features to execute a specific task using await Task.Run and then execution after that will take place on the Dispatcher thread again automagically. So something like this:

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

UpdateView(processingResult);
like image 143
Drew Marsh Avatar answered Oct 19 '22 06:10

Drew Marsh


How about encapsulating the code that is always the same in a reusable component? You could create a Freezable which implements ICommand, exposes a property of Type DoWorkEventHandler and a Result property. On ICommand.Executed, it would create a BackgroundWorker and wire up the delegates for DoWork and Completed, using the value of the DoWorkEventHandler as event handler, and handling Completed in a way that it sets its own Result property to the result returned in the event.

You'd configure the component in XAML, using a converter to bind the DoWorkEventHandler property to a method on the ViewModel (I assume you've got one), and bind your View to the component's Result property, so it gets updated automatically when Result does a change notification.

The advantages of this solution are: it is reusable, and it works with XAML only, so no more glue code in your ViewModel just for handling BackgroundWorkers. If you don't need your background process to report progress, it could even be unaware that it runs on a background thread, so you can decide in the XAML whether you want to call a method synchronously or asynchronously.

like image 27
hbarck Avatar answered Oct 19 '22 06:10

hbarck