WPF で画面遷移する方法 3
コンテンツを切り替えるコントロールといえば真っ先に TabControl を想像しますよね。というわけで今回は TabControl を少しカスタマイズしてみます。
構成は単純で、MainView ウィンドウに対する MainViewModel と、各コンテンツに対する ViewModel として Content01ViewModel、Content02ViewModel、Content03ViewModel があります。 Content01ViewModel などに対する View は MainView.xaml の中に記述するため、ファイルとしては分かれていません。
それではまず MainViewModel のソースから説明します。
namespace TabSample.ViewModels
{
using YKToolkit.Bindings;
internal class MainViewModel : NotificationObject
{
private ViewModelBase _content01ViewModel = new Content01ViewModel();
public ViewModelBase Content01ViewModel { get { return this._content01ViewModel; } }
private ViewModelBase _content02ViewModel = new Content02ViewModel();
public ViewModelBase Content02ViewModel { get { return this._content02ViewModel; } }
private ViewModelBase _content03ViewModel = new Content03ViewModel();
public ViewModelBase Content03ViewModel { get { return this._content03ViewModel; } }
}
}
愚鈍に各コンテンツの ViewModel のインスタンスを保持、公開しているだけです。各コンテンツの ViewModel は Caption プロパティを持っています。例えば Content01ViewModel クラスは次のようになっています。
namespace TabSample.ViewModels
{
internal class Content01ViewModel : ViewModelBase
{
public string Caption { get { return "Content01"; } }
}
}
さて、MainView ウィンドウに TabControl を配置しましょう。
<YK:Window x:Class="TabSample.Views.MainView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:YK="clr-namespace:YKToolkit.Controls;assembly=YKToolkit.Controls"
Title="MainView"
Width="300" Height="200">
<DockPanel>
<TabControl>
<TabItem DataContext="{Binding Content01ViewModel}" Header="{Binding Caption}">
<CheckBox Content="{Binding Caption}" />
</TabItem>
<TabItem DataContext="{Binding Content02ViewModel}" Header="{Binding Caption}">
<TextBlock Text="{Binding Caption}" />
</TabItem>
<TabItem DataContext="{Binding Content03ViewModel}" Header="{Binding Caption}">
<TextBlock Text="{Binding Caption}" />
</TabItem>
</TabControl>
</DockPanel>
</YK:Window>
各コンテンツのレイアウトを MainView.xaml 内に書いてしまいます。あまり長くなるのが嫌だったり、明確にファイルを別にしたい場合は独自のユーザコントロールを置くなどして対処すればいいかと思います。ここでは簡略化のため同一 xaml 内で、しかもコントロールを 1 つだけ置いています。
また、ここではあえてすべてのコンテンツの DataContext に別物を指定していますが、指定しなくてもいいし、同じものを指定してもいいと思います。
あ、うん。TabControl ってこんな感じだよね。
これでいい場合はこれでいいんですが、そうじゃないですよね。つまり、TabControl のタブの部分が邪魔です。というわけで Template プロパティをいじって TabPanel の部分を表示しないようにしてしまいます。
<YK:Window x:Class="TabSample.Views.MainView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:YK="clr-namespace:YKToolkit.Controls;assembly=YKToolkit.Controls"
Title="MainView"
Width="300" Height="200">
<DockPanel>
<TabControl SelectedIndex="0">
<TabControl.Template>
<ControlTemplate TargetType="{x:Type TabControl}">
<ContentPresenter x:Name="PART_SelectedContentHost" ContentSource="SelectedContent" />
</ControlTemplate>
</TabControl.Template>
<TabItem DataContext="{Binding Content01ViewModel}">
<CheckBox Content="{Binding Caption}" />
</TabItem>
<TabItem DataContext="{Binding Content02ViewModel}">
<TextBlock Text="{Binding Caption}" />
</TabItem>
<TabItem DataContext="{Binding Content03ViewModel}">
<TextBlock Text="{Binding Caption}" />
</TabItem>
</TabControl>
</DockPanel>
</YK:Window>
TabControl のカスタマイズについては MSDN のサイトが参考になります。
本来は TabControl の Template に TabPanel コントロールを配置することでタブ部分を表示させますが、これを配置せずに ContentPresenter だけを配置します。タブ部分が表示されなくなるので、各 TabItem コントロールの Header プロパティは不要になります。また、デフォルトで 0 番目のコンテンツが選択されるように TabControl の SelectedIndex プロパティを指定しています。
狙い通りタブ部分が表示されなくなりました。
さらにコンテンツを選択できるようにすれば見た目で TabControl を使っているとは思えない外観になります。
<YK:Window x:Class="TabSample.Views.MainView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:YK="clr-namespace:YKToolkit.Controls;assembly=YKToolkit.Controls"
Title="MainView"
Width="300" Height="200">
<DockPanel>
<ComboBox x:Name="combobox" DockPanel.Dock="Bottom" SelectedIndex="0">
<ComboBoxItem>Content01</ComboBoxItem>
<ComboBoxItem>Content02</ComboBoxItem>
<ComboBoxItem>Content03</ComboBoxItem>
</ComboBox>
<TabControl SelectedIndex="{Binding SelectedIndex, ElementName=combobox}">
<TabControl.Template>
<ControlTemplate TargetType="{x:Type TabControl}">
<ContentPresenter x:Name="PART_SelectedContentHost" ContentSource="SelectedContent" />
</ControlTemplate>
</TabControl.Template>
<TabItem DataContext="{Binding Content01ViewModel}">
<CheckBox Content="{Binding Caption}" />
</TabItem>
<TabItem DataContext="{Binding Content02ViewModel}">
<TextBlock Text="{Binding Caption}" />
</TabItem>
<TabItem DataContext="{Binding Content03ViewModel}">
<TextBlock Text="{Binding Caption}" />
</TabItem>
</TabControl>
</DockPanel>
</YK:Window>
Content01View のチェックボックスを入れた状態で画面遷移し、戻ってきてもちゃんとチェックが入った状態になっています。MainView.xaml に各コンテンツのインスタンスを配置しているため、View のインスタンスが保持されるからですね。
ところが、これでは前回までのように画面遷移時のアニメーションが実現できません。次回は TabControl による画面遷移でアニメーションをおこなってみます。
Tweet
<< 古い記事へ WPF で画面遷移する方法 2 |
新しい記事へ >> WPF で画面遷移する方法 4 |