1

Windows8の「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
}

info.TextWebRequestから返されたデータで更新したいのですが、 「アプリケーションが別のスレッド用にマーシャリングされたインターフェイスを呼び出しました」というエラーが発生します。これは、UIスレッドから呼び出されていないためだと理解しています。

私はDispatcher、、、キーワードを含むさまざまな異なる解決策を見つけました。SynchronizationContextawait

これを行うための最も簡単/最良の方法は何ですか?

4

3 に答える 3

4

Damirが言ったように、実際にはasync / awaitパターンを使用する必要がありますが、ワーカースレッド(タスク)でUIを更新する必要がある場合もあります。これは、呼び出しをUIスレッドにディスパッチする現在のCoreDispatcherを使用して行われます。

private void ResponseCallback(IAsyncResult asyncResult)
{
   ...

   this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
   {
      info.Text = responseString;
   });
}
于 2012-11-29T07:02:47.730 に答える
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バウンド操作は、非同期フレーバーで利用できます。ReadToEndAsync上記の例のように、UIスレッドのブロックを防ぐために両方が使用可能な場合でも、同期のものよりもそれらを優先する必要があります。

于 2012-11-29T05:40:56.707 に答える
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 / WinRTSynchronizationContextは、を使用しDispatcherます。

于 2012-11-29T01:35:09.807 に答える