Как скачивать файлы блокирующим / синхронным способом?

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 фактически зависнуть (что очень раздражает, когда я занимаюсь другими вещами при разработке) (btw, kudos to firefox, потому что я тестировал его, а firefox застыл, но я не потерял то, что я набирал здесь после восстановления)

Я не понимаю, почему while(XmlStateStream==null){} вызывает замораживание. Есть ли какой-либо атрибут для блокировок или volatile (кроме того, что у меня уже есть), или я не в той части жизненного цикла страницы Silverlight или что-то в этом роде?

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

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

  • 0
    При программировании в пользовательском интерфейсе, управляемом событиями (т. Е. Silverlight), вы всегда должны использовать резервные асинхронные методы, когда у вас большая рабочая нагрузка. Почему вы должны делать это синхронно?
Теги:
events
silverlight
blocking
webclient

4 ответа

5
Лучший ответ

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

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

2

В то время как вам нужно получить асинхронный характер вещей в Silverlight, вы можете использовать синтаксис С# 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
    Анонимные функции ... хм, ну, это удобно, я не знал, что вы можете сделать это полностью
0

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

Все, что вы действительно хотите сделать (я полагаю), прекратит ваше приложение делать что-либо, пока загрузка не завершится. Попробуйте добавить эту строку в 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.";

    }
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 намного сложнее, чем пример здесь ...: /
  • 0
    Тем не менее, это то, что ОП должен сделать. На самом деле я подозреваю, что синхронный запрос буквально невозможен, потому что загрузка может происходить в другом потоке. Независимо от сложности, это система, управляемая событиями, и попытка написать процедурный, синхронный код никогда не будет работать хорошо. Может быть забавно отвечать «Как мне выстрелить себе в ногу» кончиками оружия, но иногда «нет» - действительно лучший совет.
Показать ещё 1 комментарий

Ещё вопросы

Сообщество Overcoder
Наверх
Меню