1

我有以下简单的代码:

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()用代码替换以更新我的进度条(未显示在代码中)时,它可以工作。UI 是响应式的。

4

1 回答 1

4

您这样做的方式似乎是MSDN 在其示例中显示的方式。我也试过了,得到了同样的结果。在单独的线程中运行某些东西时,您会看到类似的行为,然后太快地回调主 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 + "%)"
            );
    }
}
于 2014-12-03T02:35:05.250 回答