Search code examples
c#wpfbackground-processcaliburn.micro

WPF 4.5: How to create child thread and continue task to UI main thread?


I use WPF 4.5 and MVVM Caliburn Micro and have following WPF code:

public class MainViewModel: Screen
{
    public MainViewModel()
    {
        if (!ConnectServer())
        {
            Console.WriteLine("Connection failed");
            return;
        }
        // Following method can only be run if server connection established
        ProcessThis();
    }
}

My code above has only one chance to connect and if it is failed it shows the view and do nothing. If I use while(!ConnectServer()) it will block the UI thread all the time, means nothing will be displayed to user while the connection is still failed.It is very ugly.

What I want:

  1. if the connection is failed, means ConnectServer() returns false, it should wait for 10 seconds and try to connect again and again (eg. call a method RetryConnect()) till it is successful WITHOUT blocking the UI thread.
  2. And after it is connected, it should continue to main thread and run ProcessThis().

Theoretically I know it needs background separated thread, but I don't know how to implement it simple and good. Please feel free to use my sample code to explain. Thank you in advance.


Solution

  • To start a background task you can use Task.Run method. And to execute a code in the main thread you can use Dispatcher of the page (in case of VM context I have placed call of Application.Current.Dispatcher)

    public class MainViewModel: Screen
    {
        public MainViewModel()
        {
            Task.Run(() =>
            {
                while (!ConnectServer())
                {
                    Console.WriteLine("Connection failed");
                    Thread.Sleep(10*1000);
                }
    
                // Following method can only be run if server connection established
                Application.Current.Dispatcher.Invoke(ProcessThis);
            }
        }
    }
    

    Instead of usage of Dispatcher you can utilize a new async/await functionality to implement it.

    public class MainViewModel: Screen
    {
        public MainViewModel()
        {
            Initialize();
        }
    }
    
    private async void Initialize()
    {
            await Task.Run(async () =>
            {
                while (!ConnectServer())
                {
                    Console.WriteLine("Connection failed");
                    await Task.Delay(10*1000);
                }
            }
    
            // Following method can only be run if server connection established
            ProcessThis();
    }