2

我对 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){}会导致冻结。是否有锁定或易失性的某些属性(除了我已经拥有的)或者我是否处于 Silverlight 页面生命周期的错误部分或其他什么?

我真的很困惑为什么这不起作用。

另外,这是silverlight 3.0

4

4 回答 4

5

很可能,此代码在处理所有 Web 浏览器与用户交互的 UI 线程中运行。这就是为什么您不会发现任何阻塞操作的原因 - 因为任何阻塞都会以与您看到的完全相同的方式冻结 UI!更重要的是,如果 UI 线程还处理网络 IO(这很常见),那么您将在这里死锁,因为您正在等待的异步操作永远不会完成。

恐怕您只需将代码重写为由异步操作驱动的状态机。

于 2009-11-03T01:57:55.843 回答
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));
}
于 2009-11-03T09:15:16.257 回答
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.";

    }
于 2009-11-03T12:48:28.133 回答
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 在该处理程序返回之前无法更新。

于 2009-11-03T02:10:34.727 回答