Настройка динамических c заголовков для WPF TabControl - PullRequest
0 голосов
/ 30 апреля 2020

Я пытаюсь создать базовое c окно, которое использует WPF TabControl, чтобы позволить пользователям добавлять новые вкладки. Я хочу, чтобы конечный продукт выглядел примерно так, как работают вкладки в веб-браузере, где последняя вкладка представляет собой просто «+», при нажатии на которую добавляется новая вкладка.

Я пытаюсь написать XAML код, чтобы настроить это, и я обнаружил, что я могу указать несколько DataTemplates в "TabControl.Resources" и на основе "DataType" правильный DataTemplate будет использоваться для отображения правильного представления для каждой вкладки ... но при работе с вкладкой Заголовки Я могу указать только один DataTemplate для "TabControl.ItemTemplate"

. Это то, что у меня есть:

<TabControl ItemsSource="{Binding Tabs}">
    <TabControl.Resources>

        <!-- If the tab is of type "TabViewModel" I want this content -->
        <DataTemplate DataType="x:Type vm:TabViewModel">
            <!-- TabView is defined as a separate user control -->
            <v:TabView/>
        </DataTemplate>

        <!-- If the tab is of type "NewTabViewModel" I want this content -->
        <DataTemplate DataType="x:Type vm:NewTabViewModel">
            <!-- NewTabView is defined as a separate user control -->
            <v:NewTabView/>
        </DataTemplate>
    </TabControl.Resources>

    <TabControl.ItemTemplate>
        <!-- if the tab is of type "TabViewModel" I want this header -->
        <DataTemplate DataType="x:Type vm:TabViewModel">
            <TextBlock Text="{Binding Name}"/>
        </DataTemplate>

        <!-- If the tab is of type "NewTabViewModel" I want this header -->
        <!-- ERROR: Adding a second "DataTemplate" here results in an error -->
        <DataTemplate DataType="x:Type vm:NewTabViewModel">
            <TextBlock Text="+"/>
        </DataTemplate>
    </TabControl.ItemTemplate>
</TabControl>

Поиск в Google Я нашел несколько статей по настройке TemplateSelector и написанию куча фонового C# кода, но это кажется чрезмерно излишним для чего-то такого простого. Я просто хочу, чтобы он отображал имя вкладки, если это обычный объект TabViewModel, и "+", если это объект NewTabViewModel.

1 Ответ

2 голосов
/ 01 мая 2020

Здесь есть два совершенно разных использования DataTemplate.

Свойство ItemTemplate имеет тип DataTemplate. В частности, один DataTemplate, а не коллекция. Он ожидает, что вы установите его в соответствии с тем шаблоном, который вам нужен, и именно это он будет использовать для заполнения заголовка вкладки. Кроме того, в случае TabControl это шаблон, который будет применен к всем заголовкам; Вы не можете изменять его отдельно для каждой вкладки.

Сами панели вкладок имеют тип ContentControl, каждая из которых связана с моделью представления. ContentControl содержит ContentPresenter, который перебирает логическое дерево в поисках DataTemplate для типа данных, к которому он был привязан (внутренне свойство DataTemplate DataTemplate просто syntacti c sugar для установки самого типа в качестве x: Key) .

Ваша проблема в том, что вы пытаетесь использовать ItemTemplate как ResourceDictionary, указав несколько DataTemplate, когда вы ожидаете, что вы предоставите сам шаблон, и только один. Таким образом, чтобы реализовать то, что вам нужно, все, что вам нужно сделать, это дать ему DataTemplate и заполнить его ContentPresenter (как это было предложено Dreamer), так же, как и на самой панели вкладок. Этот ContentPresenter имеет свой собственный ResourceDictionary, и здесь вы можете поместить свои шаблоны заголовков:

<TabControl ItemsSource="{Binding Tabs}">

    <TabControl.Resources>

        <!-- Panel templates -->

        <DataTemplate DataType="{x:Type vm:TabViewModel}">
            <v:TabView />
        </DataTemplate>

        <DataTemplate DataType="{x:Type vm:NewTabViewModel}">
            <v:NewTabView />
        </DataTemplate>
    </TabControl.Resources>

    <TabControl.ItemTemplate>
        <DataTemplate>
            <ContentPresenter Content="{Binding}">
                <ContentPresenter.Resources>

                    <!-- Header templates -->

                    <DataTemplate DataType="{x:Type vm:TabViewModel}">
                        <TextBlock Text="{Binding Name}"/>
                    </DataTemplate>

                    <DataTemplate DataType="{x:Type vm:NewTabViewModel}">
                        <TextBlock Text="+"/>
                    </DataTemplate>

                </ContentPresenter.Resources>
            </ContentPresenter>
        </DataTemplate>
    </TabControl.ItemTemplate>
</TabControl>
...