WPF中TreeView控件数据绑定和后台动态添加数据(二)
写在前面:在(一)中,介绍了TreeView控件MVVM模式下数据绑定的方法。在这篇文章中,将总结给节点添加事件的方法,这样说有些不对,总之实现的效果就是点击某个节点,将出现对应于该节点的页面或者数据。(我这里用的方法肯定不是最好的,但是是我能想到的最佳方法了,WPF初学者,希望大家多多指教。)
Example#1: 实现下图功能,点击左侧treeview姓名节点,在右侧会出现响应的detailed information. 可以将ID的textbox中的text属性绑定到treeview中SelectedItem

先构造两个类,一个是User,一个是TreeNode。User是TreeNode的一个属性。

public class User
{
public string Key { get; set; }
public string Name { get; set; }
public int? Age { get; set; } public User()
{
Key = null;
Name = null;
Age = null;
}
}
User

public class TreeNode
{
public int NodeID { get; set; }
public int ParentID { get; set; }
public string NodeName { get; set; }
public List<TreeNode> ChildNodes { get; set; }
public User user { get; set; } public TreeNode()
{
ChildNodes = new List<TreeNode>();
user = new User();
}
}
TreeNode
绑定:
<TreeView Grid.Column="0" FontSize="15" ItemsSource="{Binding Path=Nodes}" x:Name="treeview">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate DataType="{x:Type local:TreeNode}" ItemsSource="{Binding Path=ChildNodes}">
<Label Content="{Binding Path=NodeName}"/>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
<TextBox Text="{Binding ElementName=treeview, Path=SelectedItem.user.Key}" Canvas.Left="70" Width="200" Canvas.Top="8"
FontSize="15"/>
<TextBox Text="{Binding ElementName=treeview, Path=SelectedItem.user.Age}" Canvas.Left="70" Width="200" Canvas.Top="8"
FontSize="15"/>
上面两句TextBox控件,就是将项目中名为“treeview"的控件的SelectedItem.user.Key和SeletedItem.user.Age的值绑定到Text属性中。这样点”Lily"节点,右侧就会出现相应的信息。
Example#2:
上面的例子比较简单,第二个例子将button控件作为treeviewitem,并给button控件绑定一个Command。
场景描述:左侧是treeview,其中每个treeviewitem的元素都是button控件,点击每个节点,中间的listview中会出现符合条件的学生的姓名,比如,是Grade1的学生有Lucy, Tom和Lily三人。是Grade2Class1的学生有Sam和Jack两人。点击listview中的学生姓名,右侧会显示学生的ID和Age信息。


TreeView部分的XAML代码:
<TreeView Grid.Column="0" FontSize="15" ItemsSource="{Binding Path=Nodes}">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate DataType="{x:Type local:TreeNode}" ItemsSource="{Binding Path=ChildNodes}">
<Button Content="{Binding NodeName}" Command="{Binding DataContext.TreeViewCommand,
RelativeSource={RelativeSource AncestorType=local:MainWindow}}" CommandParameter="{Binding Path=NodeID}"
Background="White" BorderThickness="0"/>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
可以看见,TreeViewItem元素从Label变成了Button。其中Button控件绑定了一个TreeViewCommand。这里需要指明绑定的是DataContext下的TreeViewCommand,否则默认的是TreeNode类型中的TreeViewCommand属性。因此下面这句是非常关键的。
Command="{Binding DataContext.TreeViewCommand,
RelativeSource={RelativeSource AncestorType=local:MainWindow}}" CommandParameter="{Binding Path=NodeID}"
ListView部分的XAML代码:
<ListView Name="listview" Grid.Column="1" ItemsSource="{Binding Users}" IsSynchronizedWithCurrentItem="True"
BorderBrush="DarkGray" BorderThickness="5">
<ListView.View>
<GridView>
<GridViewColumn Header="Name" DisplayMemberBinding="{Binding Path=Name}" Width="auto"/>
</GridView>
</ListView.View>
</ListView>
ViewModel代码:

public class ViewModel :INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private List<User> userlist = new List<User>();
private List<TreeNode> nodes;
public List<TreeNode> Nodes
{
get { return nodes; }
set { nodes = value;
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs("Nodes"));
}
}
private List<User> users = new List<User>();
public List<User> Users
{
get { return users; }
set { users = value;
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs("Users"));
} } public DelegateCommand TreeViewCommand { get; } public ViewModel()
{
// 初始化Nodes和Users,一般Users是要访问数据库得到的,这里进行了简化。
InitiateNodes();
InitiateUsers();
TreeViewCommand = new DelegateCommand(TreeViewCommandHandler);
} private void TreeViewCommandHandler(object sender, DelegateCommandEventArgs e)
{
int id = Convert.ToInt32(e.Parameter);
switch (id)
{
case 1:
Users = userlist.Where(x => x.GradeNum == 1).ToList();
break;
case 2:
Users = userlist.Where(x => x.GradeNum == 2).ToList();
break;
case 3:
Users = userlist.Where(x => x.GradeNum == 3).ToList();
break;
case 4:
Users = userlist.Where(x => x.GradeNum == 1 && x.ClassNum == 1).ToList();
break;
case 5:
Users = userlist.Where(x => x.GradeNum == 1 && x.ClassNum == 2).ToList();
break;
case 6:
Users = userlist.Where(x => x.GradeNum == 2 && x.ClassNum == 1).ToList();
break;
case 7:
Users = userlist.Where(x => x.GradeNum == 2 && x.ClassNum == 2).ToList();
break;
case 8:
Users = userlist.Where(x => x.GradeNum == 3 && x.ClassNum == 1).ToList();
break;
case 9:
Users = userlist.Where(x => x.GradeNum == 3 && x.ClassNum == 2).ToList();
break;
}
} #region Initial methods
private void InitiateNodes()
{
List<TreeNode> _nodes = new List<TreeNode>()
{
new TreeNode()
{
ParentID=0,NodeID=1,NodeName="Grade1"
},
new TreeNode()
{
ParentID=0,NodeID=2,NodeName="Grade2"
},
new TreeNode()
{
ParentID=0, NodeID=3, NodeName="Grade3"
},
new TreeNode(){ParentID=1,NodeID=4,NodeName="Class1"},
new TreeNode(){ParentID=1,NodeID=5,NodeName="Class2"},
new TreeNode(){ParentID=2,NodeID=6,NodeName="Class1"},
new TreeNode(){ParentID=2, NodeID=7, NodeName="Class2"},
new TreeNode(){ParentID=3, NodeID=8, NodeName="Class1"},
new TreeNode(){ParentID=3, NodeID=9, NodeName="Class2"}
};
Nodes = getChildNodes(0, _nodes); } private List<TreeNode> getChildNodes(int parentID, List<TreeNode> nodes)
{
List<TreeNode> mainNodes = nodes.Where(x => x.ParentID == parentID).ToList();
List<TreeNode> otherNodes = nodes.Where(x => x.ParentID != parentID).ToList();
foreach (TreeNode node in mainNodes)
node.ChildNodes = getChildNodes(node.NodeID, otherNodes);
return mainNodes;
} private void InitiateUsers()
{
User Lily = new User()
{
Name = "Lily",
Age = 12,
GradeNum = 1,
ClassNum = 1
};
User Tom = new User()
{
Name = "Tom",
Age = 11,
GradeNum = 1,
ClassNum = 1
};
User Lucy = new User()
{
Name = "Lucy",
Age = 12,
GradeNum = 1,
ClassNum = 2
};
User Sam = new User()
{
Name = "Sam",
Age = 13,
GradeNum = 2,
ClassNum = 1
};
User Jack = new User() { Name = "Jack", Age = 13, GradeNum = 2, ClassNum = 1 };
User Ray = new User() { Name = "Ray", Age = 13, GradeNum = 2, ClassNum = 2 };
User Lisa = new User() { Name = "Lisa", Age = 14, GradeNum = 3, ClassNum = 1 };
User Liz = new User() { Name = "Liz", Age = 14, GradeNum = 3, ClassNum = 2 };
userlist.Add(Liz);
userlist.Add(Lisa);
userlist.Add(Sam);
userlist.Add(Lucy);
userlist.Add(Tom);
userlist.Add(Lily);
userlist.Add(Jack);
userlist.Add(Ray);
} #endregion
}
ViewModel
其中有两个类,DelegateCommand和DelegateCommandEventArgs,是继承自ICommand,然后委托方法的。

public class DelegateCommand : ICommand
{
// 定义一个名为SimpleEventHandler的委托,两个参数,一个object类,一个是自定义的DelegateCommandEventArgs类
public delegate void SimpleEventHandler(object sender, DelegateCommandEventArgs e);
// handler是方法,别忘了,委托是用于定义方法的类
private SimpleEventHandler handler;
private bool isEnabled = true; public DelegateCommand(SimpleEventHandler handler)
{
this.handler = handler;
}
public void Execute(object parameter)
{
this.handler(this, new DelegateCommandEventArgs(parameter));
}
public bool CanExecute(object parameter)
{
return this.isEnabled;
}
public event EventHandler CanExecuteChanged;
public bool IsEnabled
{
get { return this.isEnabled; }
set
{
this.isEnabled = value;
this.OnCanExecuteChanged();
}
}
private void OnCanExecuteChanged()
{
if (this.CanExecuteChanged != null)
this.CanExecuteChanged(this, EventArgs.Empty);
}
}
DelegateCommand

public class DelegateCommandEventArgs : EventArgs
{
private object parameter;
public DelegateCommandEventArgs(object parameter)
{
this.parameter = parameter;
}
public object Parameter
{
get { return this.parameter; }
}
}
DelegateCommandEventArgs
2020.06.25更新内容
之前使用Button控件作为TreeViewItem,然后为Button的Command属性绑定事件。更新为直接将事件绑定为TreeView的SelectedItemChanged属性,同样可以实现一样的效果。详情可见:
https://www.cnblogs.com/larissa-0464/p/13186486.html
2021.12.14 关于TreeView控件的demo:
WPF中常用控件(TreeView, ComboBox, DataGrid, ListView)使用MVVM模式绑定的demo - 南风小斯 - 博客园 (cnblogs.com)
WPF中TreeView控件数据绑定和后台动态添加数据(二)的更多相关文章
- WPF中TreeView控件数据绑定和后台动态添加数据(一)
数据绑定: 更新内容:补充在MVVM模式上的TreeView控件数据绑定的代码. xaml代码: <TreeView Name="syntaxTree" ItemsSourc ...
- WPF中TreeView控件SelectedItemChanged方法的MVVM绑定
问题描述:左侧treeview控件中点击不同类别的节点时,右侧的页面会显示不同的权限.比如对于My Publications,拥有Modify和Delete两种权限,对于My Subscription ...
- WPF中TreeView控件的使用案例
WPF总体来说还是比较方便的,其中变化最大的主要是Listview和Treeview控件,而且TreeView似乎在WPF是一个备受指责的控件,很多人说他不好用.我这个demo主要是在wpf中使用Tr ...
- WPF中PasswordBox控件的Password属性的数据绑定
原文:WPF中PasswordBox控件的Password属性的数据绑定 英文原文:http://www.wpftutorial.net/PasswordBox.html 中文原文:http://bl ...
- WPF中Image控件的Source属性
原文:WPF中Image控件的Source属性 imgBook 是一个Image控件,在后台代码中我想给它指定Source的属性.我先如下方式进行: Uri uri = new Uri(strImag ...
- 示例:WPF中Slider控件封装的缓冲播放进度条控件
原文:示例:WPF中Slider控件封装的缓冲播放进度条控件 一.目的:模仿播放器播放进度条,支持缓冲任务功能 二.进度: 实现类似播放器中带缓存的播放样式(播放区域.缓冲区域.全部区域等样式) 实现 ...
- WPF中Ribbon控件的使用
这篇博客将分享如何在WPF程序中使用Ribbon控件.Ribbon可以很大的提高软件的便捷性. 上面截图使Outlook 2010的界面,在Home标签页中,将所属的Menu都平铺的布局,非常容易的可 ...
- WPF中查找控件的扩展类
在wpf中查找控件要用到VisualTreeHelper类,但这个类并没有按照名字查找控件的方法,于是搜索网络,整理出下面这个类,感觉用起来很是方便. 贴出来,供大家参考. /// <summa ...
- WPF中Popup控件在Win7以及Win10等中的对齐点方式不一样的解决方案 - 简书
原文:WPF中Popup控件在Win7以及Win10等中的对齐点方式不一样的解决方案 - 简书 最近项目中使用弹出控件Popup,发现弹出框的对齐方式在不同的系统中存在不同(Popup在win10上是 ...
随机推荐
- 集合框架-HashSet存储自定义对象
1 package cn.itcast.p4.hashset.test; 2 3 import java.util.HashSet; 4 import java.util.Iterator; 5 6 ...
- 不难懂-----Mock基本使用
一.mock解决的问题 开发时,后端还没完成数据输出,前端只好写静态模拟数据.数据太长了,将数据写在js文件里,完成后挨个改url.某些逻辑复杂的代码,加入或去除模拟数据时得小心翼翼.想要尽可能还原真 ...
- APC 篇——备用 APC 队列
写在前面 此系列是本人一个字一个字码出来的,包括示例和实验截图.由于系统内核的复杂性,故可能有错误或者不全面的地方,如有错误,欢迎批评指正,本教程将会长期更新. 如有好的建议,欢迎反馈.码字不易, ...
- Python 序列类型小结
序列是python中最基本的数据结构. 序列中每一个元素都有其对应的索引,索引是从0开始,0,1,2......依次类推 python中的序列类型有:字符串str.列表list.元组tuple.Uni ...
- Dart 2.16 现已发布
文 / Michael Thomsen, Dart 产品经理 Dart 2.16 正式发布 Dart 2.16 正式版已于上周发布.尽管没有新的语言特性加入,但本次版本发布包含了数个问题修复 (包括对 ...
- IDE集成git
目录 简介 Git安装 IDE集成Git IDE集成Git代码的创建分享上传 代码的下载和普通上传 分子的创建以及合并 代码的回滚 查看历史版本 简介 Git 是一个开源的分布式版本控制软件,用以有效 ...
- js 计算中英文混合字符串长度
转载请注明来源:https://www.cnblogs.com/hookjc/ function isChinese(str) { var lst = /[u00-uFF]/; ...
- 学习JSP篇:jsp简单介绍
这几天开始学习JSP和Servlet,写些博客,记录自己的学习过程,算是自己从业开始的一个见证. 一.什么是JSP JSP的全称是Java Service Page,一种动态的网页开发技术,区别于静态 ...
- ABCD四个顺序执行方法,拓展性延申
今天在群里,有人问 有几个void返回值的方法,但是我想让这几个方法有执行顺序,要怎么处理,ABCD 四个方法,依次执行,但是这几个方法都是无返回值的 这个问题其实很简单,如果方法是同步方法,直接四个 ...
- 3U VPX i7 刀片计算机
产品概述 该产品是一款基于第三代Intel i7双核四线程的高性能3U VPX刀片式计算机.产品提供了多个高速PCIe总线接口,其中3个x4 PCIe 3.0接口,1个x4 PCIe 2.0接口.x4 ...