graphics.hatenablog.com

技術系テクニカルアーティストのあれこれ

WPF で動的にビューを切り替える

まずそもそもの話として、その「切り替え」がいわゆる画面遷移的なものだったら、
とりあえず NavigationService クラス (System.Windows.Navigation) を使っておくのが手軽でいい。
もちろん NavigationWindow クラス (System.Windows.Navigation) でもいいんだけど、
こっちは見た目のコントロールがちょっとめんどくさい。

WPFサンプル:NavigationServiceを使ったページ遷移:Gushwell's C# Dev Notes
NavigationWindowを使った画面遷移 - SourceChord

それ以外だととりあえず DataTemplate クラス (System.Windows) を使うことになるのかなと。


やってることは比較的シンプルで、
ContentControl.DataTemplate に、DataType に応じたビューを設定してるだけ。

ContentControl クラス (System.Windows.Controls) は任意のコントロールを表現することができるから、そこのテンプレートとして DataTemplate を指定する。

<Window.Resources>
    <DataTemplate DataType="{x:Type local:ViewModelA}">
        <Button Content="{Binding Label}"/>
    </DataTemplate>
    <DataTemplate DataType="{x:Type local:ViewModelB}">
        <CheckBox Content="{Binding Label}"/>
    </DataTemplate>
</Window.Resources>
<ContentControl Content="{Binding ContentViewModel}" />

DataTemplate の扱いはちょっとだけややこしい。リソース上に複数のテンプレートが定義されているときに、ContentTemplate としてどのテンプレートが適用されるか。優先順位は以下の通り。

  1. ContentTemplate 側で指定したキーに一致するテンプレート
  2. オブジェクトの型が DataType に一致するテンプレート

まず、テンプレート側に明示的なキーが指定されていれば、オブジェクトの型によらずそれが適用される。

<Window.Resources>
    <DataTemplate x:Key="testKey">
        <TextBlock Text="{Binding Label}"/>
    </DataTemplate>
</Window.Resources>
<ContentControl Content="{Binding ContentViewModel}"
                ContentTemplate="{StaticResource testKey}"/>

そうでないときは「暗黙のキー」が指定されているということになって、DataType での型判定の結果次第で自動的にテンプレートが選ばれる。
このあたりは データ テンプレートの概要 を参照のこと。

この DataTemplate は、すべての Task オブジェクトに自動的に適用されます。 
この場合、x:Key が暗黙的に設定されることに注意してください。
したがって、この DataTemplate に x:Key 値を割り当てる場合は、
暗黙の x:Key をオーバーライドします。
DataTemplate は自動的に適用されません。

同じ型のオブジェクトがバインドされてるときは、DataType でその型を指定しておいて、テンプレート内で DataTrigger を使って分岐すればいい。あとは、バインド先が TreeView だったりするときは DataTemplate じゃなくて HierarchicalDataTemplate を使うとか。

Style も x:Key と TargetType で適用先を指定できるけど、そっちも似たようなルールになってる。まずはキー指定を探して、なかったら TargetType で自動判定。