Prevent freezing UI thread when using tasks and async/await or ContinueWith are not right?

342 Views Asked by At

I have a method called Do() it do some compute then save results in 2 different files and then do some other computes. As files may be large I wanted to update files by using task or something like that to prevent UI from freezing. I tried using TaskFactory and Wait and WaitAll but they freezed UI. other option is ContinueWith but there are many code after it that I can not move them up and I do not think moving all of them in ContinueWith be right thing to do. It can be easy by using async/await but I have to use .NetFramework4 so I can not use them. Other option that I think about it is to call a method and create a backgroundworker, in it update files and in Runworkercompleted event call a method to do remaining. But it is even uglier. Is there a better way for doing something in Separate thread/task in middle of a method without affecting other codes and UI thread? It is like doing all method works in separate thread/task and do not leave it until it be done completely without freezing UI.

Note: I have to use .NetFrameWork4.

method Do is:

public void Do()
{
    //---------------
    //other codes
    //---------------

    SaveResult1();
    SaveResult2();

    //---------------
    //other codes that I can not move them up
    //---------------
}
2

There are 2 best solutions below

2
Alexander Petrov On

You can do it like this:

void Do()
{
    // Some code

    Task.Factory.StartNew(() =>
    {
        SaveResult1();
        SaveResult2();
    })
    .ContinueWith(t =>
    {
        // Other code
    });
}
0
Mahmood Shahrokni On

To perform prolonged actions, you have some options that you can think about. One of these options which I always prefer, is beginInvoke method. All you need to do is making an appropriate delegation which has the same signature of your desired method. There are two different approaches for firing a delegation. Synchronous or asynchronous. Using this method, It lets your UI to do it's own job while the second thread is responsible for doing the slow part. When you call the beginInvoke method the first thread spawns the second one and continues. It also lets you to know if the job is done. Here the first parameter of the method is a callback method. The good news is that you can pass your current state to the callback method using the second parameter.

Look at the code below :

First define your delegation

public delegate void SimpleDelegate();

Then encapsulate your method and fire it

var obj = new ClassA();
var del = new SimpleDelegate(obj.Do);
Console.WriteLine("Start");
del.BeginInvoke(null, null);
Console.WriteLine("End");
Console.ReadKey();

This is a prolonged action.

  public void Do()
  {
   Thread.Sleep(5000);
   Console.WriteLine("Done!");
  }