简体   繁体   English

为 WPF TabControl 配置动态标题

[英]Configuring dynamic headers for a WPF TabControl

I am trying to make a basic window that uses a WPF TabControl to allow users to add new tabs.我正在尝试制作一个基本的 window ,它使用 WPF TabControl 来允许用户添加新标签。 I want the end product to look somewhat like the way tabs work in a web browser where the last tab is just a "+" that when clicked it will add a new tab.我希望最终产品看起来有点像 web 浏览器中选项卡的工作方式,其中最后一个选项卡只是一个“+”,单击它会添加一个新选项卡。

I am trying to write the XAML code to set this up and I found that I can specify multiple DataTemplates within "TabControl.Resources" and based on the "DataType" the correct DataTemplate will be used to display the correct view for each tab... but when dealing with the tab headers I can only specify a single DataTemplate for "TabControl.ItemTemplate"我正在尝试编写 XAML 代码来设置它,我发现我可以在“TabControl.Resources”中指定多个 DataTemplates,并且基于“DataType”,正确的 DataTemplate 将用于显示每个选项卡的正确视图。 . 但是在处理选项卡标题时,我只能为“TabControl.ItemTemplate”指定一个 DataTemplate

This is what I have so far:这是我到目前为止所拥有的:

<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>

Googling around I found some articles on setting up a TemplateSelector and writing a bunch of background C# code, but that seems drastically overkill for something this simple.谷歌搜索,我发现了一些关于设置 TemplateSelector 和编写一堆背景 C# 代码的文章,但这对于这么简单的事情来说似乎太过分了。 I just want it to display the tab name if it is a regular TabViewModel object and a "+" if it is a NewTabViewModel object.如果它是常规 TabViewModel object,我只希望它显示选项卡名称,如果它是 NewTabViewModel object,则显示“+”。

There's two completely different uses of DataTemplate here.这里有两种完全不同的 DataTemplate 用途。

An ItemTemplate property is of type DataTemplate. ItemTemplate 属性属于 DataTemplate 类型。 Specifically, one DataTemplate, not a collection.具体来说,一个 DataTemplate,而不是一个集合。 It's expecting you to set that to whatever template you need, and that's what it will use to populate the tab header.它期望您将其设置为您需要的任何模板,这就是它将用于填充选项卡 header 的内容。 Furthermore, in the case of TabControl, that's the template that will get applied to all headers;此外,在 TabControl 的情况下,该模板将应用于所有标题; you don't get to change it on a per-tab basis.你不能在每个标签的基础上改变它。

The tab panels themselves are of type ContentControl, with each one bound to a view model.选项卡面板本身是 ContentControl 类型,每个都绑定到视图 model。 A ContentControl contains a ContentPresenter, which traverses the logical tree looking for a DataTemplate for the data type that it has been bound to (internally, the DataTemplate's DataType property is just syntactic sugar for setting the type itself as the x:Key). ContentControl 包含一个 ContentPresenter,它遍历逻辑树,为其绑定的数据类型查找 DataTemplate(在内部,DataTemplate 的 DataType 属性只是将类型本身设置为 x:Key 的语法糖)。

Your problem is that you're trying to use the ItemTemplate like a ResourceDictionary, specifying multiple DataTemplates, when it's expecting you to provide the template itself, and only one.您的问题是您尝试像 ResourceDictionary 一样使用 ItemTemplate,指定多个 DataTemplates,而它希望您提供模板本身,并且只提供一个。 So to implement what you're after, all you need to do is give it a DataTemplate and populate it with a ContentPresenter (as suggested by Dreamer), the same as the tab panel itself has.所以要实现你所追求的,你需要做的就是给它一个 DataTemplate 并用一个 ContentPresenter 填充它(正如 Dreamer 所建议的那样),就像选项卡面板本身一样。 This ContentPresenter has its own ResourceDictionary, and that's where you can put your header templates:此 ContentPresenter 有自己的 ResourceDictionary,您可以在其中放置 header 模板:

<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>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM