WPF TabControl和DataTemplates

dus*_*ell 8 wpf tabcontrol datatemplate

我有一组ViewModel,我绑定到TabControl的ItemsSource属性.让我们调用那些ViewModels AViewModel,BViewModel和CViewModel.其中每个都需要有不同的ItemTemplate(对于标题;因为它们每个都需要显示不同的图标)和不同的ContentTemplate(因为它们具有非常不同的交互模型).

我想要的是这样的:

在某处的Resource.xaml文件中定义:

<DataTemplate x:Key="ItemTemplate" DataType="{x:Type AViewModel}">
    ...
</DataTemplate>

<DataTemplate x:Key="ItemTemplate" DataType="{x:Type BViewModel}">
    ...
</DataTemplate>

<DataTemplate x:Key="ItemTemplate" DataType="{x:Type CViewModel}">
    ...
</DataTemplate>

<DataTemplate x:Key="ContentTemplate" DataType="{x:Type AViewModel}">
    ...
</DataTemplate>

<DataTemplate x:Key="ContentTemplate" DataType="{x:Type BViewModel}">
    ...
</DataTemplate>

<DataTemplate x:Key="ContentTemplate" DataType="{x:Type CViewModel}">
    ...
</DataTemplate>
Run Code Online (Sandbox Code Playgroud)

单独定义:

<TabControl ItemTemplate="[ Some way to select "ItemTemplate" based on the type ]"
            ContentTemplate="[ Some way to select "ContentTemplate" based on the type ]"/>
Run Code Online (Sandbox Code Playgroud)

现在,我真实地知道,每次我使用相同的键定义DataTemplate时,系统就会抱怨.但是,有什么我可以做的类似于这将允许我将DataTemplate放入基于名称和数据类型的TabControl?

Lia*_*amV 17

最简单的方法是使用自动模板系统,将DataTemplates包含在ContentControl的资源中.模板的范围仅限于它们所在的元素!

<TabControl ItemsSource="{Binding TabViewModels}">
    <TabControl.ItemTemplate>
        <DataTemplate>
            <ContentControl Content="{Binding}">
                <ContentControl.Resources>
                    <DataTemplate DataType="{x:Type AViewModel}">
                        ...
                    </DataTemplate>
                    <DataTemplate DataType="{x:Type BViewModel}">
                        ...
                    </DataTemplate>
                    <DataTemplate DataType="{x:Type CViewModel}">
                        ...
                    </DataTemplate>
                </ContentControl.Resources>
            </ContentControl>
        </DataTemplate>
    </TabControl.ItemTemplate>
    <TabControl.Resources>
        <DataTemplate DataType="{x:Type AViewModel}">
            ...
        </DataTemplate>
         <DataTemplate DataType="{x:Type BViewModel}">
            ...
        </DataTemplate>
        <DataTemplate DataType="{x:Type CViewModel}">
            ...
        </DataTemplate>
    </TabControl.Resources>
</TabControl>
Run Code Online (Sandbox Code Playgroud)

  • 我的 TabControl 只显示我的视图模型的名称。我如何在 contentTemplate 中显示相应的视图? (2认同)

And*_*mes 8

您可以删除x:Key :)这将在遇到给定类型时自动应用模板(可能是WPF中最强大和未充分利用的功能之一,即imo.

这篇WPF博士的文章很好地介绍了DataTemplates.您需要注意的部分是" 为给定的CLR数据类型定义默认模板 ".

http://www.drwpf.com/blog/Home/tabid/36/EntryID/24/Default.aspx

如果这对您的情况没有帮助,您可以使用Style(ItemContainerStyle)做一些接近您正在寻找的事情,并使用数据触发器根据类型设置内容和标题.

下面的示例取决于您的ViewModel,它具有一个名为"Type"的属性,其定义非常类似(如果您有一个ViewModel,则很容易放入):

public Type Type 
{ 
   get { return this.GetType(); } 
}
Run Code Online (Sandbox Code Playgroud)

所以只要你拥有它,这应该可以让你做任何你想做的事情.注意我有"A Header!" 在这里的文本块中,但很容易就是任何东西(图标等).

我在这里有两种方式......一种风格应用模板(如果你已经对这些进行了大量投资),另一种只使用setter将内容移动到正确的位置.

<Window x:Class="WpfApplication1.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Window1" Height="300" Width="300"
        xmlns:local="clr-namespace:WpfApplication1">
    <Window.Resources>
        <CompositeCollection x:Key="MyCollection">
            <local:AViewModel Header="A Viewmodel" Content="A Content" />
            <local:BViewModel Header="B ViewModel" Content="B Content" />
        </CompositeCollection>

    <DataTemplate x:Key="ATypeHeader" DataType="{x:Type local:AViewModel}">
        <WrapPanel>
            <TextBlock>A Header!</TextBlock>
            <TextBlock Text="{Binding Header}" />
        </WrapPanel>
    </DataTemplate>
    <DataTemplate x:Key="ATypeContent" DataType="{x:Type local:AViewModel}">
        <StackPanel>
            <TextBlock>Begin "A" Content</TextBlock>
            <TextBlock Text="{Binding Content}" />
        </StackPanel>
    </DataTemplate>

    <Style x:Key="TabItemStyle" TargetType="TabItem">
        <Style.Triggers>
            <!-- Template Application Approach-->
            <DataTrigger Binding="{Binding Path=Type}" Value="{x:Type local:AViewModel}">
                <Setter Property="HeaderTemplate" Value="{StaticResource ATypeHeader}" />
                <Setter Property="ContentTemplate" Value="{StaticResource ATypeContent}" />
            </DataTrigger>

            <!-- Just Use Setters Approach -->
            <DataTrigger Binding="{Binding Path=Type}" Value="{x:Type local:BViewModel}">
                <Setter Property="Header">
                    <Setter.Value>
                        <WrapPanel>
                            <TextBlock Text="B Header!"></TextBlock>
                            <TextBlock Text="{Binding Header}" />
                        </WrapPanel>
                    </Setter.Value>
                </Setter>
                <Setter Property="Content" Value="{Binding Content}" />
            </DataTrigger>
        </Style.Triggers>
    </Style>
</Window.Resources>
<Grid>
    <TabControl ItemContainerStyle="{StaticResource TabItemStyle}" ItemsSource="{StaticResource MyCollection}" />
</Grid>
Run Code Online (Sandbox Code Playgroud)

HTH,安德森


Ken*_*art 7

一种方法是使用DataTemplateSelectors并让每个人从一个单独的解析资源ResourceDictionary.