Pregunta

I do some tests with the new asynchronous pattern of C# 5.0 (async/await) I have a problem with understanding how the asynchronous methods are called.

Considering this code :

private async Task<string> DownloadAsync()
    {
        progress.ProgressChanged += (s, e) =>
            {
                progressBar1.Value = e.value;
            };

            return await DownloadSomething(myurl, progress);

    }

private async void CallDownloadAsync()
    {
        string text = await DownloadAsync();
        progressBar1.Value = 0;
        label1.Text = "Done!";
    }

private void button4_Click(object sender, EventArgs e)
    {
        CallDownloadAsync();
    }

So, this code works very well. When I clic the "button4" a downloading task begins and my ProgressBar is updated correctly.

But, I'd like to compact my code a little bit more by removing CallDownloadAsync() method like this :

private void button4_Click(object sender, EventArgs e)
    {
        new Action(async () =>
        {
            string result = await Task.Run<string>(() => DownloadAsync());
        }).Invoke();
        label1.Text = "Running...";
    }

So here, I want to directly initiate an action which calls the DownloadAsync method but when I hit my Button4 I have a Cross-thread operation not valid on the progressBar. So I do not understand what is the main difference between the Action() and the call of my CallDownloadAsync() method.

¿Fue útil?

Solución 2

The difference is that in former case you call CallDownloadAsync() from UI thread (context).

In the latter case, DownloadAsync() is called from the initiated Task which is generally executed in a different thread created by TPL (Task Parallel Library) out of UI thread or threads created from it.

In WPF, UI components can be accessed only by a dedicated UI thread or (its children) threads created from under it (i.e with the same UI context).

Otros consejos

You may find my async/await intro helpful. In particular, an async method does not run on a background thread; Task.Run is used to run something on a background thread, hence the difference in your code.

In general, you should avoid async void, unless you're writing an async event handler. Like this:

private async void button4_Click(object sender, EventArgs e)
{
    label1.Text = "Running...";
    string result = await DownloadAsync();
    progressBar1.Value = 0;
    label1.Text = "Done!";
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top