Асинхронная загрузка файлов с индикатором выполнения - PullRequest
21 голосов
/ 27 февраля 2012

Я пытаюсь изменить индикатор выполнения при изменении хода загрузки 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 ]

24 голосов
/ 27 февраля 2012

Поток пользовательского интерфейса будет зависать при нажатии startDownload () .Если вы не хотите замораживать форму, вы используете 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

13 голосов
/ 27 февраля 2012

Вы должны позвонить startDownload() из потока пользовательского интерфейса. Идея WebClient.DownloadFileAsync() заключается в том, что он автоматически создаст для вас рабочий поток, не блокируя вызывающий поток. В startDownload() вы указали обратные вызовы, которые изменяют элементы управления, которые, как я полагаю, были созданы потоком пользовательского интерфейса. Таким образом, если вы вызовете startDownload() из фонового потока, это вызовет проблемы, поскольку поток может изменять только созданные им элементы пользовательского интерфейса.

Способ, которым он должен работать, заключается в том, что вы вызываете startDownload() из потока пользовательского интерфейса, startDownload(), так как вы определили, что он устанавливает обратные вызовы событий, которые обрабатываются потоком пользовательского интерфейса. Затем он начинает загрузку асинхронно и сразу же возвращается. Поток пользовательского интерфейса будет уведомлен об изменении хода выполнения, и код, отвечающий за обновление элемента управления индикатором выполнения, будет выполнен в потоке пользовательского интерфейса, и проблем быть не должно.

2 голосов
/ 01 апреля 2018
 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;
}
1 голос
/ 27 февраля 2012

Я считаю, что эта статья приведет вас в правильном направлении 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».

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...