次の方法で共有


タブ ビュー

TabView コントロールは、一連のタブとそれぞれの内容を表示するための手段です。 TabView コントロールは、ユーザーが新しいタブを並べ替えたり、閉じたり、開いたりしながら、コンテンツの複数のページ (またはドキュメント) を表示する場合に便利です。

TabView の例

これは適切なコントロールですか?

一般に、タブ付き UI には、関数と外観が異なる 2 つの異なるスタイルのいずれかが含まれます。

  • 静的タブ は、設定ウィンドウでよく見られるタブの一種です。 通常、内容があらかじめ定義されている固定順序の複数のページが含まれます。
  • ドキュメント タブ は、Microsoft Edge などのブラウザーで使用されるタブの一種です。 ユーザーは、タブの作成、削除、再配置、ウィンドウ間でのタブの移動、タブの内容の変更を行うことができます。

既定では、 TabView はドキュメント タブを提供するように構成されています。 ユーザーが次のことを実行できる場合は、TabView をお勧めします。

  • タブを動的に開く、閉じる、または並べ替える。
  • ドキュメントまたは Web ページをタブに直接開きます。
  • ウィンドウ間でタブをドラッグ アンド ドロップします。

TabView API では、静的タブのコントロールを構成できます。 ただし、Windows の設計ガイダンスに従い、静的なナビゲーション項目が複数ある場合は、 NavigationView コントロールの使用を検討してください。

構造

タブ付き UI は、TabView コントロールと 1 つ以上の TabViewItem コントロールを使用して作成されます。 TabView は、1 つのタブとそのコンテンツを表す TabViewItem のインスタンスをホストします。

TabView パーツ

この図は 、TabView コントロールの部分を示しています。 タブ ストリップにはヘッダーとフッターがありますが、ドキュメントとは異なり、タブ ストリップのヘッダーとフッターはそれぞれストリップの左端と右端にあります。

この図は、タブ ビュー コントロールの部分を示しています。タブ ストリップには 4 つのタブがあり、ヘッダーとフッターがあり、それぞれストリップの左端と右端にあります。

TabViewItem パーツ

この図は 、TabViewItem コントロールの部分を示しています。 コンテンツは TabView コントロール内に表示されますが、コンテンツは実際には TabViewItem の一部です。

この画像は、タブ ビュー項目コントロールの部分を示しています。個々のタブが選択され、アイコンとラベルが表示され、タブの下にコンテンツ領域が表示されます。

推奨 事項

タブの選択

ほとんどのユーザーは、Web ブラウザーを使用して簡単にドキュメント タブを使用した経験があります。 アプリでドキュメント タブを使用するとき、ユーザーは経験からタブがどのように動作するかを予期します。

ユーザーが一連のドキュメント タブを操作する方法に関係なく、常にアクティブなタブが存在する必要があります。ユーザーが選択したタブを閉じたり、選択したタブを別のウィンドウに分割したりすると、別のタブがアクティブなタブになります。 TabView は、次のタブを自動的に選択しようとします。アプリで未選択のタブを持つ TabView を許可する正当な理由がある場合、TabView のコンテンツ領域は空白になります。

キーボード ナビゲーション

TabView では、多くの一般的なキーボード ナビゲーション シナリオが既定でサポートされています。 このセクションでは、組み込みの機能について説明し、一部のアプリで役立つ追加機能についての推奨事項を示します。

タブとカーソル キーの動作

TabStrip 領域にフォーカスが移動すると、選択した TabViewItem にフォーカスが移動します。 その後、ユーザーは左方向キーと右方向キーを使用して、タブ ストリップ内の他のタブにフォーカス (選択されていない) を移動できます。 矢印フォーカスはタブ ストリップ内でトラップされ、ある場合はタブ追加 [+] ボタンが表示されます。 タブ ストリップ領域からフォーカスを移動するには、 Tab キーを押すと、フォーカスが次のフォーカス可能な要素に移動します。

タブ を使用してフォーカスを移動する

タブを使用してフォーカスを移動する

方向キーがフォーカスを循環しない

方向キーがフォーカスを循環しない

タブの選択

TabViewItem にフォーカスがある場合は、 Space キーまたは Enter キー を押してその TabViewItem を選択します。

方向キーを使用してフォーカスを移動し、スペース 押してタブを選択します。

タブを選択するスペース

隣接するタブを選択するためのショートカット

Ctrl キーを押しながら Tab キーを押して、次の TabViewItem を選択しますCtrl + Shift + Tab キーを押して、前の TabViewItem を選択します。 このような場合、タブ リストは "ループ" されるため、最後のタブが選択されている間に次のタブを選択すると、最初のタブが選択されます。

タブを閉じる

Ctrl + F4 キーを押して TabCloseRequested イベントを発生させます。 イベントを処理し、必要に応じてタブを閉じます。

ヒント

詳細については、この記事で後述 する開発者向けのキーボード ガイダンス を参照してください。

タブ ビューを作成する

WinUI 3 ギャラリー アプリには、ほとんどの WinUI 3 コントロール、機能、および機能の対話型の例が含まれています。 Microsoft Store からアプリを取得するか、GitHub でソース コードを取得する

このセクションの例では、 TabView コントロールを構成するさまざまな方法を示します。

タブ ビューの項目

TabView の各タブは TabViewItem コントロールによって表され、タブ ストリップに表示されるタブとタブ ストリップの下に表示されるコンテンツの両方が含まれます。

タブを構成する

TabViewItem ごとに、ヘッダーとアイコンを設定し、ユーザーがタブを閉じることができるかどうかを指定できます。

  • Header プロパティは、通常、タブのわかりやすいラベルを提供する文字列値に設定されます。ただし、Headerプロパティには任意のオブジェクトを指定できます。 HeaderTemplate プロパティを使用して、バインドされたヘッダー データの表示方法を定義する DataTemplate を指定することもできます。
  • IconSource プロパティを設定して、タブのアイコンを指定します。
  • 既定では、タブには 閉じるボタン (X) が表示されます。 IsClosable プロパティをfalseに設定すると、閉じるボタンを非表示にし、ユーザーがタブを閉じることができないことを確認できます (閉じる要求されたイベントの外部でアプリ コードのタブを閉じる場合は、最初にIsClosabletrueされていることを確認する必要があります)。

TabView では、すべてのタブに適用される複数のオプションを構成できます。

  • 既定では、閉じるボタンは常に、閉じるタブに対して表示されます。 この動作を変更するには、 CloseButtonOverlayMode プロパティを OnPointerOver に設定できます。 この場合、選択したタブは常に閉じるボタンを表示しますが、選択されていないタブでは、タブが閉じられ、ユーザーがその上にポインターを置いている場合にのみ閉じるボタンが表示されます。
  • TabWidthMode プロパティを設定して、タブのサイズを変更できます。 (TabViewItemでは、Width プロパティは無視されます)。TabViewWidthMode 列挙型のオプションは次のとおりです。
    • Equal - 各タブの幅は同じです。 これが既定値です。
    • SizeToContent - 各タブは、タブ内のコンテンツに合わせて幅を調整します。
    • Compact - 選択されていないタブが折りたたまれると、そのアイコンのみが表示されます。 選択したタブが調整され、タブ内のコンテンツが表示されます。

コンテンツ

選択したタブに表示される要素は、TabViewItemContent プロパティに追加されます。 TabViewItem は ContentControlであるため、任意の種類のオブジェクトをコンテンツとして追加できます。 DataTemplateContentTemplate プロパティに適用することもできます。 詳細については、 ContentControl クラスを参照してください。

この記事の例では、XAML の Content 要素にテキストを直接追加する簡単なケースを示します。 ただし、実際の UI は通常、より複雑です。 タブのコンテンツとして複雑な UI を追加する一般的な方法は、 それを UserControl または Page にカプセル化し、それを TabViewItem のコンテンツとして追加することです。 この例では、アプリに PictureSettingsControlという XAML UserControl があることを前提としています。

<TabViewItem>
    <TabViewItem.Content>
        <local:PictureSettingsControl/>
    </TabViewItem.Content>
</TabViewItem>

静的タブ

この例では、2 つの静的タブを含む単純な TabView を示します。 どちらのタブ項目も、TabView のコンテンツとして XAML に追加されます。

TabView を静的にするには、次の設定を使用します。

  • IsAddTabButtonVisible プロパティを false に設定すると、タブの追加ボタンが非表示になり、AddTabButtonClick イベントが発生しないようにすることができます。
  • CanReorderTabs プロパティを false に設定すると、ユーザーがタブを別の順序にドラッグできなくなります。
  • TabViewItemIsClosable プロパティを false に設定すると、 Tab Close ボタンが非表示にされ、ユーザー が TabCloseRequested イベントを発生させるのを防ぐことができます。
<TabView VerticalAlignment="Stretch"
         IsAddTabButtonVisible="False"
         CanReorderTabs="False">
    <TabViewItem Header="Picture" IsClosable="False">
        <TabViewItem.IconSource>
            <SymbolIconSource Symbol="Pictures"/>
        </TabViewItem.IconSource>
        <TabViewItem.Content>
            <StackPanel Padding="12">
                <TextBlock Text="Picture settings" 
                    Style="{ThemeResource TitleTextBlockStyle}"/>
            </StackPanel>
        </TabViewItem.Content>
    </TabViewItem>
    <TabViewItem Header="Sound" IsClosable="False">
        <TabViewItem.IconSource>
            <SymbolIconSource Symbol="Audio"/>
        </TabViewItem.IconSource>
        <TabViewItem.Content>
            <StackPanel Padding="12">
                <TextBlock Text="Sound settings" 
                    Style="{ThemeResource TitleTextBlockStyle}"/>
            </StackPanel>
        </TabViewItem.Content>
    </TabViewItem>
</TabView>

ドキュメント タブ

既定では、TabView は ドキュメント タブ用に構成されています。 ユーザーは、新しいタブを追加したり、タブを再配置したり、タブを閉じたりすることができます。 この構成では、機能を有効にするには、 AddTabButtonClick イベントと TabCloseRequested イベントを処理する必要があります。

タブビューにタブを追加すると、タブストリップに表示できないタブが多すぎる可能性があります。 この場合、スクロール バンパーが表示され、ユーザーはタブ ストリップを左右にスクロールして非表示のタブにアクセスできます。

この例では、タブを開いたり閉じたりするためのイベント ハンドラーと共に、単純な TabView を作成します。 TabView_AddTabButtonClick イベント ハンドラーは、コードに TabViewItem を追加する方法を示しています。

<TabView VerticalAlignment="Stretch"
         AddTabButtonClick="TabView_AddTabButtonClick"
         TabCloseRequested="TabView_TabCloseRequested">
    <TabViewItem Header="Home" IsClosable="False">
        <TabViewItem.IconSource>
            <SymbolIconSource Symbol="Home" />
        </TabViewItem.IconSource>
        <TabViewItem.Content>
            <StackPanel Padding="12">
                <TextBlock Text="TabView content" 
                           Style="{ThemeResource TitleTextBlockStyle}"/>
            </StackPanel>
        </TabViewItem.Content>
    </TabViewItem>
</TabView>
// Add a new tab to the TabView.
private void TabView_AddTabButtonClick(TabView sender, object args)
{
    var newTab = new TabViewItem();
    newTab.Header = $"New Document {sender.TabItems.Count}";
    newTab.IconSource = new SymbolIconSource() { Symbol = Symbol.Document };
    newTab.Content = new TextBlock() { Text = $"Content for new tab {sender.TabItems.Count}.",
                                       Padding = new Thickness(12) };
    sender.TabItems.Add(newTab);
    sender.SelectedItem = newTab;
}

// Remove the requested tab from the TabView.
private void TabView_TabCloseRequested(TabView sender, 
                                       TabViewTabCloseRequestedEventArgs args)
{
    sender.TabItems.Remove(args.Tab);
}

最後のタブが閉じられたときにウィンドウを閉じる

アプリ内のすべてのタブが閉じ可能で、最後のタブが閉じられたときにアプリ ウィンドウを閉じる必要がある場合は、 TabCloseRequested イベント ハンドラーのウィンドウも閉じる必要があります。

まず、App.xaml.cs ファイルで、TabView をホストするPageからWindow インスタンスにアクセスできるようにするpublic static プロパティを追加します。 ( ユーザー インターフェイスの移行を参照してください)。

public partial class App : Application
{
    // ... code removed.

    // Add this.
    public static Window Window { get { return m_window; } }
    // Update this to make it static.
    private static Window m_window;
}

次に、TabView からすべてのタブが削除されている場合に Window.Close を呼び出す TabCloseRequested イベント ハンドラーを変更します。

// Remove the requested tab from the TabView.
// If all tabs have been removed, close the Window.
private void TabView_TabCloseRequested(TabView sender, 
                                       TabViewTabCloseRequestedEventArgs args)
{
    sender.TabItems.Remove(args.Tab);

    if (sender.TabItems.Count == 0)
    {
        App.Window.Close();
    }
}

この例は、1 つのウィンドウ (MainWindow) を持つアプリに対して機能します。 アプリに複数のウィンドウがある場合、またはタブの破棄を有効にしている場合は、ウィンドウを追跡し、閉じる正しいウィンドウを見つける必要があります。 この例については、次のセクションを参照してください。

タブの引き裂き

タブの破棄 は、ユーザーが TabView のタブ ストリップからタブをドラッグして別の TabView コントロール (通常は新しいウィンドウ) に移動した場合の動作を示します。

Windows App SDK 1.6 以降、TabView には CanTearOutTabs プロパティがあり、タブを新しいウィンドウにドラッグするエクスペリエンスを強化するために設定できます。 このオプションを有効にしてタブ ストリップの外にタブをドラッグすると、ドラッグ中に新しいウィンドウがすぐに作成され、ユーザーはウィンドウを画面の端にドラッグして、ウィンドウ を 1 つのスムーズなモーションで最大化または スナップできます。 この実装ではドラッグ アンド ドロップ API も使用されないため、これらの API の制限の影響を受けません。

CanTearOutTabs プロパティをtrueに設定すると、ドラッグ アンド ドロップ イベントではなくタブの破棄イベントが発生します。 タブの破棄を実装するには、次のイベントを処理する必要があります。

  • TabTearOutWindowRequested

    このイベントは、タブがタブ ストリップから最初にドラッグされたときに発生します。 これを処理して、タブが移動される新しいウィンドウと TabView を作成します。

  • TabTearOutRequested

    このイベントは、新しいウィンドウが指定された後に発生します。 これを処理して、元の TabView から新しいウィンドウの TabView に引き裂かれたタブを移動します。

  • ExternalTornOutTabsDropping

    このイベントは、引き裂かれたタブが既存の TabView の上にドラッグされたときに発生します。 タブを受け入れるかどうかを示すために、引き裂かれたタブを受け取っている TabView でそれを処理します。

  • ExternalTornOutTabsDropped

    このイベントは、引き裂かれたタブが既存の TabView の上にドラッグされ、ExternalTornOutTabsDropping イベントによってドロップが許可されていることが示された場合に発生します。 元の TabView からタブを削除し、指定したインデックス位置にある受信 TabView に挿入するために、引き裂かれたタブを受信している TabView で処理します。

TabDragStarting、TabStripDragOverTabStripDropTabDragCompletedTabDroppedOutside のタブティアアウトが有効になっている場合、これらのイベントは発生しません。

注意

管理者として管理者特権で実行されているプロセスでは、タブの破棄がサポートされます。

次の例では、タブの破棄をサポートするイベント ハンドラーを実装する方法を示します。

TabView を設定する

この XAML では、 CanTearOutTabs プロパティを true に設定し、タブの破棄イベント ハンドラーを設定します。

<TabView x:Name="tabView"
     CanTearOutTabs="True"
     TabTearOutWindowRequested="TabView_TabTearOutWindowRequested"
     TabTearOutRequested="TabView_TabTearOutRequested"
     ExternalTornOutTabsDropping="TabView_ExternalTornOutTabsDropping"
     ExternalTornOutTabsDropped="TabView_ExternalTornOutTabsDropped">
    <!-- TabView content -->
</TabView>

新しいウィンドウを作成して追跡する

タブの切り離しでは、アプリで新しいウィンドウを作成して管理する必要があります。

ヒント

WinUI ギャラリー アプリには、アプリ内のウィンドウの管理を容易にする WindowHelper クラスが含まれています。 GitHub から WinUI ギャラリー リポジトリ ( WindowHelper.cs) からコピーできます。 タブの破棄を実装するには、このヘルパー クラスをお勧めします。その使用方法については、GitHub の TabViewWindowingSamplePage を参照してください。

この記事では、ヘルパー メソッドは WindowHelper.csからコピーされますが、読みやすくするために変更され、インラインで表示されます。

ここでは、すべてのアクティブなウィンドウを追跡するためのリストが App.xaml.csに作成されます。 OnLaunched メソッドは、作成後にウィンドウを追跡するように更新されます。 (これは、WindowHelper クラスを使用する場合は必要ありません)。

static public List<Window> ActiveWindows = new List<Window>();

protected override void OnLaunched(Microsoft.UI.Xaml.LaunchActivatedEventArgs args)
{
    m_window = new MainWindow();
    // Track this window.
    ActiveWindows.Add(m_window);
    m_window.Activate();
}

タブの破棄が開始されると、新しいウィンドウが要求されます。 ここで、変数 tabTearOutWindow は、作成後に新しいウィンドウにアクセスできます。 CreateWindow および TrackWindow ヘルパー メソッドは、新しいウィンドウを作成し、アクティブウィンドウ追跡リストに追加します。

新しいウィンドウを作成したら、新しいページを作成し、ウィンドウの内容として設定する必要があります。 新しい Page には、 TabTearOutRequested イベント ハンドラーで引き裂かれたタブを移動する TabView コントロールが含まれている必要があります。

ヒント

この例では、空の TabView のみが含まれるため、新しい MainPage クラスを作成します (XAML ではタブは直接追加されません)。 MainPageに、分離したウィンドウに表示すべきでない他のUI要素が含まれている場合は、必要な要素のみを含む別のページ(少なくともTabViewを含む)を作成し、そのページのインスタンスを作成できます。

最後に、新しいウィンドウの AppWindow.Idargs.NewWindowId プロパティに割り当てます。 これは TabViewTabTearOutRequestedEventArgs.NewWindowId プロパティで使用されるため、そのイベント ハンドラーからウィンドウにアクセスできます。

private Window? tabTearOutWindow = null;

private void TabView_TabTearOutWindowRequested(TabView sender, TabViewTabTearOutWindowRequestedEventArgs args)
{
    tabTearOutWindow = CreateWindow();
    tabTearOutWindow.Content = new MainPage();
    // Optional window setup, such as setting the icon or
    // extending content into the title bar happens here.
    args.NewWindowId = tabTearOutWindow.AppWindow.Id;
}

private Window CreateWindow()
{
    Window newWindow = new Window
    {
        SystemBackdrop = new MicaBackdrop()
    };
    newWindow.Title = "Torn Out Window";
    TrackWindow(newWindow);
    return newWindow;
}

private void TrackWindow(Window window)
{
    window.Closed += (sender, args) => {
        App.ActiveWindows.Remove(window);
    };
    App.ActiveWindows.Add(window);
}

最後のタブが閉じられたときにウィンドウを閉じる

前に説明したように、TabView の最後のタブが閉じられたときにウィンドウを閉じる必要がある場合があります。 アプリに複数のウィンドウがある場合は、追跡対象のウィンドウの一覧で閉じる適切なウィンドウを見つける必要があります。 この例では、その方法を示します。

// Remove the requested tab from the TabView.
// If all tabs have been removed, close the Window.
private void TabView_TabCloseRequested(TabView sender, TabViewTabCloseRequestedEventArgs args)
{
    sender.TabItems.Remove(args.Tab);

    if (sender.TabItems.Count == 0)
    {
        GetWindowForElement(this)?.Close();
    }
}

public Window? GetWindowForElement(UIElement element)
{
    if (element.XamlRoot != null)
    {
        foreach (Window window in App.ActiveWindows)
        {
            if (element.XamlRoot == window.Content.XamlRoot)
            {
                return window;
            }
        }
    }
    return null;
}

タブを新しいウィンドウに移動する

新しいウィンドウが表示されたら、sender TabView から引き裂かれたタブを削除し、新しいウィンドウの TabView に追加する必要があります。 この例では、public AddTabToTabs ヘルパー メソッドを使用して、元のページ インスタンスから新しい MainPage インスタンスの TabView にアクセスし、引き裂かれたタブを追加します。

private void TabView_TabTearOutRequested(TabView sender, TabViewTabTearOutRequestedEventArgs args)
{
    if (tabTearOutWindow?.Content is MainPage newPage
        && args.Tabs.FirstOrDefault() is TabViewItem tab)
    {
        sender.TabItems.Remove(tab);
        newPage.AddTabToTabs(tab);
    }
}

// This method provides access to the TabView from
// another page instance so you can add the torn-out tab.
public void AddTabToTabs(TabViewItem tab)
{
    tabView.TabItems.Add(tab);
}

引き裂かれたタブを別の TabView にドラッグする

前の手順で示したように、タブが引き裂かれ、新しいウィンドウに配置されると、次の 2 つのいずれかが発生する可能性があります。

  • ユーザーはタブを削除でき、新しいウィンドウに残ります。 分離プロセスはここで終了し、これ以上のイベントは発生しません。
  • ユーザーは引き続き取り外されたタブを既存の TabView コントロールにドラッグできます。 この場合、プロセスが続行され、さらにいくつかのイベントが発生して、元の TabView からタブを削除し、既存の TabView に外部タブを挿入できます。

タブが既存の TabView の上にドラッグされると、 ExternalTornOutTabsDropping イベントが発生します。 イベント ハンドラーでは、この TabView にタブを挿入できるかどうかを判断できます。 ほとんどの場合、 args.AllowDrop プロパティを trueに設定するだけで済む場合があります。 ただし、そのプロパティを設定する前にチェックを実行する必要がある場合は、ここで行うことができます。 AllowDropfalseに設定されている場合、タブドラッグアクションは続行され、ExternalTornOutTabsDropped イベントは発生しません。

private void TabView_ExternalTornOutTabsDropping(TabView sender, 
                        TabViewExternalTornOutTabsDroppingEventArgs args)
{
    args.AllowDrop = true;
}

AllowDroptrue イベント ハンドラーで ExternalTornOutTabsDropping に設定されている場合、ExternalTornOutTabsDropped イベントが直ちに発生します。

イベント名の Dropped は、ドラッグ アンド ドロップ API の ドロップ アクションの概念に直接対応していません。 ここでは、 ユーザーがドロップ アクションを実行するためにタブを離す必要はありません。 タブがタブ ストリップの上に保持されている間にイベントが発生し、TabView にタブを ドロップ するコードが実行されます。

ExternalTornOutTabsDropped イベント ハンドラーは、TabTearOutRequested イベントと同じパターンに従いますが、反転されます。元の TabView からタブを削除し、sender TabView に挿入する必要があります。

TabView はタブが挿入されるコントロールであるため、 ヘルパー メソッドを使用して元のタブを検索します。これは、引き裂かれた TabViewItem から始まり、VisualTreeHelper 使用してビジュアル ツリーをウォークアップし、項目が属する TabView を見つけます。 TabView が見つかると、TabViewItem は TabItems コレクション から削除され、 TabView の コレクションに挿入され、DropIndexで指定されたインデックスに挿入されます。

private void TabView_ExternalTornOutTabsDropped(TabView sender, 
                             TabViewExternalTornOutTabsDroppedEventArgs args)
{
    if (args.Tabs.FirstOrDefault() is TabViewItem tab)
    {
        GetParentTabView(tab)?.TabItems.Remove(tab);
        sender.TabItems.Insert(args.DropIndex, tab);
    }
}

// Starting with the TabViewItem, walk up the
// visual tree until you get to the TabView.
private TabView? GetParentTabView(TabViewItem tab)
{
    DependencyObject current = tab;
    while (current != null)
    {
        if (current is TabView tabView)
        {
            return tabView;
        }
        current = VisualTreeHelper.GetParent(current);
    }
    return null;
}

ヒント

Windows Community Toolkit を使用している場合は、GetParentTabViewではなく、ツールキットの DependencyObjectExtensionsFindAscendant ヘルパー メソッドを使用できます。

ウィンドウのタイトル バーに TabView タブを表示する

ウィンドウのタイトル バーの下にタブが独自の行を占有する代わりに、2 つを同じ領域にマージできます。 これにより、コンテンツの縦方向の領域が節約され、最新のアプリの感じになります。

ユーザーはタイトル バーでウィンドウをドラッグしてウィンドウの位置を変更できるため、タイトル バーがタブで完全に埋め込まれていないことが重要です。 したがって、タイトル バーにタブを表示する場合は、ドラッグ可能領域として予約するタイトル バーの一部を指定する必要があります。 ドラッグ可能領域を指定しない場合、タイトル バー全体がドラッグ可能になり、タブが入力イベントを受信できなくなります。 TabView がウィンドウのタイトル バーに表示される場合は、 TabView に TabStripFooter を常に含 め、ドラッグ 可能な領域としてマークする必要があります。

詳細については、「タイトル バーのカスタマイズ」を参照してください。

タイトル バーのタブ

<TabView VerticalAlignment="Stretch">
    <TabViewItem Header="Home" IsClosable="False">
        <TabViewItem.IconSource>
            <SymbolIconSource Symbol="Home" />
        </TabViewItem.IconSource>
    </TabViewItem>

    <TabView.TabStripFooter>
        <Grid x:Name="CustomDragRegion" Background="Transparent" />
    </TabView.TabStripFooter>
</TabView>
private void MainPage_Loaded(object sender, RoutedEventArgs e)
{
    App.Window.ExtendsContentIntoTitleBar = true;
    App.Window.SetTitleBar(CustomDragRegion);
    CustomDragRegion.MinWidth = 188;
}

ウィンドウへの参照を取得する方法は、アプリでウィンドウを追跡する方法によって異なる場合があります。 詳細については、この記事の「 最後のタブを閉じたときにウィンドウを閉じると「新しいウィンドウを作成して追跡する」 を参照してください。

開発者向けのキーボード ガイダンス

ヒント

組み込みのキーボード サポートの詳細については、この記事の「 キーボード ナビゲーション 」を参照してください。

アプリケーションによっては、より高度なキーボード制御が必要になる場合があります。 アプリに適している場合は、次のショートカットを実装することを検討してください。

警告

既存のアプリに TabView を追加する場合は、推奨される TabView キーボード ショートカットのキーの組み合わせに対応するキーボード ショートカットが既に作成されている可能性があります。 この場合は、既存のショートカットを保持するか、ユーザーに直感的なタブ エクスペリエンスを提供するかを、検討する必要があります。

  • Ctrl + T キーを押 して新しいタブを開きます。通常、このタブには定義済みのドキュメントが設定されているか、コンテンツを簡単に選択できる空のタブが作成されます。 ユーザーが新しいタブのコンテンツを選択する必要がある場合は、コンテンツ選択コントロールに入力フォーカスを設定することを検討します。
  • Ctrl + W キーを押 すと、選択したタブが閉じます。TabView では次のタブが自動的に選択されることに注意してください。
  • Ctrl + Shift + T キー を押して最近閉じたタブを開く必要があります (または、より正確には、最近閉じたタブと同じ内容の新しいタブを開きます)。 最後に閉じられたタブから始めて、ショートカットが呼び出されるたびに、時間を遡って移動します。 これには、最近閉じられたタブのリストを保持する必要があることに注意してください。
  • Ctrl + 1 キーを押して、タブリストの最初のタブを選択します。 同様に、Ctrl + 2 キーが押されたら 2 番目のタブを選択し、Ctrl + 3 キーが押されたら 3 番目のタブを選択します。Ctrl + 8 キーマで同様です。
  • Ctrl + 9 キーを押して、一覧に含まれるタブの数に関係なく、タブ一覧の最後のタブを選択する必要があります。
  • タブで "閉じる" 以外のコマンド (タブの複製やピン留めなど) も提供する場合は、コンテキスト メニューを使用して、タブで実行できるすべての操作を表示します。

ブラウザー スタイルのキーボード動作を実装する

この例では、 TabView に上記の推奨事項の数を実装します。 具体的には、この例では 、Ctrl + TCtrl + WCtrl + 1 - 8および Ctrl + 9 を実装します。

<TabView>
    <!-- ... some tabs ... -->
    <TabView.KeyboardAccelerators>
        <KeyboardAccelerator Key="T" Modifiers="Control"
                             Invoked="NewTabKeyboardAccelerator_Invoked" />
        <KeyboardAccelerator Key="W" Modifiers="Control"
                             Invoked="CloseSelectedTabKeyboardAccelerator_Invoked" />
        <KeyboardAccelerator Key="Number1" Modifiers="Control"
                             Invoked="NavigateToNumberedTabKeyboardAccelerator_Invoked" />
        <KeyboardAccelerator Key="Number2" Modifiers="Control"
                             Invoked="NavigateToNumberedTabKeyboardAccelerator_Invoked" />
        <KeyboardAccelerator Key="Number3" Modifiers="Control"
                             Invoked="NavigateToNumberedTabKeyboardAccelerator_Invoked" />
        <KeyboardAccelerator Key="Number4" Modifiers="Control"
                             Invoked="NavigateToNumberedTabKeyboardAccelerator_Invoked" />
        <KeyboardAccelerator Key="Number5" Modifiers="Control"
                             Invoked="NavigateToNumberedTabKeyboardAccelerator_Invoked" />
        <KeyboardAccelerator Key="Number6" Modifiers="Control"
                             Invoked="NavigateToNumberedTabKeyboardAccelerator_Invoked" />
        <KeyboardAccelerator Key="Number7" Modifiers="Control"
                             Invoked="NavigateToNumberedTabKeyboardAccelerator_Invoked" />
        <KeyboardAccelerator Key="Number8" Modifiers="Control"
                             Invoked="NavigateToNumberedTabKeyboardAccelerator_Invoked" />
        <KeyboardAccelerator Key="Number9" Modifiers="Control"
                             Invoked="NavigateToNumberedTabKeyboardAccelerator_Invoked" />
    </TabView.KeyboardAccelerators>
</TabView>

private void NewTabKeyboardAccelerator_Invoked(KeyboardAccelerator sender,
                                      KeyboardAcceleratorInvokedEventArgs args)
{
    // Create new tab.
    TabView senderTabView = (TabView)args.Element;
    if (senderTabView is not null)
    {
        // (Click handler defined in previous example.)
        TabView_AddTabButtonClick(senderTabView, new EventArgs());
    }
    args.Handled = true;
}

private void CloseSelectedTabKeyboardAccelerator_Invoked(KeyboardAccelerator sender,
                                                KeyboardAcceleratorInvokedEventArgs args)
{
    TabView tabView = (TabView)args.Element;
    TabViewItem tab = (TabViewItem)tabView.SelectedItem;
    if (tab is not null)
    {
        CloseSelectedTab(tabView, tab);
    }
    args.Handled = true;
}

private void TabView_TabCloseRequested(TabView sender, TabViewTabCloseRequestedEventArgs args)
{
    CloseSelectedTab(sender, args.Tab);
}

private void CloseSelectedTab(TabView tabView, TabViewItem tab)
{
    // Only remove the selected tab if it can be closed.
    if (tab.IsClosable == true)
    {
        tabView.TabItems.Remove(tab);
    }
}


private void NavigateToNumberedTabKeyboardAccelerator_Invoked(KeyboardAccelerator sender,
                                                     KeyboardAcceleratorInvokedEventArgs args)
{
    TabView tabView = (TabView)args.Element;
    int tabToSelect = 0;

    switch (sender.Key)
    {
        case Windows.System.VirtualKey.Number1:
            tabToSelect = 0;
            break;
        case Windows.System.VirtualKey.Number2:
            tabToSelect = 1;
            break;
        case Windows.System.VirtualKey.Number3:
            tabToSelect = 2;
            break;
        case Windows.System.VirtualKey.Number4:
            tabToSelect = 3;
            break;
        case Windows.System.VirtualKey.Number5:
            tabToSelect = 4;
            break;
        case Windows.System.VirtualKey.Number6:
            tabToSelect = 5;
            break;
        case Windows.System.VirtualKey.Number7:
            tabToSelect = 6;
            break;
        case Windows.System.VirtualKey.Number8:
            tabToSelect = 7;
            break;
        case Windows.System.VirtualKey.Number9:
            // Select the last tab
            tabToSelect = tabView.TabItems.Count - 1;
            break;
    }

    // Only select the tab if it is in the list.
    if (tabToSelect < tabView.TabItems.Count)
    {
        tabView.SelectedIndex = tabToSelect;
    }
}

UWP と WinUI 2

重要

この記事の情報と例は、Windows App SDK と WinUI 3を使用するアプリ向けに最適化されていますが、一般に、WinUI 2使用する UWP アプリに適用されます。 プラットフォーム固有の情報と例については、UWP API リファレンスを参照してください。

このセクションには、UWP または WinUI 2 アプリでコントロールを使用するために必要な情報が含まれています。

UWP アプリの TabView コントロールは、WinUI 2 の一部として含まれています。 インストール手順を含む詳細については、WinUI 2を参照してください。 このコントロールの API は 、Microsoft.UI.Xaml.Controls 名前空間に存在します。

タブティアアウト API は、WinUI 2 バージョンの TabView には含まれません。

最新の WinUI 2 を使用して、すべてのコントロールの最新のスタイル、テンプレート、および機能を取得することをお勧めします。 WinUI 2.2 以降には、丸い角を使用するこのコントロール用の新しいテンプレートが含まれています。 詳細については、「 コーナー半径」を参照してください。

WinUI 2 でこの記事のコードを使用するには、XAML のエイリアス (muxcを使用) を使用して、プロジェクトに含まれる Windows UI ライブラリ API を表します。 詳細については、「 WinUI 2 の概要 」を参照してください。

xmlns:muxc="using:Microsoft.UI.Xaml.Controls"

<muxc:TabView />