我在Windows 8“Metro”应用程序中有一个按钮和一个文本块。单击该按钮时,它通过HttpWebRequest调用Web服务。
private void buttonGo_Click(object sender, RoutedEventArgs e)
{
HttpWebRequest req = (HttpWebRequest)WebRequest.Create("http://localhost/");
req.BeginGetResponse(ResponseCallback, req);
}
private void ResponseCallback(IAsyncResult asyncResult)
{
HttpWebRequest req = (HttpWebRequest)asyncResult.AsyncState;
HttpWebResponse res = (HttpWebResponse)req.EndGetResponse(asyncResult);
Stream streamResponse = res.GetResponseStream();
StreamReader streamRead = new StreamReader(streamResponse);
string responseString = streamRead.ReadToEnd();
info.Text = responseString; // Can't do this as outside the UI thread
}
我想使用从WebRequest返回的数据更新info.Text
,但是它会导致错误:“应用程序调用了为不同线程编组的接口。”我理解这是因为它没有从UI线程调用。
我找到了涉及Dispatcher
,SynchronizationContext
,await
关键字的各种不同解决方案。
最简单/最好的方法是什么?
答案 0 :(得分:4)
像Damir一样,我们确实应该使用async / await模式,但有时只需更新工作线程(任务)中的UI。这是使用当前的CoreDispatcher完成的,该调度将调用分派给UI线程:
private void ResponseCallback(IAsyncResult asyncResult)
{
...
this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
info.Text = responseString;
});
}
答案 1 :(得分:2)
在Windows应用商店应用中,您确实应该为所有异步调用使用异步等待模式 - 这是最简单,最有效的方式。您可以重写现有代码以使用此模式,如下所示:
private async void buttonGo_Click(object sender, RoutedEventArgs e)
{
HttpWebRequest req = (HttpWebRequest)WebRequest.Create("http://localhost/");
HttpWebResponse res = (HttpWebResponse)(await req.GetResponseAsync());
Stream streamResponse = res.GetResponseStream();
StreamReader streamRead = new StreamReader(streamResponse);
// all IO operations should be called asynchronously
string responseString = await streamRead.ReadToEndAsync();
info.Text = responseString; // This way the code runs on UI thread
}
每个await关键字之后的代码实际上就像它在回调中一样,但它总是在UI线程上执行,因此您不必担心它。
Windows应用商店应用的API中的所有IO绑定操作都以异步方式提供。你应该更喜欢它们而不是同步的,即使两者都可以防止阻塞UI线程 - 例如上面的ReadToEndAsync
示例。
答案 2 :(得分:1)
最简单,最好:
private async void buttonGo_Click(object sender, RoutedEventArgs e)
{
using (var client = new HttpClient())
{
info.Text = await client.GetStringAsync("http://localhost/");
}
}
在幕后,await
会捕获当前SynchronizationContext
并在该上下文中恢复该方法。 Win8 / WinRT SynchronizationContext
依次使用Dispatcher
。