1. 理解MVVM模式下的TreeView数据绑定
在WPF开发中,TreeView控件是展示层级数据的利器,而MVVM模式则是构建可维护应用程序的最佳实践。当这两者结合时,我们需要理解几个关键概念:
首先,MVVM模式将应用程序分为三个部分:Model(数据模型)、View(用户界面)和ViewModel(业务逻辑)。在TreeView的场景中,Model代表我们的树形数据结构,View是XAML中定义的TreeView控件,而ViewModel则负责准备数据和命令。
数据绑定的核心要素包括:
- 节点模型类:实现INotifyPropertyChanged接口,确保属性变更能通知UI
- HierarchicalDataTemplate:定义树节点的可视化结构和子项绑定
- ObservableCollection:动态集合,当集合变化时自动更新UI
我曾在项目中遇到过TreeView性能问题,当节点数量超过5000时,界面会出现明显卡顿。后来发现是因为没有正确使用MVVM模式的数据绑定机制,导致每次数据更新都触发了完整的UI重绘。
2. 构建基础树形数据结构
2.1 设计节点模型
一个典型的树节点类应该包含以下基本属性:
public class TreeNode : INotifyPropertyChanged
{
private string _name;
public string Name
{
get => _name;
set { _name = value; OnPropertyChanged(); }
}
private ObservableCollection<TreeNode> _children;
public ObservableCollection<TreeNode> Children
{
get => _children ??= new ObservableCollection<TreeNode>();
set { _children = value; OnPropertyChanged(); }
}
// 支持展开/选中状态绑定
private bool _isExpanded;
public bool IsExpanded
{
get => _isExpanded;
set { _isExpanded = value; OnPropertyChanged(); }
}
private bool _isSelected;
public bool IsSelected
{
get => _isSelected;
set { _isSelected = value; OnPropertyChanged(); }
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string name = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
}
这个模型类有几个关键点需要注意:
- 实现了INotifyPropertyChanged接口,确保属性变更能通知UI
- Children属性使用ObservableCollection,自动处理集合变更
- 包含了IsExpanded和IsSelected属性,用于双向绑定节点的展开和选中状态
2.2 准备ViewModel
ViewModel负责准备树形数据和命令:
public class MainViewModel : INotifyPropertyChanged
{
public ObservableCollection<TreeNode> TreeData { get; } = new();
// 节点选中命令
public ICommand NodeSelectedCommand { get; }
public MainViewModel()
{
// 初始化树数据
TreeData.Add(new TreeNode {
Name = "根节点1",
Children = {
new TreeNode { Name = "子节点1-1" },
new TreeNode {
Name = "子节点1-2",
Children = {
new TreeNode { Name = "孙节点1-2-1" }
}
}
}
});
TreeData.Add(new TreeNode {
Name = "根节点2",
Children = {
new TreeNode { Name = "子节点2-1" }
}
});
// 初始化命令
NodeSelectedCommand = new RelayCommand<TreeNode>(node =>


5028

被折叠的 条评论
为什么被折叠?



