コントロールの使い方ばかりを書くのも飽きてきたので趣向を変えていきます。
DispatcherObject
WPFでは、他のUIフレームワークと同様にUIを操作するには専用のスレッドから操作をする必要があります。WPFでは、この操作を簡単にするためにDispatcherという仕組みを提供しています。WPFの継承階層を上へ上へたどっていくとDispatcherObjectというクラスに必ず当たります。このクラスにはDispatcherというプロパティが定義されていて、このオブジェクトが生成されたスレッドから操作されているかをチェックする仕組みや、オブジェクトが生成されたスレッドで処理のキューイングを行う仕組みを提供しています。
DispatcherObjectで提供される主な機能を以下に示します。 |プロパティ名|説明| |----------|----| |public Dispatcher Dispatcher { get; }|DispatcherObjectに紐づけられたスレッドに対応するDispatcherオブジェクトを取得します。|
メソッド名 | 説明 |
---|---|
public void VerifyAccess() | 現在のスレッドがDispatcherObjectに紐づけられたスレッドかどうかチェックします。チェックの結果異なるスレッドの場合InvalidOperationExceptionの例外をスローします。 |
public bool CheckAccess() | 現在のスレッドがDispatcherObjectに紐づけられたスレッドかどうかチェックします。チェックの結果異なるスレッドの場合falseを返します。 |
これらの機能の使い方についてのサンプルプログラムを以下に示します。 DispatcherObjectは抽象クラスなので、継承してメソッドを1つもつクラスを作成しました。メソッド内では、VerifyAccessメソッドを使って有効なスレッドからのアクセスかどうかを確認して、デバッグウィンドウへメッセージを出力しています。
publicclass DrivedObject : DispatcherObject { publicvoid DoSomething() { // UIスレッドからのアクセスかチェックするthis.VerifyAccess(); Debug.WriteLine("DoSomething"); } }
Windowに3つのボタンを置いて、UIスレッドからの直接呼出し、UIスレッド以外からの呼び出し、UIスレッド以外からDispatcher経由での呼び出しの3パターンの呼び出しを確認します。
<Window x:Class="DispatcherObjectSample01.MainWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"Title="MainWindow"Height="350"Width="525"><StackPanel><Button Content="UIスレッドからなのでOK"Click="OKButton_Click" /><Button Content="UIスレッド以外から呼ぶのでNG"Click="NGButton_Click" /><Button Content="UIスレッド以外からDispatcher経由で呼ぶのでOK"Click="DispatcherButton_Click" /></StackPanel></Window>
privatevoid OKButton_Click(object sender, RoutedEventArgs e) { // UIスレッドからの普通の呼び出しなのでOK var d = new DrivedObject(); d.DoSomething(); } private async void NGButton_Click(object sender, RoutedEventArgs e) { // UIスレッド以外からの呼び出しなので例外が出る var d = new DrivedObject(); try { await Task.Run(() => d.DoSomething()); } catch (Exception ex) { Debug.WriteLine(ex); } } private async void DispatcherButton_Click(object sender, RoutedEventArgs e) { // UIスレッド以外だがDispatcher経由での呼び出しなのでOK var d = new DrivedObject(); await Task.Run(async () => { if (!d.CheckAccess()) { await d.Dispatcher.InvokeAsync(() => d.DoSomething()); // OK } }); }
実行して上から順番にボタンを押した結果のデバッグウィンドウを以下に示します。
DoSomething ...省略... System.InvalidOperationException: このオブジェクトは別のスレッドに所有されているため、呼び出しスレッドはこのオブジェクトにアクセスできません。 ...省略... DoSomething
最初のボタンでは、UIスレッドからの呼び出しなので、エラーもなくデバッグウィンドウに結果が出ています。二番目のボタンでは、UIスレッド以外からの呼び出しでVerifyAccessの箇所でInvalidOperationExceptionが発生しています。三番目のボタンでは、UIスレッド以外からDispatcher経由で、呼び出しているためデバッグウィンドウに結果が出ていることが確認できます。
通常のWPFを使った開発でも、UIスレッド以外からUIを直接または間接的に操作することがあります。そんなときは、このDispatcherを使い今回のサンプルプログラムのように呼び出す必要があります。
過去記事
- WPF4.5入門 その1 「はじめに」
- WPF4.5入門 その2 「WPFとは」
- WPF4.5入門 その3 「Hello world」
- WPF4.5入門 その4 「Mainメソッドはどこにいった?」
- WPF4.5入門 その5 「全てC#でHello world」
- WPF4.5入門 その6 「WPFを構成するものを考えてみる」
- WPF4.5入門 その7 「XAMLのオブジェクト要素と名前空間」
- WPF4.5入門 その8 「オブジェクト要素のプロパティ」
- WPF4.5入門 その9 「コレクション構文」
- WPF4.5入門 その10 「コンテンツ構文」
- WPF4.5入門 その11 「マークアップ拡張」
- WPF4.5入門 その12 「その他のXAMLの機能」
- WPF4.5入門 その13 「簡単なレイアウトを行うコントロール」
- WPF4.5入門 その14 「レイアウトコントロールのCanvasとStackPanel」
- WPF4.5入門 その15 「レイアウトコントロールのDockPanelとWrapPanel」
- WPF4.5入門 その16 「ViewBoxコントロール」
- WPF4.5入門 その17 「ScrollViewerコントロール」
- WPF4.5入門 その18 「Gridコントロール part 1」
- WPF4.5入門 その19 「Gridコントロール part 2」
- WPF4.5入門 その20 「レイアウトに影響を与えるプロパティ」
- WPF4.5入門 その21 「WPFのコンセプトと重要な機能つまみ食い」
- WPF4.5入門 その22 「Buttonコントロール」
- WPF4.5入門 その23 「DataGridコントロール その1」
- WPF4.5入門 その24 「DataGridコントロール その2」
- WPF4.5入門 その25 「TreeViewコントロール その1」
- WPF4.5入門 その26 「TreeViewコントロール その2」
- WPF4.5入門 その28 「Calendarコントロール」 - かずきのBlog@hatena
- WPF4.5入門 その29 「ContextMenuコントロール」 - かずきのBlog@hatena
- WPF4.5入門 その30「Menuコントロール」 - かずきのBlog@hatena
- WPF4.5入門 その31 「ToolBarコントロール」 - かずきのBlog@hatena
- WPF4.5入門 その32 「CheckBoxコントロール」 - かずきのBlog@hatena
- WPF4.5入門 その33 「ComboBoxコントロール」 - かずきのBlog@hatena
- WPF4.5入門 その34 「ListBoxコントロール」 - かずきのBlog@hatena
- WPF4.5入門 その35 「RadioButtonコントロール」 - かずきのBlog@hatena
- WPF4.5入門 その36 「Sliderコントロール」 - かずきのBlog@hatena
- WPF4.5入門 その37 「TabControl」 - かずきのBlog@hatena
- WPF4.5入門 その38 「ファイルダイアログ」 - かずきのBlog@hatena
- WPF4.5入門 その39 「情報を表示するコントロール」 - かずきのBlog@hatena
- WPF4.5入門 その40 「Popup、ToolTip、TextBox、Image、MediaElementコントロール」 - かずきのBlog@hatena