ブロック/同期的な方法でファイルをダウンロードするには?
-
12-09-2019 - |
質問
私は、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です。
解決
ほとんどの場合、このコードは、ユーザとWebブラウザの相互作用のすべてを扱うUIスレッドで実行されています。何そのため、ブロックはあなたが見たまったく同じ方法でUIを凍結する - あなたはどのブロック操作を見つけることができません理由はここにあります! UIスレッドでも(一般的です)ネットワークIOを処理する場合、あなたが待機している非同期操作が終了しませんので、多くはである何、あなたはここにデッドロックでしょう。
私はあなただけの非同期操作によって駆動ステートマシンとして、あなたのコードを書き換える必要があります怖います。
他のヒント
あなたはもう少し一緒に物事を保つためにC#3の構文を使用することができますSilverlightの物事の非同期性を取得する必要がなくなり: -
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));
}
あなたはDownloadFileCompleted
イベントを使用する必要があります。
これを削除します:
while (XmlStateStream == null) { }
lblProgress.Content = "Done Loading";
これを追加します:
webClient.DownloadFileCompleted +=
new DownloadFileCompletedEventHandler(webClient_DownloadFileCompleted);
これます:
void webClient_DownloadFileCompleted(object sender, AsyncCompletedEventHandler) {
lblProgress.Content = "Done Loading";
}
あなたが本当に同期ダウンロードを持っている必要があります場合は、、あなたはダウンロードが少なく、多くの場合、完全であることのための「世論調査」にする必要があります。あなたのビジー待機ループ内から50-250ms遅れてSystem.Threading.Thread.Sleep()
を呼び出してみます。
これはあなたのコードの無駄なCPU使用率を削減しますが、それはそれはUIの応答性の問題を解決しないことが可能です。それはあなたのMainPage_Loaded
を呼び出しているスレッドがUIの更新イベントを呼び出すことができる唯一のものであるかどうかに依存します。その場合は、その後、UIは、単純にそのハンドラが戻るまで更新することができません。
ファイルがダウンロードされるまでブロックすることで、あなたのSilverlightのアプリのUIスレッドをブロックしているだけでなく、 - あなたはまた、ブラウザのUIスレッドをブロックしている、それが思わ
。あなたが本当に(私は推測)やりたいことのすべては、ダウンロードが完了するまで何もしてあなたのアプリを停止しています。 MainPage_Loadedに次の行を追加してみてください。
LayoutRoot.IsHitTestVisible = false;
ループと完了メッセージ(最後の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.";
}