写在前面:在(一)中,介绍了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控件数据绑定和后台动态添加数据(二)的更多相关文章

  1. WPF中TreeView控件数据绑定和后台动态添加数据(一)

    数据绑定: 更新内容:补充在MVVM模式上的TreeView控件数据绑定的代码. xaml代码: <TreeView Name="syntaxTree" ItemsSourc ...

  2. WPF中TreeView控件SelectedItemChanged方法的MVVM绑定

    问题描述:左侧treeview控件中点击不同类别的节点时,右侧的页面会显示不同的权限.比如对于My Publications,拥有Modify和Delete两种权限,对于My Subscription ...

  3. WPF中TreeView控件的使用案例

    WPF总体来说还是比较方便的,其中变化最大的主要是Listview和Treeview控件,而且TreeView似乎在WPF是一个备受指责的控件,很多人说他不好用.我这个demo主要是在wpf中使用Tr ...

  4. WPF中PasswordBox控件的Password属性的数据绑定

    原文:WPF中PasswordBox控件的Password属性的数据绑定 英文原文:http://www.wpftutorial.net/PasswordBox.html 中文原文:http://bl ...

  5. WPF中Image控件的Source属性

    原文:WPF中Image控件的Source属性 imgBook 是一个Image控件,在后台代码中我想给它指定Source的属性.我先如下方式进行: Uri uri = new Uri(strImag ...

  6. 示例:WPF中Slider控件封装的缓冲播放进度条控件

    原文:示例:WPF中Slider控件封装的缓冲播放进度条控件 一.目的:模仿播放器播放进度条,支持缓冲任务功能 二.进度: 实现类似播放器中带缓存的播放样式(播放区域.缓冲区域.全部区域等样式) 实现 ...

  7. WPF中Ribbon控件的使用

    这篇博客将分享如何在WPF程序中使用Ribbon控件.Ribbon可以很大的提高软件的便捷性. 上面截图使Outlook 2010的界面,在Home标签页中,将所属的Menu都平铺的布局,非常容易的可 ...

  8. WPF中查找控件的扩展类

    在wpf中查找控件要用到VisualTreeHelper类,但这个类并没有按照名字查找控件的方法,于是搜索网络,整理出下面这个类,感觉用起来很是方便. 贴出来,供大家参考. /// <summa ...

  9. WPF中Popup控件在Win7以及Win10等中的对齐点方式不一样的解决方案 - 简书

    原文:WPF中Popup控件在Win7以及Win10等中的对齐点方式不一样的解决方案 - 简书 最近项目中使用弹出控件Popup,发现弹出框的对齐方式在不同的系统中存在不同(Popup在win10上是 ...

随机推荐

  1. 集合框架-HashSet存储自定义对象

    1 package cn.itcast.p4.hashset.test; 2 3 import java.util.HashSet; 4 import java.util.Iterator; 5 6 ...

  2. 不难懂-----Mock基本使用

    一.mock解决的问题 开发时,后端还没完成数据输出,前端只好写静态模拟数据.数据太长了,将数据写在js文件里,完成后挨个改url.某些逻辑复杂的代码,加入或去除模拟数据时得小心翼翼.想要尽可能还原真 ...

  3. APC 篇——备用 APC 队列

    写在前面   此系列是本人一个字一个字码出来的,包括示例和实验截图.由于系统内核的复杂性,故可能有错误或者不全面的地方,如有错误,欢迎批评指正,本教程将会长期更新. 如有好的建议,欢迎反馈.码字不易, ...

  4. Python 序列类型小结

    序列是python中最基本的数据结构. 序列中每一个元素都有其对应的索引,索引是从0开始,0,1,2......依次类推 python中的序列类型有:字符串str.列表list.元组tuple.Uni ...

  5. Dart 2.16 现已发布

    文 / Michael Thomsen, Dart 产品经理 Dart 2.16 正式发布 Dart 2.16 正式版已于上周发布.尽管没有新的语言特性加入,但本次版本发布包含了数个问题修复 (包括对 ...

  6. IDE集成git

    目录 简介 Git安装 IDE集成Git IDE集成Git代码的创建分享上传 代码的下载和普通上传 分子的创建以及合并 代码的回滚 查看历史版本 简介 Git 是一个开源的分布式版本控制软件,用以有效 ...

  7. js 计算中英文混合字符串长度

    转载请注明来源:https://www.cnblogs.com/hookjc/ function isChinese(str) {    var lst = /[u00-uFF]/;          ...

  8. 学习JSP篇:jsp简单介绍

    这几天开始学习JSP和Servlet,写些博客,记录自己的学习过程,算是自己从业开始的一个见证. 一.什么是JSP JSP的全称是Java Service Page,一种动态的网页开发技术,区别于静态 ...

  9. ABCD四个顺序执行方法,拓展性延申

    今天在群里,有人问 有几个void返回值的方法,但是我想让这几个方法有执行顺序,要怎么处理,ABCD 四个方法,依次执行,但是这几个方法都是无返回值的 这个问题其实很简单,如果方法是同步方法,直接四个 ...

  10. 3U VPX i7 刀片计算机

    产品概述 该产品是一款基于第三代Intel i7双核四线程的高性能3U VPX刀片式计算机.产品提供了多个高速PCIe总线接口,其中3个x4 PCIe 3.0接口,1个x4 PCIe 2.0接口.x4 ...