使用进度条下载异步文件

时间:2012-02-27 02:07:14

标签: c# asynchronous progress-bar

我正在尝试在WebClient下载进度发生变化时更改进度条的进度。当我调用startDownload()窗口冻结下载文件时,此代码仍会下载该文件。我希望用户能够在启动屏幕加载时看到进度更改。有没有办法解决这个问题,以便用户可以看到progressBar2更改的进度?

private void startDownload()
{
    WebClient client = new WebClient();
    client.DownloadProgressChanged += new DownloadProgressChangedEventHandler(client_DownloadProgressChanged);
    client.DownloadFileCompleted += new AsyncCompletedEventHandler(client_DownloadFileCompleted);
    client.DownloadFileAsync(new Uri("http://joshua-ferrara.com/luahelper/lua.syn"), @"C:\LUAHelper\Syntax Files\lua.syn");
}
void client_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
    double bytesIn = double.Parse(e.BytesReceived.ToString());
    double totalBytes = double.Parse(e.TotalBytesToReceive.ToString());
    double percentage = bytesIn / totalBytes * 100;
    label2.Text = "Downloaded " + e.BytesReceived + " of " + e.TotalBytesToReceive;
    progressBar1.Value = int.Parse(Math.Truncate(percentage).ToString());
}
void client_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
{
    label2.Text = "Completed";
}

4 个答案:

答案 0 :(得分:23)

单击 startDownload()时,UI线程将被冻结。如果您不希望get form冻结,可以在另一个线程中使用 startDownload(),并在交叉线程中进行更新。 一种方式,

private void startDownload()
{
    Thread thread = new Thread(() => {
          WebClient client = new WebClient();
          client.DownloadProgressChanged += new DownloadProgressChangedEventHandler(client_DownloadProgressChanged);
          client.DownloadFileCompleted += new AsyncCompletedEventHandler(client_DownloadFileCompleted);
          client.DownloadFileAsync(new Uri("http://joshua-ferrara.com/luahelper/lua.syn"), @"C:\LUAHelper\Syntax Files\lua.syn");
    });
    thread.Start();
}
void client_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
    this.BeginInvoke((MethodInvoker) delegate {
        double bytesIn = double.Parse(e.BytesReceived.ToString());
        double totalBytes = double.Parse(e.TotalBytesToReceive.ToString());
        double percentage = bytesIn / totalBytes * 100;
        label2.Text = "Downloaded " + e.BytesReceived + " of " + e.TotalBytesToReceive;
        progressBar1.Value = int.Parse(Math.Truncate(percentage).ToString());
    });
}
void client_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
{
    this.BeginInvoke((MethodInvoker) delegate {
         label2.Text = "Completed";
    }); 
}

像这样在Google中阅读更多多线程 http://msdn.microsoft.com/en-us/library/ms951089.aspx

- 修复失踪关闭);到bgThread声明

答案 1 :(得分:13)

您应该从UI线程中调用startDownload()WebClient.DownloadFileAsync()的整个想法是它会自动为你生成一个工作线程,而不会阻塞调用线程。在startDownload()中,您指定了修改控件的回调,我假设这些控件是由UI线程创建的。因此,如果从后台线程调用startDownload(),它将导致问题,因为线程只能修改它创建的UI元素。

它应该工作的方式是你从UI线程startDownload()调用startDownload(),因为你定义它设置由UI线程处理的事件回调。然后它以异步方式启动下载并立即返回。当进度发生变化时,将通知UI线程,并且负责更新进度条控件的代码将在UI线程上执行,并且应该没有任何问题。

答案 2 :(得分:1)

我相信这篇文章会引导你走向正确的方向http://www.dreamincode.net/forums/topic/115491-download-file-asynchronously-with-progressbar/

在这篇MSDN文章http://msdn.microsoft.com/en-us/library/ms229675.aspx中讨论了如何“在BackgroundWorker组件的工作线程上下载文件,该线程运行DoWork事件处理程序。当您的代码调用RunWorkerAsync方法时,该线程就会启动。”

答案 3 :(得分:1)

 public class ProgressEventArgsEx
{
    public int Percentage { get; set; }
    public string Text { get; set; }
}
public async static Task<string> DownloadStraingAsyncronous(string url, IProgress<ProgressEventArgsEx> progress)
{
    WebClient c = new WebClient();
    byte[] buffer = new byte[1024];
    var bytes = 0;
    var all = String.Empty;
    using (var stream = await c.OpenReadTaskAsync(url))
    {
        int total = -1;
        Int32.TryParse(c.ResponseHeaders[HttpRequestHeader.ContentLength], out total);
        for (; ; )
        {
            int len = await stream.ReadAsync(buffer, 0, buffer.Length);
            if (len == 0)
                break;
            string text = c.Encoding.GetString(buffer, 0, len);

            bytes += len;
            all += text;
            if (progress != null)
            {
                var args = new ProgressEventArgsEx();
                args.Percentage = (total <= 0 ? 0 : (100 * bytes) / total);
                progress.Report(args);
            }
        }
    }
    return all;
}
// Sample
private async void Bttn_Click(object sender, RoutedEventArgs e)
{
    //construct Progress<T>, passing ReportProgress as the Action<T> 
    var progressIndicator = new Progress<ProgressEventArgsEx>(ReportProgress);
    await TaskLoader.DownloadStraingAsyncronous(tbx.Text, progressIndicator);
}
private void ReportProgress(ProgressEventArgsEx args)
{
    this.statusText.Text = args.Text + " " + args.Percentage;
}