2009-11-03 3 views
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){} вызывая замерзание. Есть ли какой-либо атрибут для блокировок или volatile (кроме того, что у меня уже есть), или я не в той части жизненного цикла страницы Silverlight или что-то в этом роде?

Я действительно смущен, почему это не работает.

Кроме того, это Silverlight 3.0

+0

При программировании в управляемых событиях UI (т. Е Silverlight), вы всегда должны использовать замещающие асинхронные методы, когда у вас есть тяжелые рабочие нагрузки. Почему вы должны делать это синхронно? –

ответ

5

Скорее всего, этот код выполняется в потоке пользовательского интерфейса, который обрабатывает все взаимодействия веб-браузера с пользователем. Вот почему вы не обнаружите никаких блокирующих операций, потому что все, что блокирует, заморозит пользовательский интерфейс точно так же, как вы видели! Более того, если поток пользовательского интерфейса также обрабатывает сетевой IO (что является общим), тогда вы зашли в тупик, потому что асинхронная операция, которую вы ожидаете, никогда не завершится.

Боюсь, вам просто придется переписать свой код как конечный автомат, управляемый асинхронными операциями.

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 мс из цикла «Занят-ожидание».

Несмотря на то, что это уменьшит нерациональное использование вашего кода в коде, возможно, он не исправит проблему реагирования пользовательского интерфейса. Это зависит от того, является ли поток, вызывающий ваш MainPage_Loaded, единственным, который может вызывать события обновления интерфейса. Если это так, то пользовательский интерфейс просто не может обновляться до тех пор, пока этот обработчик не вернется.

+0

Это не загрузка синхронной манеры, правда, сейчас? Я подозреваю, что реальный код OP намного сложнее, чем пример здесь ...:/ – bdonlan

+0

Тем не менее, это то, что должен делать OP. На самом деле я подозреваю, что синхронный запрос буквально невозможно, потому что загрузка может происходить в другом потоке. Независимо от сложности, это управляемая событиями система и попытка написать процедурный, синхронный код никогда не будет работать хорошо. Может быть забавно ответить «Как стрелять себе в ногу» с пистолетными наконечниками, но иногда «не надо» - лучший совет. –

+0

Я только начал писать программу, но для меня это было «естественным» способом, чтобы попытаться написать ее. Я думаю, что вещи должны быть немного сложнее, поэтому они могут быть более параллельными/отзывчивыми, хотя .. Я просто буду чтобы настроить (даже больше!) на программирование Silverlight .. Я не знал, что в Silverlight происходит много многопотоков (не так уж мало, так как загрузка происходит в потоке пользовательского интерфейса) – Earlz

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)); 
} 
+0

Анонимные функции .. .hmm хорошо, это удобно, я не знал, что вы можете это сделать полностью – Earlz

0

Блокируя, пока файл не будет загружен, вы не только блокирует поток пользовательского интерфейса вашего приложения silverlight - вы также блокируете поток пользовательского интерфейса браузера.

Все, что вы действительно хотите сделать (я полагаю), прекратит ваше приложение делать что-либо, пока загрузка не завершится.Попробуйте добавить эту строку в MainPage_Loaded:

LayoutRoot.IsHitTestVisible = false; 

Снимите блокировку в то время как петля и завершенное сообщение (последние две строк).

В 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."; 

    } 
Смежные вопросы