Come scaricare i file in modo blocco / sincrono?
-
12-09-2019 - |
Domanda
Sono abbastanza nuovo a Silverlight e sono rimasto molto sorpreso di vedere che solo il download di file asincrono può essere fatto. Beh, ho cercato di contrastare questo agire semplicemente impostando una bandiera e in attesa su di esso per cambiare .. Questo è il mio semplice codice
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;
}
Questo sta causando Firefox per congelare in realtà verso l'alto (il che è estremamente fastidioso quando sto facendo altre cose mentre in via di sviluppo) (a proposito, complimenti a firefox perché ho provato e Firefox congelato, ma non ho perso quello che stavo scrivendo qui dopo il ripristino)
Non capisco il motivo per cui il while(XmlStateStream==null){}
sta causando un blocco su. C'è qualche attributo per serrature o volatili (diverso da quello che ho già) o sto nella parte sbagliata del ciclo di vita pagina Silverlight o qualcosa del genere?
Sono molto confusa sul motivo per cui questo non sta funzionando.
Inoltre, questo è Silverlight 3.0
Soluzione
Molto probabilmente, questo codice è in esecuzione in thread dell'interfaccia utente che gestisce tutte le interazioni del browser Web con l'utente. Questo è il motivo per cui non troverete alcuna operazione di blocco - perché tutto ciò che blocca congelare l'interfaccia utente esattamente nello stesso modo in cui avete visto! Cosa c'è di più, se il thread dell'interfaccia utente gestisce anche reti IO (che è comune), allora ti deadlock qui perché l'operazione asincrona siete in attesa sulla non potrà mai finire.
Ho paura che vi resta che riscrivere il codice come una macchina a stati guidata da operazioni asincrone.
Altri suggerimenti
Mentre è necessario per ottenere con la natura asincrona delle cose in Silverlight è possibile utilizzare C # 3 sintassi per mantenere le cose un po 'più insieme: -
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));
}
È necessario utilizzare l'evento DownloadFileCompleted
.
cancellare questo:
while (XmlStateStream == null) { }
lblProgress.Content = "Done Loading";
aggiungere questo:
webClient.DownloadFileCompleted +=
new DownloadFileCompletedEventHandler(webClient_DownloadFileCompleted);
e questo:
void webClient_DownloadFileCompleted(object sender, AsyncCompletedEventHandler) {
lblProgress.Content = "Done Loading";
}
Se davvero necessario avere scaricano sincrono, è necessario "sondaggio" per il download essere completo meno spesso. Prova a chiamare System.Threading.Thread.Sleep()
con un ritardo di 50-250ms all'interno del tuo ciclo busy-wait.
Anche se questo riduce l'utilizzo della CPU spreco di codice, è possibile che non risolverà il problema di interfaccia utente di risposta. Dipende se il filo che sta chiamando il vostro MainPage_Loaded
è l'unico che può chiamare gli eventi di aggiornamento dell'interfaccia utente. Se questo è il caso, allora l'interfaccia utente semplicemente non può aggiornare fino a che restituisce gestore.
Con il blocco fino a quando il file viene scaricato, non sei solo bloccare il thread UI del vostro silverlight app -. Si sta anche bloccando il thread dell'interfaccia utente del browser, sembrerebbe
Tutto quello che vuole veramente fare (presumo) è smettere la vostra applicazione di fare qualsiasi cosa fino al completamento del download. Prova ad aggiungere questa riga a MainPage_Loaded:
LayoutRoot.IsHitTestVisible = false;
Rimuovere il blocco ciclo while e il messaggio completato (le ultime due righe).
In webClient_OpenReadCompleted, aggiungere:
LayoutRoot.IsHitTestVisible = true;
lblProgress.Content = "Done Loading.";
E tutto dovrebbe funzionare il mio modo di pensare che si desidera.
Ecco il codice completo:
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.";
}