TabViewはウェブブラウザのタブのように任意に追加したり削除したりできるタブ機能をアプリに追加するためのコントロールです。TabViewを使うことで、複数のドキュメントやページを動的に開いたり閉じたりということが可能になります。
開発環境
- .NET 6.0
- WinUI 3.0 (Windows App SDK 1.0)

TabViewとは?
TabViewはブラウザのようなタブ機能をアプリに導入するためのコントロールです。タブを導入することでアプリに複数のページを表示することができ、それをユーザーが追加したり閉じたりすることも可能になります。
TabViewの領域は次のように名前が定義されています。

さらに、1つ1つのタブについては次のようになります。

詳細については以下をご覧ください。
なお、TabViewに似たコントロールとしてNavigationViewがありますが、公式ドキュメントでは次のような場合にTabViewを用いることが推奨されています。
- ユーザーが、タブを動的に開いたり、閉じたり、再配置したりできる。
- ユーザーが、ドキュメントや Web ページを直接タブで開くことができる。
- ユーザーが、ウィンドウ間でタブをドラッグ アンド ドロップできる。
NavigationViewでPaneDisplayMode=”top”とした場合はTabViewに似たGUIとなるので、上記すべてに当てはまらないような場合はNavigationViewを用いることが推奨されています。NavigationViewについては以下の記事もご覧ください。
TabViewを導入する
まずは最低限のタブだけ実装したアプリを作成してみましょう。
TabViewのコンテントプロパティであるTabItemsプロパティにTabViewItemを配置することで、タブを配置できます。
MainWindow
MainWindow.xaml
<Window ...(省略)... >
<TabView>
<TabViewItem Header="タブ1">
<Page>
<TextBlock Text="タブ1です"/>
</Page>
</TabViewItem>
<TabViewItem Header="タブ2">
<Page>
<TextBlock Text="タブ2です"/>
</Page>
</TabViewItem>
<TabViewItem Header="タブ3">
<Page>
<TextBlock Text="タブ3です"/>
</Page>
</TabViewItem>
</TabView>
</Window>

TabViewItemが1つ1つのタブとなり、そのHeaderプロパティでタブに表示する文字列を指定することができます。タブのコンテンツは以下のようにそのコンテントプロパティであるContentプロパティにコーディングします。
TabViewのデザインを調整する
タブの幅を調整する
TabViewのTabWidthModeプロパティで表示させるタブの幅を指定することができます。TabWidthModeプロパティの値は次の中から指定します。
- Compact:選択されていないタブはアイコンだけ表示されます
- Equal:すべてのタブが同じサイズで均等に表示されます
- SizeToContent:すべてのタブがその内容に応じたサイズで表示されます
Compact

Equal

SizeToContent

タブ領域の横に任意のコントロールを表示させる
TabViewのTabStripHeaderプロパティとTabStripFooterプロパティでそれぞれタブ領域の左と右に任意のコントロールを配置することができます。
MainWindow
MainWindow.xaml
<Window ...(省略)... >
<TabView>
<TabView.TabStripHeader>
<StackPanel Orientation="Horizontal" VerticalAlignment="Bottom">
<Button Content="ボタンA"/>
<Button Content="ボタンB"/>
</StackPanel>
</TabView.TabStripHeader>
<TabViewItem Header="タブ1"/>
<TabViewItem Header="タブ2"/>
<TabViewItem Header="タブ3"/>
<TabView.TabStripFooter>
<TextBlock Text="フッター" VerticalAlignment="Center"/>
</TabView.TabStripFooter>
</TabView>
</Window>

ここではタブ領域の左側のヘッダーにはボタンを配置し、右側のフッターには文字列を配置しています。
タブの追加ボタンを非表示にする
TabViewのIsAddTabButtonVisibleプロパティをFalseにすることで、タブを追加するための[+]ボタンが非表示となります。
TabViewItemのデザインを調整する
タブにアイコンを表示させる
TabViewItemのIconSourceプロパティにアイコンを指定することでタブのアイコンを指定できます。ただし、このIconSourceプロパティにアイコンそのもの(IconElement)を直接指定することはできずに、IconSourceで指定する必要があることに注意が必要です。あらかじめ定義されているSymbol列挙型から指定する場合はSymbolIconSourceで指定します。また任意の画像をアイコンとして指定する場合はBitmapIconSourceにその画像のURLを渡して指定しましょう。
MainWindow
MainWindow.xaml
<Window ...(省略)... >
<TabView>
<TabViewItem Header="Home">
<TabViewItem.IconSource>
<SymbolIconSource Symbol="ホーム"/>
</TabViewItem.IconSource>
</TabViewItem>
<TabViewItem Header="ドキュメント">
<TabViewItem.IconSource>
<SymbolIconSource Symbol="Document"/>
</TabViewItem.IconSource>
</TabViewItem>
<TabViewItem Header="インポート">
<TabViewItem.IconSource>
<SymbolIconSource Symbol="Import"/>
</TabViewItem.IconSource>
</TabViewItem>
</TabView>
</Window>

タブを閉じられないようにする
TabViewItemのIsClosableプロパティをFalseに設定することで、タブを閉じるための[x]ボタンが表示されなくなり、常に表示させておくことができます。
MainWindow
MainWindow.xaml
<Window ...(省略)... >
<TabView>
<TabViewItem Header="タブ1" IsClosable="False"/>
<TabViewItem Header="タブ2"/>
<TabViewItem Header="タブ3"/>
</TabView>
</Window>

これで「タブ1」だけ[x]ボタンがなくなり閉じられなくなっていることが分かります。
タブの動作を定義する
新しいタブを作成する
右側の追加ボタン[+]をクリックすると、TabViewのAddTabButtonClickイベントが呼び出されます。ここに新しいタブを生成するメソッドを登録しておきましょう。
MainWindow
MainWindow.xaml
<Window ...(省略)... >
<TabView AddTabButtonClick="TabView_AddTabButtonClick">
<TabViewItem Header="タブ1"/>
<TabViewItem Header="タブ2"/>
<TabViewItem Header="タブ3"/>
</TabView>
</Window>
MainWindow.xaml.cs
public sealed partial class MainWindow : Window
{
public MainWindow()
{
this.InitializeComponent();
}
// 新たなタブを生成するメソッド
private TabViewItem CreateNewTab()
{
TabViewItem newItem = new TabViewItem();
newItem.Header = "新しいタブ";
newItem.IconSource = new Microsoft.UI.Xaml.Controls.SymbolIconSource() { Symbol = Symbol.Document };
Frame frame = new Frame();
frame.Navigate(typeof(NewPage));
newItem.Content = frame;
return newItem;
}
// AddTabButtonClickイベントで呼び出されるメソッド
private void TabView_AddTabButtonClick(TabView sender, object args)
{
sender.TabItems.Add(CreateNewTab());
sender.SelectedIndex = sender.TabItems.Count-1;
}
}
ここでは、AddTabButtonClickイベントにTabView_AddTabButtonClickメソッドを登録しています。さらに、CreateNewTabメソッドとして新たなタブを生成する処理を書いておき、TabView_AddTabButtonClickメソッドが呼び出されたら、CreateNewTabメソッドでタブを生成します。これを26行目でTabItemsに登録し、さらに27行目でSelectedIndexを新たに作成したものにしておくことで、新たに生成されたタブを表示させることができます。
新たに生成するタブページのひな形として以下のNewPageを作成しておきましょう。
NewPage
NewPage
<Page ...(省略)... >
<Grid>
<TextBlock Text="新しいページ"/>
</Grid>
</Page>

選択されたタブを閉じる
上記にタブを閉じるときの処理も付け加えておきます。タブの閉じるボタン[x]をクリックすると、その所属するTabViewのTabCloseRequestedイベントが呼び出されます。ここにタブを閉じるための処理を登録しておきましょう。なお、TabViewItemのCloseRequestedイベントに処理を登録することもできますが、すべてのタブを束ねているTabViewに処理を登録した方がコーディングしやすいでしょう。
MainWindow
MainWindow.xaml
<Window ...(省略)... >
<TabView AddTabButtonClick="TabView_AddTabButtonClick" TabCloseRequested="TabView_TabCloseRequested">
<TabViewItem Header="タブ1"/>
<TabViewItem Header="タブ2"/>
<TabViewItem Header="タブ3"/>
</TabView>
</Window>
MainWindow.xaml.cs
public sealed partial class MainWindow : Window
{
...(省略)...
// TabCloseRequestedイベントで呼び出されるメソッド
private void TabView_TabCloseRequested(TabView sender, TabViewTabCloseRequestedEventArgs args)
{
sender.TabItems.Remove(args.Tab);
}
}
ここではTabCloseRequestedイベントにコード・ビハインドで作成したTabView_TabCloseRequestedメソッドを登録しています。引数でTabViewTabCloseRequestedEventArgsオブジェクトを受け取ることができるので、TabプロパティでどのTabViewItemの閉じるボタン[x]が押されたかを取得し、それをTabItemsから削除しましょう(9行目)。
これでタブを開いたり閉じたりが自由にできるようになり、タブの機能を最低限使えるようになりました。
コメント