System.Net.WebClient问题

时间:2011-03-26 23:37:44

标签: c# silverlight webclient

我正在编写一个必须访问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 个答案:

答案 0 :(得分:3)

您可以使用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();

这回答了你的问题,但它仍然会让UI线程等待 - 你真的必须接受与Silverlight的异步,所以努力寻找一个在DownloadStringCompleted事件处理程序中更新你的模型的解决方案 - 这样你就不会不得不使用拐杖,你的应用程序会表现得更好。

答案 1 :(得分:2)

您可以使用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;
}

请注意,阻止主线程是一种不好的做法,因为它会冻结UI。更好的方法是在下载完成的事件处理程序中简单地处理结果。并且因为此处理程序在不同于UI线程的线程上执行,所以不要忘记编组将UI更新到主线程的任何调用。

推荐示例:

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

这样您就不再阻止主线程,UI仍然流畅。异步操作完成后,通过使用Dispatcher.BeginInvoke方法对UI线程的调用进行编组来更新UI结果。