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がフリーズしたので、Firefoxに敬意を表しますが、復元後にここに入力した内容は失われませんでした)。

while(XmlStateStream==null){}なぜフリーズが発生しているのかわかりません。ロックまたは揮発性(私がすでに持っているもの以外)の属性がありますか、それともSilverlightページのライフサイクルの間違った部分にいますか?

なぜこれが機能しないのか、私は本当に混乱しています。

また、これはSilverlight3.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

You need to use the DownloadFileCompleted event.

delete this:

while (XmlStateStream == null) { }
lblProgress.Content = "Done Loading";

add this:

webClient.DownloadFileCompleted +=
    new DownloadFileCompletedEventHandler(webClient_DownloadFileCompleted);

and this:

void webClient_DownloadFileCompleted(object sender, AsyncCompletedEventHandler) {
    lblProgress.Content = "Done Loading";
}

If you really must have synchronous downloading, you need to "poll" for the download being complete less often. Try calling System.Threading.Thread.Sleep() with a delay of 50-250ms from within your busy-wait loop.

Although this will reduce the wasteful CPU utilization of your code, it's possible that it will not fix the UI responsiveness problem. It depends on whether the thread that's calling your MainPage_Loaded is the only one that can call UI update events. If that's the case, then the UI simply can not update until that handler returns.

于 2009-11-03T02:10:34.727 に答える
0

ファイルがダウンロードされるまでブロックすることで、SilverlightアプリのUIスレッドをブロックするだけでなく、ブラウザーのUIスレッドもブロックしているように見えます。

あなたが本当にやりたいのは(私が思うに)ダウンロードが完了するまでアプリが何かをするのをやめることだけです。次の行をMainPage_Loadedに追加してみてください。

LayoutRoot.IsHitTestVisible = false;

ブロッキングwhileループと完了したメッセージ(最後の2行)を削除します。

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 に答える