我有一组我绑定到一个TabControl的ItemsSource属性的ViewModels的。 让我们把那些的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>
分别定义:
<TabControl ItemTemplate="[ Some way to select "ItemTemplate" based on the type ]"
ContentTemplate="[ Some way to select "ContentTemplate" based on the type ]"/>
现在,我知道,现实,每次我定义具有相同的密钥系统只是去抱怨一个DataTemplate。 但是,是有什么我可以做的,它类似于此,这将让我把一个DataTemplate到基于名称和数据类型的TabControl的?
一种方法是使用DataTemplateSelector
S和各有一个解决资源从一个单独ResourceDictionary
。
最简单的方法是使用自动模板系统,通过在一个ContentControl中的资源的DataTemplates。 模板的范围仅限于它们所在内的元素!
<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>
您可以删除X:关键:)当给定类型遇到(可能是WPF的最强大的和未充分利用的功能之一,国际海事组织这将自动应用模板。
这WPF博士本文将详细的DataTemplates相当不错。 你要注意部分“ 定义默认模板对于给定的CLR数据类型 ”。
http://www.drwpf.com/blog/Home/tabid/36/EntryID/24/Default.aspx
如果这没有帮助你的情况,你也许能够做一些接近你在找什么用样式(ItemContainerStyle)以及基于使用数据触发类型的内容和标题。
下面的示例取决于其定义非常喜欢这样(轻松的放进一个基础视图模型,如果你有一个)被称为“类型”属性的视图模型:
public Type Type
{
get { return this.GetType(); }
}
所以只要你有,这应该让你做任何你想要的。 注意:我有“头!” 在这里一个文本块,但很容易被任何东西(图标等)。
我在这里两个方面得到了它......一个样式适用模板(如果你有这些已经是显著投资)和其他只使用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>
HTH,安德森
在这个例子中,我用我的资源部分的DataTemplates TabControl
,因为我想在标签项目上显示每个视图模型。 在这种情况下,我映射ViewModelType1
到View1
和ViewModelType2
到View2
。 视图模型将被设置为DataContext
自动的看法对象。
为了显示标签项头,我使用ItemTemplate
。 视图模型我绑定到不同类型的,而是从一个共同的基类派生ChildViewModel
,有一个Title
属性。 所以,我可以建立一个绑定拿起标题标签项目标题来显示它。
此外,我在显示选项卡项目标头中的“关闭”按钮。 如果你不需要的是,只是删除从示例代码的按钮,所以你只要在标题文本。
的标签的项目的内容物被用一个简单ItemTemplate
,其与内容显示视图在内容控制=“{结合}”。
<UserControl ...>
<UserControl.DataContext>
<ContainerViewModel></ContainerViewModel>
</UserControl.DataContext>
<TabControl ItemsSource="{Binding ViewModels}"
SelectedItem="{Binding SelectedViewModel}">
<TabControl.Resources>
<DataTemplate DataType="{x:Type ViewModelType1}">
<View1/>
</DataTemplate>
<DataTemplate DataType="{x:Type ViewModelType2}">
<View2/>
</DataTemplate>
</TabControl.Resources>
<TabControl.ItemTemplate>
<DataTemplate>
<DockPanel>
<TextBlock Text="{Binding Title}" />
<Button DockPanel.Dock="Right" Margin="5,0,0,0"
Visibility="{Binding RemoveButtonVisibility}"
Command="{Binding DataContext.CloseItemCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type TypeOfContainingView}}}"
>
<Image Source="/Common/Images/ActiveClose.gif"></Image>
</Button>
</DockPanel>
</DataTemplate>
</TabControl.ItemTemplate>
<TabControl.ContentTemplate>
<DataTemplate>
<ContentControl Content="{Binding}"/>
</DataTemplate>
</TabControl.ContentTemplate>
</TabControl>
</UserControl>
其中包含的标签控制用户控制具有类型的容器视图模型ContainerViewModel
作为DataContext
。 在这里,我必须在标签控件中显示的所有视图模型的集合。 我也有当前所选视图模型(标签项目)的属性。
这是我的容器视图模型的缩短版(我跳过了变更通知的部分)。
public class ContainerViewModel
{
/// <summary>
/// The child view models.
/// </summary>
public ObservableCollection<ChildViewModel> ViewModels {get; set;}
/// <summary>
/// The currently selected child view model.
/// </summary>
public ChildViewModel SelectedViewModel {get; set;}
}
约什-史密斯正是使用这一技术在他的优秀文章和示例项目(驱动与视图模型集合的标签控制的) WPF应用程序与模型-视图-视图模型设计模式 。 在这种方法中,因为虚拟机集合中的每个项目都有一个相应的DataTemplate链接查看到VM类型(通过省略X:关键安德森艾姆斯正确地指出),每个标签可以有一个完全不同的UI。 详情请参阅完整的文章和源代码。
XAML中的关键部分是:
<DataTemplate DataType="{x:Type vm:CustomerViewModel}">
<vw:CustomerView />
</DataTemplate>
<DataTemplate x:Key="WorkspacesTemplate">
<TabControl
IsSynchronizedWithCurrentItem="True"
ItemsSource="{Binding}"
ItemTemplate="{StaticResource ClosableTabItemTemplate}"
Margin="4"
/>
有一个缺点 - 从驾驶WPF TabControl的一个的ItemsSource有性能问题,如果标签中的UI大/复杂,因此缓慢的绘制(例如,大量数据的数据网格)。 有关这方面的问题,所以搜索“WPF VirtualizingStackPanel以提高性能”。