2011-03-26 88 views
1

我在写一个必须访问MySQL数据库的程序。为此,我编写了一个PHP WebService以获取表中的所有值。我遇到的问题是我正在用C#编写一个函数来获取这些值。我希望函数等待,直到调用DownloadStringCompleted事件的事件处理程序,然后返回值。我这样做:System.Net.WebClient问题

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应用程序,任何帮助将不胜感激。

回答

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事件处理程序中更新你的模型 - 这样你就不必使用拐杖,你的应用程序的性能会更好。

+0

与调用方法的阻塞版本不同:webClient.DownloadString(new Uri(“http://google.com”)); ??? – 2011-03-26 23:48:04

+2

@Mitch - 是的但在Silverlight afaik中不支持 - 这是启用同步请求的拐杖,但正如评论中提到的,OP应该采用异步方法,而不是尝试查找解决方法。 – BrokenGlass 2011-03-26 23:49:33

+0

啊,SilverLight!错过了那一点。 – 2011-03-26 23:50:28

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。