WPF TabControl不同数据源绑定模板问题及DataTemplateSelector使用咨询
首先咱们先搞定你当前MacroRight绑定无效的问题,再一步步实现DataTemplateSelector的方案,这样你能清楚整个流程。
一、修复当前绑定无效的问题
你当前的代码里,TabItem的Content属性是空的,而ContentTemplate里的ContentPresenter用了ContentSource="{Binding MacroRight}"——这其实是个误区,ContentSource是用来绑定到当前元素的某个属性(比如Content),不是直接绑定DataContext里的属性。
要让MacroRight正确绑定,你需要把TabItem的Content直接绑定到MacroRight,然后指定ContentTemplate为你的TemplateType1:
<TabItem Header="{x:Static p:Resources.Type1_Right}" Style="{StaticResource VerticalTabItem}" Content="{Binding MacroRight}"> <TabItem.ContentTemplate> <StaticResource ResourceKey="TemplateType1"/> </TabItem.ContentTemplate> </TabItem>
这样ContentPresenter会自动把TabItem的Content(也就是MacroRight对象)作为数据源,应用你的模板,绑定就能生效了。
二、使用DataTemplateSelector实现多模板切换
如果你需要根据数据源是单个对象还是ObservableCollection自动选择不同模板,DataTemplateSelector是最优方案,下面是具体步骤:
1. 创建自定义的TemplateSelector类
在你的项目里新建一个类,继承DataTemplateSelector,重写SelectTemplate方法,根据数据类型返回对应模板:
using System.Collections.ObjectModel; using System.Windows; using System.Windows.Controls; // 替换成你实际的单个对象类型 public class YourMacroType { /* 你的对象属性,比如Name、Bottom等 */ } public class MacroTemplateSelector : DataTemplateSelector { // 单个对象对应的模板 public DataTemplate SingleObjectTemplate { get; set; } // 集合对应的模板 public DataTemplate CollectionTemplate { get; set; } public override DataTemplate SelectTemplate(object item, DependencyObject container) { if (item is ObservableCollection<YourMacroType>) { return CollectionTemplate; } else if (item is YourMacroType) { return SingleObjectTemplate; } // 默认返回基类的模板(如果需要可以自定义) return base.SelectTemplate(item, container); } }
2. 在XAML中定义模板和Selector
在你的Window/UserControl的Resources里,先定义两个模板(单个对象的TemplateType1和集合的模板),然后实例化自定义的Selector并关联这两个模板:
<!-- 先添加命名空间,指向Selector所在的程序集 --> <UserControl xmlns:local="clr-namespace:YourProjectNamespace" ...> <UserControl.Resources> <!-- 单个对象的模板(你原来的TemplateType1) --> <DataTemplate x:Key="TemplateType1" > <StackPanel> <Grid Background="{StaticResource WindowBackgroundColor}"> <!-- 省略你原有模板的内容 --> </Grid> </StackPanel> </DataTemplate> <!-- 集合的模板:用ListView展示集合中的每个项,复用单个对象的模板 --> <DataTemplate x:Key="CollectionTemplate"> <ListView ItemsSource="{Binding}"> <ListView.ItemTemplate> <DataTemplate> <ContentPresenter Content="{Binding}" ContentTemplate="{StaticResource TemplateType1}"/> </DataTemplate> </ListView.ItemTemplate> </ListView> </DataTemplate> <!-- 实例化自定义的TemplateSelector --> <local:MacroTemplateSelector x:Key="MacroTemplateSelector" SingleObjectTemplate="{StaticResource TemplateType1}" CollectionTemplate="{StaticResource CollectionTemplate}"/> </UserControl.Resources> <!-- 你的TabControl和TabItem --> <TabControl> <!-- 绑定单个对象的TabItem --> <TabItem Header="{x:Static p:Resources.Type1_Right}" Style="{StaticResource VerticalTabItem}" Content="{Binding MacroRight}"> <TabItem.ContentTemplateSelector> <StaticResource ResourceKey="MacroTemplateSelector"/> </TabItem.ContentTemplateSelector> </TabItem> <!-- 绑定ObservableCollection的TabItem --> <TabItem Header="{x:Static p:Resources.Type2_Collection}" Style="{StaticResource VerticalTabItem}" Content="{Binding MacroCollection}"> <TabItem.ContentTemplateSelector> <StaticResource ResourceKey="MacroTemplateSelector"/> </TabItem.ContentTemplateSelector> </TabItem> </TabControl> </UserControl>
3. 关键说明
- 确保你的TabItem的
DataContext包含MacroRight(单个对象)和MacroCollection(ObservableCollection)属性; - 集合模板里我用了
ListView,你可以根据需求换成ItemsControl、DataGrid等; - 如果你的单个对象类型不是
YourMacroType,记得替换成你实际的类名。
这样设置后,TabControl会自动根据每个TabItem绑定的数据源类型,选择对应的模板展示内容啦!
内容的提问来源于stack exchange,提问作者Siegfried.V

