2

我使用 C# 5.0 (async/await) 的新异步模式进行了一些测试,但我在理解如何调用异步方法时遇到了问题。

考虑到这段代码:

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();
    }

所以,这段代码工作得很好。当我单击“button4”时,下载任务开始并且我的 ProgressBar 已正确更新。

但是,我想通过删除这样的 CallDownloadAsync() 方法来进一步压缩我的代码:

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

所以在这里,我想直接启动一个调用 DownloadAsync 方法的操作,但是当我点击我的 Button4 时,我的跨线程操作在进度条上无效。所以我不明白 Action() 和我的 CallDownloadAsync() 方法的调用之间的主要区别是什么。

4

2 回答 2

4

您可能会发现我的async/await介绍很有帮助。特别是,async方法不在后台线程上运行;Task.Run用于在后台线程上运行某些东西,因此您的代码有所不同。

通常,您应该避免async void使用 ,除非您正在编写async事件处理程序。像这样:

private async void button4_Click(object sender, EventArgs e)
{
    label1.Text = "Running...";
    string result = await DownloadAsync();
    progressBar1.Value = 0;
    label1.Text = "Done!";
}
于 2013-04-22T11:31:29.090 回答
1

不同之处在于,在前一种情况下,您CallDownloadAsync()从 UI 线程(上下文)调用。

在后一种情况下,DownloadAsync()从启动的任务中调用,该任务通常在由 TPL(任务并行库)创建的 UI 线程或从它创建的线程中创建的不同线程中执行。

在 WPF 中,UI 组件只能由专用的 UI 线程或从其下创建的(其子)线程(即具有相同的 UI 上下文)访问。

于 2013-04-22T11:11:19.320 回答