WPF中将Composite组合模式对象绑定到TreeView的实现问题
核心问题定位
你的代码存在4个影响绑定的关键问题:
Box类中的Children是私有字段,WPF绑定仅支持公共属性Leaf和Box均采用显式接口实现ITree的属性,默认绑定规则无法访问显式实现的接口成员- 后台的
ListToBind是字段而非公共属性,不符合绑定要求 - 直接使用单一
HierarchicalDataTemplate无法区分有无子节点的类型,扩展性差
调整后的代码示例
1. 类型定义调整
using System.Collections.ObjectModel; using System.ComponentModel; using System.Runtime.CompilerServices; // 接口可选继承INotifyPropertyChanged,实现属性变更通知 public interface ITree : INotifyPropertyChanged { string Name { get; } string Property1 { get; } string Property2 { get; } } // Leaf类实现 public class Leaf : ITree { // 改为隐式实现接口,改为公共属性 public string Name { get => _name; set { _name = value; OnPropertyChanged(); } } public string Property1 { get => property1; set { property1 = value; OnPropertyChanged(); } } public string Property2 { get => property2; set { property2 = value; OnPropertyChanged(); } } private string _name; private string property1; private string property2; public event PropertyChangedEventHandler PropertyChanged; protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } } // Box类实现 public class Box : ITree { public string Name { get => _name; set { _name = value; OnPropertyChanged(); } } public string Property1 { get => property1; set { property1 = value; OnPropertyChanged(); } } public string Property2 { get => property2; set { property2 = value; OnPropertyChanged(); } } // 改为公共ObservableCollection属性,支持子节点增删自动更新界面 public ObservableCollection<ITree> Children { get; } = new ObservableCollection<ITree>(); private string _name; private string property1; private string property2; public event PropertyChangedEventHandler PropertyChanged; protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } }
2. 后台xaml.cs调整
// 改为公共属性,不要用字段 public ObservableCollection<ITree> ListToBind { get; } = new ObservableCollection<ITree>(); public MainWindow() { InitializeComponent(); ITree finalObject = PopulateCompositeObjeectWithData(); ListToBind.Add(finalObject); }
3. 前端XAML调整
首先确保Window节点设置了正确的x:Name:
<Window x:Class="你的命名空间.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:你的命名空间" x:Name="Window" Title="TreeViewDemo" Height="450" Width="800">
TreeView部分改为按类型匹配模板:
<TreeView ItemsSource="{Binding ElementName=Window, Path=ListToBind}"> <TreeView.Resources> <!-- 复合节点Box的层级模板 --> <HierarchicalDataTemplate DataType="{x:Type local:Box}" ItemsSource="{Binding Children}"> <TextBlock Text="{Binding Name}"/> <!-- 可自行扩展显示Property1、Property2等字段 --> </HierarchicalDataTemplate> <!-- 叶子节点Leaf的普通模板 --> <DataTemplate DataType="{x:Type local:Leaf}"> <TextBlock Text="{Binding Name}"/> </DataTemplate> </TreeView.Resources> </TreeView>
可选兼容方案
如果你必须保留显式接口实现,不需要修改类定义,只需将绑定路径改为指定接口即可:
<TextBlock Text="{Binding Path=(local:ITree.Name)}"/> <HierarchicalDataTemplate DataType="{x:Type local:Box}" ItemsSource="{Binding Path=(local:Box.Children)}">
内容的提问来源于stack exchange,提问作者ilito
相关产品推荐
相关产品推荐

