WPF asynchronous Task<T> blocking UI

block, task, user-interface, wpf

Solution

Your main thread is blocking because the call to `Task.Result` waits until the `Task` has completed. Instead you can use `Task.ContinueWith()` to access the `Task.Result` after the `Task` has completed. The call to `TaskScheduler.FromCurrentSynchronizationContext()` causes the continuation to run on the main UI thread (so you can access `_button` safely).

private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
    _button.IsEnabled = false;

    Task<Boolean>.Factory.StartNew(() =>
    {
        Thread.Sleep(5*1000);
        return true;
    }).ContinueWith(t=>
    {
        if (t.Result)
            _button.IsEnabled = true;
    }, TaskScheduler.FromCurrentSynchronizationContext());        
}

Update

If you are using C# 5 you can use async/await instead.

private async void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
    _button.IsEnabled = false;

    var result = await Task.Run(() =>
    {
        Thread.Sleep(5*1000);
        return true;
    });

    _button.IsEnabled = result;      
}

Problem

I already worked with `Task` type. And all was good while `Task` return nothing. For example: XAML: ``` <Button Name="_button" Click="ButtonBase_OnClick"> Click </Button> ``` CodeBehind: ``` private void ButtonBase_OnClick(object sender, RoutedEventArgs e) { _button.IsEnabled = false; Task.Factory.StartNew(() => { Thread.Sleep(5*1000); Dispatcher.Invoke(new Action(() => _button.IsEnabled = true)); }); } ``` This works fine. But I want to `Task` returns some value, for example `Boolean`. So I need to use `Task<Boolean>`: ``` private void ButtonBase_OnClick(object sender, RoutedEventArgs e) { _button.IsEnabled = false; var task = Task<Boolean>.Factory.StartNew(() => { Thread.Sleep(5*1000); return true; }); if (task.Result) _button.IsEnabled = true; } ``` And here we have a problem with UI blocking. UI thread is locked untill task will return result. ``` _button.IsEnabled = false; ``` So, string above is completely ignored. I am on `.Net 4.0`, so I cannot use `async/await` approach. This problem really makes me sick... Has it solution?

Original source