Проблемы System.Net.WebClient - PullRequest
       33

Проблемы System.Net.WebClient

1 голос
/ 27 марта 2011

Я пишу программу, которая должна получить доступ к базе данных MySQL.Для этого я написал PHP WebService, чтобы получить все значения в таблице.Проблема в том, что я пишу функцию на C # для получения этих значений.Я хочу, чтобы функция ожидала вызова обработчика события DownloadStringCompleted, а затем возвращала значения.Я сделал это так:

WebClient client = new WebClient();
client.DownloadStringCompleted += new DownloadStringCompletedEventHandler(DownloadCompletedHandler);
client.DownloadStringAsync(new Uri(Application.Current.Host.Source.AbsoluteUri + "\\PHP\\GetAdmins.php"));
while (DownloadCompleted == false) { }
return DownloadResult;

Но это приводит к зависанию программы.

Мне нужно что-то, что заставит эту часть программы приостановиться, пока DownloadConpleted = true.* Я использую Visual Studio Ultimate 2010, я делаю приложение Silverlight, и любая помощь будет оценена.

Ответы [ 2 ]

3 голосов
/ 27 марта 2011

Вы можете использовать ManualResetEvent - сигнализировать о событии завершения из обработчика завершения загрузки и заставлять главный поток ждать его:

ManualResetEvent completionEvent = new ManualResetEvent(false);
WebClient webClient = new WebClient();
webClient.DownloadStringCompleted +=delegate(object sender, DownloadStringCompletedEventArgs e)
{
    completionEvent.Set();
};

webClient.DownloadStringAsync(new Uri(Application.Current.Host.Source.AbsoluteUri + "\\PHP\\GetAdmins.php"));
completionEvent.WaitOne();

Это отвечает на ваш вопрос, ноэто все равно заставит поток пользовательского интерфейса ждать - вам действительно нужно использовать асинхронность с Silverlight, поэтому работайте над решением, которое обновляет вашу модель в обработчике событий DownloadStringCompleted - таким образом вам не нужно использовать костыли, и ваше приложение будет работатьнамного лучше.

2 голосов
/ 27 марта 2011

Вы можете использовать ManualResetEvent :

public string Download()
{
    var manualEvent = new ManualResetEvent(false);
    WebClient client = new WebClient();
    var result = string.Empty;
    client.DownloadStringCompleted += (sender, e) =>
    {
        if (e.Error != null)
        {
            result = e.Result;
        }
        manualEvent.Set();
    };
    client.DownloadStringAsync(new Uri(Application.Current.Host.Source.AbsoluteUri + "\\PHP\\GetAdmins.php"));
    // block while the download is completed and the event is signaled or
    // timeout after 30 seconds
    if (!manualEvent.WaitOne(TimeSpan.FromSeconds(30)))
    {
        // timeout
    }
    return result;
}

Обратите внимание, что блокировка основного потока является плохой практикой, поскольку он блокирует пользовательский интерфейс.Лучшим способом было бы просто обработать результаты в обработчике события завершения загрузки.И поскольку этот обработчик выполняется в потоке, отличном от потока пользовательского интерфейса, не забудьте маршалировать любые вызовы, которые обновляют пользовательский интерфейс в основном потоке.

Рекомендуемый пример:

public void string Download()
{
    var manualEvent = new ManualResetEvent(false);
    WebClient client = new WebClient();
    client.DownloadStringCompleted += (sender, e) =>
    {
        if (e.Error != null)
        {
            Dispatcher.BeginInvoke(() => 
            { 
                ResultLabel.Text = e.Result; 
            });
        } 
        else 
        {
            Dispatcher.BeginInvoke(() => 
            { 
                ResultLabel.Text = e.Error.ToString(); 
            });
        }
    };
    var url = new Uri(Application.Current.Host.Source.AbsoluteUri + "\\PHP\\GetAdmins.php");
    client.DownloadStringAsync(url);
}

Таким образом, вы больше не блокируете основную резьбу, а пользовательский интерфейс остается текучим.После завершения асинхронной операции вы обновляете пользовательский интерфейс с помощью результата, направляя вызов в поток пользовательского интерфейса с помощью метода Dispatcher.BeginInvoke .

...