Listview update in ProgressChanged event slows down the application too much

Viewed 42

I have a ProgressChanged event for download and in this event I update a Listview writing async threads statuses. But this operation slows down the program, even causes Not Responding. My code and an ss are below. How can I fix this problem.

private void downloader_ProgressChanged(object sender, EventArguments.ProgressChangedEventArgs e)
{
    this.Invoke(new Action(() =>
    {
        progressBar1.Value = (int)(downloader.Progress * 100);
        if (downloader.Info.ContentSize > 0)
            lblContentSize.Text = downloader.Info.ContentSize.ToHumanReadableSize();
        lblSpeed.Text = downloader.Speed.ToHumanReadableSize() + "/s";
        lblReceived.Text =
            string.Format("{0} ({1})",
                downloader.TotalBytesReceived.ToHumanReadableSize(),
                string.Format("{0:0.00}%", downloader.Progress));
        segmentedProgressBar1.ContentLength = downloader.Info.ContentSize;
        segmentedProgressBar1.Bars = downloader.Ranges.ToList().Select(x => new Bar(x.TotalBytesReceived, x.Start, x.Status)).ToArray();
        lblResumeability.Text = downloader.Info.AcceptRanges ? "Yes" : "No";
        listView1.BeginUpdate();
        writeThreads();
        listView1.EndUpdate();
    }));
}

private void writeThreads()
{
    var ranges = downloader.Ranges.ToList();
    ranges = ranges.Where(x => !x.IsIdle).ToList();
    for (var i = 0; i < ranges.Count; i++)
    {
        listView1.Items[i].SubItems[1].Text = (ranges[i].TotalBytesReceived.ToHumanReadableSize());
        listView1.Items[i].SubItems[2].Text = (ranges[i].Status.ToString());
    }
}

enter image description here

1 Answers

DownloadProgressChanged being fired on every chunk received e.g. for each 4kb received. You probably may update UI not for each call but only if percentage was changed.

private int storedPercentage = -1;

private void downloader_ProgressChanged(object sender, EventArguments.ProgressChangedEventArgs e)
{
    if (e.ProgressPercentage != storedPercentage)
    {
        storedPercentage = e.ProgressPercentage;
        this.Invoke((Action)(() =>
        {
            // existing code...
        }));
    }
}

Disclamer: exactly this way to fix is applicable only for single active download process. But the idea would be the same for concurrent downloads.

Related