WebClient.DownloadProgressChanged:Console.WriteLine()阻止UI线程

时间:2014-12-03 00:50:39

标签: c# webclient downloadfileasync

我有以下简单的代码:

private void btn_download_Click(object sender, EventArgs e){

    WebClient client = new WebClient();
    client.DownloadProgressChanged += client_DownloadProgressChanged;
    client.DownloadFileAsync(new Uri("http://.../file.zip"), "file.zip");

}

void client_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e){
    //Prints: "Downloaded 3mb of 61.46mb  (4%)"

    Console.WriteLine("Downloaded "
        + ((e.BytesReceived / 1024f) / 1024f).ToString("#0.##") + "mb"
        + " of "
        + ((e.TotalBytesToReceive / 1024f) / 1024f).ToString("#0.##") + "mb"
        + "  (" + e.ProgressPercentage + "%)"
    );
}

为什么这会阻止UI线程?当我用代码替换Console.WriteLine()以更新我的进度条(不在代码中显示)时,它可以正常工作。用户界面响应迅速。

1 个答案:

答案 0 :(得分:4)

你这样做的方式似乎是MSDN shows in its examples。我也试了一下,得到了同样的结果。在单独的线程中运行某些东西时会看到类似的行为,然后过快地回调到主UI线程并将其与更新相关联。 UI线程得到备份并有效冻结。

DownloadProgressChanged事件真的很快发生......似乎每秒数百次,这意味着它也试图快速写入控制台。

您可以限制您写入控制台的频率,这将解决问题(我通过尝试下载4GB ISO进行测试,并在保持UI响应的同时写入控制台):

// define a class-level field variable
private int counter;

private void client_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
    counter++;

    // Only print to the console once every 500 times the event fires,
    //  which was about once per second when I tested it
    if (counter % 500 == 0)
    {
        //Prints: "Downloaded 3mb of 61.46mb  (4%)"
        Console.WriteLine("Downloaded "
                          + ((e.BytesReceived / 1024f) / 1024f).ToString("#0.##") + "mb"
                          + " of "
                          + ((e.TotalBytesToReceive / 1024f) / 1024f).ToString("#0.##") + "mb"
                          + "  (" + e.ProgressPercentage + "%)"
            );
    }
}