如何在WPF TreeView中展示含ConfiguratorAttribute的多层级数据
解决WPF TreeView显示ConfiguratorAttributeViewModel的问题
核心问题分析
当前TreeView模板存在两个关键问题:
ConfiguratorObjectViewModel的HierarchicalDataTemplate存在语法错误(ItemsSource="{Binding }" Children是无效写法)- 未将
ConfiguratorObjectViewModel的Attributes集合作为子节点纳入TreeView层级
由于ConfiguratorAttributeViewModel本身无层级结构,只需为它定义普通DataTemplate即可,无需使用HierarchicalDataTemplate。
方案一:ViewModel层合并子项集合(推荐)
在ConfiguratorObjectViewModel中新增一个合并了Attributes和Children的集合,让TreeView可以直接绑定这个统一的子项集合:
public class ConfiguratorObjectViewModel { public string Name { get; set; } public string Id { get; set; } public string ParentId { get; set; } public ObservableCollection<ConfiguratorAttributeViewModel> Attributes { get; set; } public ObservableCollection<ConfiguratorObjectFamilyViewModel> Children { get; set; } // 合并属性与子家族的集合,供TreeView绑定 public ObservableCollection<object> CombinedChildItems { get; } public ConfiguratorObjectViewModel() { Attributes = new ObservableCollection<ConfiguratorAttributeViewModel>(); Children = new ObservableCollection<ConfiguratorObjectFamilyViewModel>(); CombinedChildItems = new ObservableCollection<object>(); // 监听集合变化,自动同步合并集合 Attributes.CollectionChanged += (s, e) => SyncCombinedItems(e, Attributes); Children.CollectionChanged += (s, e) => SyncCombinedItems(e, Children); } private void SyncCombinedItems(NotifyCollectionChangedEventArgs e, IEnumerable items) { switch (e.Action) { case NotifyCollectionChangedAction.Add: foreach (var item in e.NewItems) CombinedChildItems.Add(item); break; case NotifyCollectionChangedAction.Remove: foreach (var item in e.OldItems) CombinedChildItems.Remove(item); break; case NotifyCollectionChangedAction.Reset: CombinedChildItems.Clear(); foreach (var attr in Attributes) CombinedChildItems.Add(attr); foreach (var family in Children) CombinedChildItems.Add(family); break; } } }
修正后的TreeView模板
<TreeView ItemsSource="{Binding RootObject}" > <TreeView.Resources> <!-- 家族节点模板:子项为ConfiguratorObject --> <HierarchicalDataTemplate DataType="{x:Type local:ConfiguratorObjectFamilyViewModel}" ItemsSource="{Binding ConfiguratorObjects}"> <local:ConfiguratorObjectTreeItem /> </HierarchicalDataTemplate> <!-- 对象节点模板:子项为合并后的属性和子家族 --> <HierarchicalDataTemplate DataType="{x:Type local:ConfiguratorObjectViewModel}" ItemsSource="{Binding CombinedChildItems}"> <local:ConfiguratorObjectTreeItem /> </HierarchicalDataTemplate> <!-- 属性节点模板:无层级,直接显示 --> <DataTemplate DataType="{x:Type local:ConfiguratorAttributeViewModel}"> <local:ConfiguratorObjectTreeItem /> </DataTemplate> </TreeView.Resources> </TreeView>
方案二:XAML层用CompositeCollection合并集合(无需修改ViewModel)
如果不想改动ViewModel,可以在XAML中通过CompositeCollection直接合并Attributes和Children:
<TreeView ItemsSource="{Binding RootObject}" > <TreeView.Resources> <HierarchicalDataTemplate DataType="{x:Type local:ConfiguratorObjectFamilyViewModel}" ItemsSource="{Binding ConfiguratorObjects}"> <local:ConfiguratorObjectTreeItem /> </HierarchicalDataTemplate> <HierarchicalDataTemplate DataType="{x:Type local:ConfiguratorObjectViewModel}"> <local:ConfiguratorObjectTreeItem /> <!-- 合并Attributes和Children作为子节点 --> <HierarchicalDataTemplate.ItemsSource> <CompositeCollection> <CollectionContainer Collection="{Binding Attributes, RelativeSource={RelativeSource AncestorType=local:ConfiguratorObjectViewModel}}" /> <CollectionContainer Collection="{Binding Children, RelativeSource={RelativeSource AncestorType=local:ConfiguratorObjectViewModel}}" /> </CompositeCollection> </HierarchicalDataTemplate.ItemsSource> </HierarchicalDataTemplate> <DataTemplate DataType="{x:Type local:ConfiguratorAttributeViewModel}"> <local:ConfiguratorObjectTreeItem /> </DataTemplate> </TreeView.Resources> </TreeView>
注意:使用
CompositeCollection时,CollectionContainer的绑定需要通过RelativeSource指定数据上下文,因为它不在TreeView的视觉树中,直接绑定可能无法找到目标属性。
内容的提问来源于stack exchange,提问作者jnce
相关产品推荐
相关产品推荐

