我正在编写一个必须访问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应用程序,我们将不胜感激。
答案 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结果。