使用WebClient下载文件时UI冻结
本文关键字:UI 冻结 文件 WebClient 下载 使用 | 更新日期: 2023-09-27 18:20:38
我正在尝试使用WebClient.DownloadFileAsync-Method下载一些文件。只要用户界面没有显示,它就可以正常工作。
UI是一个带有标签和进度条的表单。
在DownloadProgressChanged事件中,我想显示当前进度。为了做到这一点,我调用了一个带有int参数的方法。以下是下载的方法:
private void DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
if(progressDialog!=null){
progressDialog.setFileProgress(e.ProgressPercentage);
}
Trace.WriteLine(String.Format("downloaded {0} of {1} bytes. {2} % complete...",
e.BytesReceived,
e.TotalBytesToReceive,
e.ProgressPercentage));
}
private void DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
{
if(progressDialog!=null){
progressDialog.setFileProgress(100);
}
are.Set();
}
private AutoResetEvent are = new AutoResetEvent(false);
public void DownloadFiles(List<DownloadObject> objects){
Trace.WriteLine("Start Download");
wc.DownloadProgressChanged += DownloadProgressChanged;
wc.DownloadFileCompleted += DownloadFileCompleted;
try{
foreach(DownloadObject dlo in objects){
currentFile = dlo;
String url = dlo.DownloadURL;
String path = dlo.LocalPath;
Uri uri = new Uri(url);
//GET
Thread thread = new Thread(() => wc.DownloadFileAsync(uri,path));
//thread.SetApartmentState(ApartmentState.STA);
thread.Start();
are.WaitOne();
DeleteFile(dlo.ID);
}
Trace.WriteLine("FileDownload finished");
}catch(Exception ex){
Trace.WriteLine("FileDownload failed: "+ex.Message);
}finally{
wc.Dispose();
}
}
以下是ProgressDialog窗体中的相关方法:
public delegate void dummy();
public void setFileProgress(int progress){
if(prgFile.InvokeRequired){
Trace.WriteLine("Invoke required");
prgFile.Invoke(new dummy(() => prgFile.Value = progress));
}else{
Trace.WriteLine("Invoke not required");
prgFile.Value = progress;
}
}
public static ProgressDialog getInstance(IWin32Window owner){
ProgressDialog pd = new ProgressDialog();
//pd.Show(owner); //
return pd;
}
现在发生的是:如果没有调用pd.Show(),一切都很好。进度被更改,我得到了输出"Invokenotrequired"以及下载的每一步。
但是,如果调用了pd.Show(),我会多次获得输出"Invoke-required",其间没有任何下载消息。
因此,我调试了这部分代码,似乎调用了progressDialog.setFileProgress(),但在调用prgFile.Invoke-method后,DownloadProgressChanged事件再次直接触发。
如果我将Invoke调用切换到BeginInvoke,我会再次获得所有正确的消息,但ProgressDialog会冻结,直到所有下载完成,并且我没有显示任何进度。
我在那里错过了什么?我读了很多关于这方面的问题和线索,但无法让它运行起来。
我正在将SharpDevelop与.Net Framework 4.0 一起使用
因为"DownloadFiles"方法是同步的,它会阻塞UI线程。你启动了一个新的线程来下载文件,但
are.WaitOne();
阻止当前线程(UI线程),直到CCD_ 1被设置为止(在下载完成事件中)。
正确的解决方案是将下载后的工作(例如DeleteFile)放在完整事件中。
因为DownloadFiles
-方法是同步的,并且在UI线程中运行。因此,如果执行该方法,则UI线程将被阻塞,直到该方法完成。
有两种方法:
多线程
只要让该方法在不同的任务中运行,就会解决UI冻结问题。然而,正如您所提到的,在您的情况下,这将是一种可怕的方法,因为您无法跨线程操作UI。如果你想更新状态,你不应该这样做。
异步/等待
这里有更好的方法。虽然看起来很简单,但async/await实际上很难做到正确。互联网上有很多资源,我建议从dotnetperls开始,这是对async/await的详细介绍。这需要一些时间,但这无疑是最好的方法。