c#downloadfileasync等待没有冻结ui

时间:2015-02-15 10:27:54

标签: c# .net multithreading winforms

问题很简单,但我还没找到任何具体的文章。 我希望能够下载异步文件,等到它完成,显示进度条,然后从我在主线程中的位置继续,而不是从filecompleted引发的事件。我需要将文件下载为异步,因为我需要显示进度条。我被迫使用.NET 2.0。

我找到的所有页面都解决了这个问题,只需将DownloadFileAsync作为最后一个命令运行,所以没有什么可以运行了...这种方式很简单,因为执行"继续"当downloadfile完成时触发。总而言之,我搜索的所有样本都是这样工作的。

但我需要的是保留在主线程上,等待,让downloadprogresschanged访问UI以更新进度条,然后从那里继续。

这样的事情:

private ManualResetEvent myMREDown = new ManualResetEvent(false);

WebClient myClient = new WebClient();
myClient.DownloadProgressChanged += new DownloadProgressChangedEventHandler(myClient_DownloadProgressChanged);
   myClient.DownloadFileCompleted += new AsyncCompletedEventHandler(myClient_DownloadFileCompleted);

myClient.DownloadFileAsync(SomeURL);
mre_DownloadingFile.WaitOne();
ContinueDoingSomethingElse(); // <-- I want to reach THIS point after download

void myClient_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
  {
//update the progress bar
}

void myClient_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
  {
mre_DownloadingFile.Set();
}

现在,我的问题是:

A)一般来说,如果我只运行DownloadFileAsync,我理解下载发生在一个单独的线程中,因为如果我之后再编写一些代码,它将在不等待DownloadFileAsync完成的情况下运行...但是,如果我从我的主线程WaitOne(),那下载线程似乎挂起,因为它没有显示任何进度条...所以...它在我的一个单独的线程上或不? ?

B)如果我将整个下载过程包装到一个方法然后我使用Start New Thread()来运行它,然后我使用ManualResetEvent Waitone(),UI冻结了同样的...

C)最重要的是......有没有出路???? (请提供代码,如果可能的话)

1 个答案:

答案 0 :(得分:1)

好的,我深入研究了这个问题,所以我会回复自己,我希望这会帮助其他人同样怀疑。

数目:

  

A)一般来说,如果我只是运行DownloadFileAsync,我明白了   下载发生在一个单独的线程中,因为如果我写一些   之后更多的代码,它将无需等待即可运行   DownloadFileAsync完成...但是,如果我从我的主要WaitOne()   线程,下载线程似乎挂起,因为它没有显示   任何进度条...所以...它与我的一个单独的线程或不是   ???

问题是:你不能在主UI线程上等待。这意味着当您运行程序时,它通常在一个可以访问UI的线程上运行。所以,无论你做什么以及如何做,如果你在那里WaitOne(),你的UI将会冻结。没有出路。保持原样。 当您运行DownloadFileAsync时,它会SPAWNS一个新线程,但是从那里开始,您正在尝试更新主线程上的进度条,如果该线程正在等待,它将无法执行任何操作。所以问题是,你不能在主线程上等待。

  

B)如果我将整个下载过程包装到一个方法然后我使用   启动New Thread()来运行它,之后我使用ManualResetEvent   用户(),用户界面冻结了同样的......

原因与A)点相同 - 即使你开始一个新的线程,但是你在主线程UI上等待,你也无法去任何地方。

  

C)最重要的是......有没有出路???? (请提供代码,   如果可能的话)

是的,解决方案是:以不同的方式思考您的计划。由于你不能在那里等待,你需要重新编码所有内容,以便你必须能够运行asyncdownload,放弃你在那之前所做的程序逻辑,并在其他地方继续它(在我的情况下从DownloadFileCompleted事件)。例如,您可以在新线程上运行所有内容,使用委托更新进度条(因此它们将从正确的线程调用UI更新),然后从这个新线程中您甚至可以使用Wait(),因为这样将把等待放在一个单独的线程上,这不是主线程。

在我的情况下,我有一个要执行的命令列表...所以我首先创建了一个Queue并在那里添加了所有命令,然后我创建了一个方法“RunNextCommand”,它使Element出列并运行命令,如果有的话命令是“downloadafile”,然后我只运行asyncdownload,并从DownloadFileCompleted事件中再运行一次“RunNextCommand”。

这样你就不会使用DoEvents()(这总是一个非常糟糕的主意),你的CPU不能100%运行,你的代码很漂亮干净; - )

谢谢你。我很受欢迎。再见。