我对silverlight很新,并且非常惊讶地发现只能进行异步文件下载。好吧,我试图通过设置一个标志并等待它改变来反击这个行为。 这是我的简单代码
void MainPage_Loaded(object sender, RoutedEventArgs e)
{
WebClient webClient = new WebClient();
webClient.DownloadProgressChanged +=
new DownloadProgressChangedEventHandler(webClient_DownloadProgressChanged);
webClient.OpenReadCompleted += new OpenReadCompletedEventHandler(webClient_OpenReadCompleted);
webClient.OpenReadAsync(new Uri("/trunk/internal/SilverLightInterface.ashx?xxid=XXX", UriKind.Relative));
while (XmlStateStream == null) { }
lblProgress.Content = "Done Loading";
}
void webClient_DownloadProgressChanged(object sender,
DownloadProgressChangedEventArgs e) {
lblProgress.Content = "Downloading " + e.ProgressPercentage + "%";
}
volatile Stream XmlStateStream = null;
void webClient_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
{
if (e.Error != null)
{
lblProgress.Content = "Error: " + e.Error.Message;
return;
}
XmlStateStream = e.Result;
}
这导致Firefox实际冻结(当我在开发时做其他事情时非常讨厌)(顺便说一句,对firefox的称赞导致我测试它并且firefox冻结了,但我没有丢失我输入的内容在恢复之后)
我不明白为什么while(XmlStateStream==null){}
导致冻结。锁或volatile是否有某些属性(除了我已有的属性)或者我在Silverlight页面生命周期的错误部分还是什么?
我真的很困惑为什么这不起作用。
此外,这是silverlight 3.0
答案 0 :(得分:5)
最有可能的是,此代码在UI线程中运行,该线程处理所有Web浏览器与用户的交互。这就是为什么你不会发现任何阻塞操作的原因 - 因为任何阻塞都会以与你看到的完全相同的方式冻结UI!更重要的是,如果UI线程也处理网络IO(这是常见的),那么你将在这里死锁,因为你正在等待的异步操作永远不会完成。
我担心你只需将代码重写为由异步操作驱动的状态机。
答案 1 :(得分:2)
虽然您需要在Silverlight中使用异步特性,但您可以使用C#3语法将事情保持在一起: -
void MainPage_Loaded(object sender, RoutedEventArgs e)
{
DownloadXmlStateStream();
}
void DownloadXmlStateStream()
{
WebClient webClient = new WebClient();
webClient.DownloadProgressChanged += (s, e) => {
lblProgress.Content = "Downloading " + e.ProgressPercentage + "%";
}
webClient.OpenReadCompleted += (s, e) => {
if (e.Error != null)
{
lblProgress.Content = "Error: " + e.Error.Message;
}
else
{
XmlStateStream = e.Result;
lblProgress.Content = "Done Loading";
}
}
webClient.OpenReadAsync(new Uri("/trunk/internal/SilverLightInterface.ashx?xxid=XXX", UriKind.Relative));
}
答案 2 :(得分:0)
您需要使用DownloadFileCompleted
事件。
删除此:
while (XmlStateStream == null) { }
lblProgress.Content = "Done Loading";
添加:
webClient.DownloadFileCompleted +=
new DownloadFileCompletedEventHandler(webClient_DownloadFileCompleted);
和此:
void webClient_DownloadFileCompleted(object sender, AsyncCompletedEventHandler) {
lblProgress.Content = "Done Loading";
}
如果您确实必须进行同步下载,则需要“轮询”下载完成的次数较少。尝试从忙碌等待循环中拨打System.Threading.Thread.Sleep()
,延迟50-250毫秒。
虽然这会减少代码浪费的CPU利用率,但它可能无法修复UI响应问题。这取决于调用您的MainPage_Loaded
的线程是否是唯一可以调用UI更新事件的线程。如果是这种情况,那么在该处理程序返回之前,UI根本无法更新。
答案 3 :(得分:0)
通过阻止直到文件下载,你不仅要阻止你的silverlight应用程序的UI线程 - 你也会阻止浏览器的UI线程,看起来就像。
你真正想做的事(我认为)就是停止你的应用程序做任何事情,直到下载完成。尝试将此行添加到MainPage_Loaded:
LayoutRoot.IsHitTestVisible = false;
删除阻止while循环和完成的消息(最后两行)。
在webClient_OpenReadCompleted中,添加:
LayoutRoot.IsHitTestVisible = true;
lblProgress.Content = "Done Loading.";
一切都应该按我想要的方式运作。
这是完整的代码:
void MainPage_Loaded(object sender, RoutedEventArgs e)
{
WebClient webClient = new WebClient();
webClient.DownloadProgressChanged +=
new DownloadProgressChangedEventHandler(webClient_DownloadProgressChanged);
webClient.OpenReadCompleted += new OpenReadCompletedEventHandler(webClient_OpenReadCompleted);
webClient.OpenReadAsync(new Uri("/trunk/internal/SilverLightInterface.ashx?xxid=XXX", UriKind.Relative));
LayoutRoot.IsHitTestVisible = false;
}
void webClient_DownloadProgressChanged(object sender,
DownloadProgressChangedEventArgs e) {
lblProgress.Content = "Downloading " + e.ProgressPercentage + "%";
}
void webClient_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
{
if (e.Error != null)
{
lblProgress.Content = "Error: " + e.Error.Message;
return;
}
LayoutRoot.IsHitTestVisible = true;
lblProgress.Content = "Done Loading.";
}