はじめに
Silverlight では、コントロールにバインドされた ObservableCollection を、非同期に操作したいケースがよくあります。
例えば、サービス呼出しの結果を反映させたいときとか。Silverlight の通信は非同期が基本なので。
MSDN マガジンに参考記事があります!
非同期通信を行い、処理結果を ObservableCollection に反映させるサンプルが MSDN マガジンにあります。
Silverlight アプリケーションを MVVM で作成する記事。Silverlight2 のときの記事だけど、Silverlight3 でも使えるハズ。
ところが…
この記事を参考に、非同期で取得したデータを ObservableCollection に追加するために
Application.Current.RootVisual.Dispatcher.BeginInvoke(() => { // ObservableCollection の操作 this.Items.Add(data); });
と記述したら、例外が発生。
デバッガで追ってみたところ、RootVisual プロパティにアクセスした時点で例外が発生してました。
UI スレッド外から RootVisual プロパティにアクセスした時点でアウト!
この問題を回避する方法
非同期処理を開始する前に、Dispatcher への参照を保存しておけばいいです。
// Dispatcher 保存 Dispatcher rootDispatcher = Application.Current.RootVisual.Dispatcher; // 非同期処理スタート WebRequest request = WebRequest.Create(WEB_API_URL); request.BeginGetResponse(result => { WebResponse response = request.EndGetResponse(result); using(Stream stream = response.GetResponseStream()) { XmlSerializer serializer = new XmlSerializer(typeof(Foo)); Foo data = (Foo)serializer.Deserialize(stream); // UI スレッド上で ObservableColelction を操作する。 // Items は ObservableCollection<Foo> 型。 // 保存しておいた Dispatcher を使用。 rootDispatcher.BeginInvoke(() => { this.Items.Add(data); }); } }, request);
RootVisual の Dispatcher は、スタティック変数に代入しておいて、プロジェクト全体で使い回せばいいと思います。