1

I have the following simple code:

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 + "%)"
    );
}

Why is this blocking the UI thread? When I replace the Console.WriteLine() with code to update my progress bar (not show in code), it works. The UI is responsive.

leppie
  • 115,091
  • 17
  • 196
  • 297
Krimson
  • 7,386
  • 11
  • 60
  • 97
  • Is there a console to write to? Why are you writing to a console from your GUI program? Would it make more sense to use the `Debug` class here, or a `TraceListener`? – Peter Duniho Dec 03 '14 at 00:54
  • @PeterDuniho Well writing to Console is basically outputting to "standard output" and this can be viewed in the "output: window in Visual Studio. Add yes it would make more sense but my question is not asking for an alternative. I want to know the reason behind this behaviour – Krimson Dec 03 '14 at 00:57
  • @GrantWinney The Console updates, i.e I can see the output from `Console.WriteLine()` but the GUI is stuck. Once the download is completed, the GUI is responsive again – Krimson Dec 03 '14 at 00:58

1 Answers1

4

The way you're doing it seems to be how MSDN shows in its examples. I tried it too and got the same result. You'll see similar behavior when running something in a separate thread, which then calls back to the main UI thread too quickly and pounds it with updates. The UI thread gets backed up and effectively freezes.

That DownloadProgressChanged event fires really quickly... appears to be hundreds of times per second, meaning it's trying to write to the console that quickly too.

You can limit how often you're writing to the console, which will resolve the issue (I tested it by trying to download a 4GB ISO, and it wrote to the console while leaving the UI responsive):

// 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 + "%)"
            );
    }
}
Grant Winney
  • 65,241
  • 13
  • 115
  • 165