WPF async await

I'm trying to use async click event:

private async void Button_Click(object sender, RoutedEventArgs e)
{
    MessageBox.Show(Thread.CurrentThread.ManagedThreadId + "   click_begin");
    await changeProgressBarAsync(ProgresBar_mainLoad);
    MessageBox.Show(Thread.CurrentThread.ManagedThreadId + "    click_end");
}

public Task changeProgressBarAsync(ProgressBar pb)
{
    return Task.Factory.StartNew(() =>
    {
        MessageBox.Show(Thread.CurrentThread.ManagedThreadId + "    task");
        int count = 100;
        while (count-- > 0)
        {
            pb.Dispatcher.Invoke(() =>
            {
                pb.Value += 1;
            });

            Thread.Sleep(10);
        }
    });
}

Following the async-await C# logic, lines

MessageBox.Show(Thread.CurrentThread.ManagedThreadId + "    task");

and

MessageBox.Show(Thread.CurrentThread.ManagedThreadId + "    click_end");

should show equal thread Id, but this program show me

  • 1 click_begin
  • 5 task
  • 1 click_end

So why it happens?

I did same test in console app

static void Main(string[] args)
{
    TestClick();
    Console.ReadKey();
}

public static async void TestClick()
{
    Console.WriteLine(Thread.CurrentThread.ManagedThreadId + " it is TestClick1");
    await Worker();
    Console.WriteLine(Thread.CurrentThread.ManagedThreadId + " it is TestClick2");
}

public static Task Worker()
{
    return Task.Factory.StartNew(() =>
    {
        Console.WriteLine(Thread.CurrentThread.ManagedThreadId + " it is Task");
    });
}

And it show me

  • 1 it is TestClick1
  • 3 it is Task
  • 3 it is TestClick2
Jon Skeet
people
quotationmark

You're explicitly starting a new task using Task.Factory.StartNew(). That's almost always going to run in a non-UI thread.

The async/await way of doing this is not to start a new task on a different thread, not to use the dispatcher, and not to use Thread.Sleep, but Task.Delay instead. Then you'd have:

public async Task ChangeProgressBarAsync(ProgressBar pb)
{
    MessageBox.Show(Thread.CurrentThread.ManagedThreadId + "    task");
    int count = 100;
    while (count-- > 0)
    {
        pb.Value++;
        await Task.Delay(10);
    }
}

No extra threads anywhere.

In your console app you're seeing different threads because a console app doesn't have a synchronization context - there's nothing to make the continuation execute in the same thread as the thread that originally awaited.

people

See more on this question at Stackoverflow