2012-02-27 3 views
14

Я пытаюсь изменить прогресс прогресса в процессе изменения хода загрузки WebClient. Этот код все еще загружает файл, но когда я звоню startDownload(), окно зависает, когда оно загружает файл. Я хотел бы, чтобы пользователь мог видеть изменение хода работы при загрузке заставки. Есть ли способ исправить это, чтобы пользователь мог увидеть ход изменения progressBar2?Asynchronous File Download with Progress Bar

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

Если окно зависает, это означает, что человек загружается в потоке пользовательского интерфейса, что означает, что ваш код является синхронным, а не асинхронным. – Joakim

+0

Я вызываю 'startDownload()' через фоновый рабочий, работающий асинхронно. Это не должно заставлять замораживать окно, верно? –

+6

Пожалуйста, не прикрепите свои заголовки к «C#» и тому подобное. Для этого нужны теги. –

ответ

9

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

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

+0

Спасибо, я не понял, что не смог бы начать загрузку через другой асинхронный поток. Сейчас все работает нормально. –

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».

+0

Я уже последовали за этой статьей, которая привела к той же проблеме. –

+2

Используете ли вы свою функцию, чтобы показывать ход загрузки из фонового потока? Если это так, вы должны запустить его в потоке пользовательского интерфейса, но подключите к нему функцию прогресса рабочего фона. Надеюсь, это может помочь. Я все еще делаю чтение, касающееся проблемы, с которой вы так надеетесь, я мог бы придумать другое решение. – SMT

18

UI Тема будет замораживаться, когда вы нажимаете startDownload(). Если вы не хотите, чтобы форма формы зависала, вы используете startDownload() в другом потоке и обновляете прогресс в кросс-threaded. Один из способов,

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

-fixed отсутствующего близко); к объявлению bgThread

+0

MethodInvoker не входит в мою программу, что мне делать –

+1

BeginInvoke находится в пространстве имен WinForms. Если вы используете WPF, вы должны использовать Dispatcher.BeginInvoke – Tsukasa

+0

Используя приведенный выше код, чтобы загрузить файлы, но я не могу подключиться к удаленной ошибке сервера. –