DataTemplateで要素の切り替え

#はじめに
ツール開発に関して自分のなかである程度知識がまとまってきたので、
ちょっと高度な？MVVMについてに記述していきます。

## 今回やること
下の用な感じでタブコントロールの中身をスマートに変更できるようプログラム作っていきます。
![image](https://qiita-image-store.s3.amazonaws.com/0/63344/3aae394c-8d7b-73e2-f43d-3bb7a6036b0f.png)

# タブコントロールの作成

```xaml:TabControlView.xaml
     <UserControl.Resources>
        <vm:DockPaneTemplateSelector x:Key="TabItemTemplateSelector">
            <vm:DockPaneTemplateSelector.ShaderProgramTemplate>
                <DataTemplate  DataType="{x:Type vm:ShaderProgramViewModel}">
                    <v:ShaderProgramView/>
                </DataTemplate>
            </vm:DockPaneTemplateSelector.ShaderProgramTemplate>
            <vm:DockPaneTemplateSelector.VoxelTemplate>
                <DataTemplate DataType="{x:Type vmc:VoxelViewModel}">
                    <vc:VoxelView/>
                </DataTemplate>
            </vm:DockPaneTemplateSelector.VoxelTemplate>

        <DataTemplate x:Key="TabItemHeaderTempalte">
            <DockPanel>
                <TextBlock Text="{Binding Title}" DockPanel.Dock="Left"/>
                <Button Content=" x " Command="{Binding CloseTabItem}" DockPanel.Dock="Right" Background="White"/>
            </DockPanel>
        </DataTemplate>
    </UserControl.Resources>

    <TabControl ItemsSource="{Binding ItemsSource}" SelectedItem="{Binding ActiveItem}" ContentTemplateSelector="{StaticResource TabItemTemplateSelector}" ItemTemplate="{StaticResource TabItemHeaderTempalte}"/>

```


```C#:TabControlViewModel.cs

    public class TabControlViewModel : DockWindowViewModel
    {

        private TabItemViewModel _activeItem;
        public TabItemViewModel ActiveItem
        {
            get
            {
                return _activeItem;
            }
            set
            {
                SetValue(ref _activeItem, value);
            }
        }
        private ObservableCollection<TabItemViewModel> _ItemsSource = new ObservableCollection<TabItemViewModel>();
        public ObservableCollection<TabItemViewModel> ItemsSource
        {
            get
            {
                return _ItemsSource;
            }
            set
            {
                SetValue(ref _ItemsSource, value);
            }
        }

        public TabControlViewModel()
        {

        }
   }

class DockPaneTemplateSelector: DataTemplateSelector
    {
        public DataTemplate ShaderProgramTemplate { get; set; }
        public DataTemplate VoxelTemplate { get; set; }
        public override DataTemplate SelectTemplate(object item, DependencyObject container)
        {
            if (item is ShaderProgramViewModel)
            {
                return ShaderProgramTemplate;
            }
            if(item is VoxelViewModel)
            {
                return VoxelTemplate;
            }
            return base.SelectTemplate(item, container);
        }
　　}
```

こんな感じです。
まずはC#のほうではDataTemplateSelectorを継承しDockPaneTemplateSelectorを定義します。
これでItemsSourceに値が追加されると、Itemの型を参照し、
ShaderProgramViewModelが追加されたんだったらShaderProgramTemplate使ってねと指定できます。

次にxamlのほうです。
一番の注目はContentTemplateSelectorです。
ここでUserControl.Resourceに書いたTabItemTempalateSelectorをBindingしています。
ここで、ShaderProgramTemplateならShaderProgramViewを表示してね
追加されたItemの型はShaderProgramViewModelだよと指定できます。

ちなみにVoxelViewとShaderProgramViewはUserControlです。あとはコントロール配置してるだけです。

#最後に
DataTemplateSelectorの他にStyleSelectorなるものもあります。
表示するViewModelによってStyleを変更したいときに使えるようです。

このあたり使えるようになるとツール開発やりやすくなってくると思います。