数据绑定:
更新内容:补充在MVVM模式上的TreeView控件数据绑定的代码。
xaml代码:
TreeView中的ItemsSource绑定的是一个名为TreeNodes的TreeNode的列表,即List
ViewModel.cs中的代码(有删减):
public class ViewModel : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; private Listtreenodes = new List (); public List TreeNodes { get { return treenodes; } set { treenodes = value; if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs("TreeNodes")); } } public ViewModel() { // Nodes是我已经获得的一组节点 TreeNodes = getChildNodes(0,Nodes); } private List getChildNodes(int parentID, List nodes) { List mainNodes = nodes.Where(x => x.ParentID == parentID).ToList(); List otherNodes = nodes.Where(x => x.ParentID != parentID).ToList(); foreach (TreeNode node in mainNodes) node.ChildNodes = getChildNodes(node.NodeID, otherNodes); return mainNodes; }
}
使用MVVM模式,那么xaml.cs文件就会变得非常简单了,基本只有一句代码了:
this.DataContext = new ViewModel();
该模式的好处就是使得UI设计和后端代码分开,只通过数据绑定进行连接。尝试用了几次,真的还蛮方便。
TreeView数据绑定需要使用层次结构数据模板(HierarchicalDataTemplate)来显示分层数据。XAML代码如下:
其中,ItemsSource绑定的对象ChildNodes应该是一个集合类型:List
public class TreeNode { public int NodeID { get; set; } public int ParentID { get; set; } public string NodeName { get; set; } public ListChildNodes { get; set; } public TreeNode() { ChildNodes = new List (); } }
因为是树形结构,因此TreeNode需要有NodeID属性和ParentID属性,即某个树节点node本身的ID和它所属的父节点的ID。以目录为例,则xaml.cs中的代码如下。首先是写入了数据,在我实际项目中,这些数据是从DB中查询的,这里为了简化,直接Input数据了。
public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); InputData(); chapterTree.ItemsSource = getNodes(0, nodes); } private Listnodes; private void InputData() { nodes = new List () { new TreeNode(){ParentID=0, NodeID=1, NodeName = "Chapter1" }, new TreeNode(){ParentID=0, NodeID=2, NodeName="Chapter2"}, new TreeNode(){ParentID=0,NodeID=3, NodeName="Chapter3"}, new TreeNode(){ParentID=1, NodeID=4, NodeName="Section1.1"}, new TreeNode(){ParentID=1, NodeID=5, NodeName="Section1.2"}, new TreeNode(){ParentID=2, NodeID=6, NodeName="Section2.1"}, new TreeNode(){ParentID=3, NodeID=7, NodeName="Section3.1"}, new TreeNode(){ParentID=6, NodeID=8, NodeName="SubSection2.1.1"}, new TreeNode(){ParentID=6, NodeID=9, NodeName="SubSection2.1.2"}, new TreeNode(){ParentID=2, NodeID=10,NodeName="Section2.2"}, new TreeNode(){ParentID=3, NodeID=11, NodeName="Section3.2"} }; } private List getNodes(int parentID, List nodes) { List mainNodes = nodes.Where(x => x.ParentID == parentID).ToList(); List otherNodes = nodes.Where(x => x.ParentID != parentID).ToList(); foreach (TreeNode node in mainNodes) node.ChildNodes = getNodes(node.NodeID, otherNodes); return mainNodes; } }
需要注意的就是NodeID是不断增加的,每个节点都有自己的ID,而其ParentID就看它是属于哪个父节点的了。getNodes()是一个递归方法,就是不断读取某个节点的子节点。运行结果如图所示:
后台动态添加TreeView:
一开始,没用数据绑定,就直接在xaml.cs中使用treeview,虽然后来用了数据绑定之后发现还是绑定更方便,但是这种在后台构建treeview的方法没准哪天也能用到,就记录一下吧。
XAML文件,使用一个TreeView控件
XAML.CS文件,同样使用递归方法,就是不断的新建treeviewitem控件。
public partial class DynamicTreeView : Window { public DynamicTreeView() { InitializeComponent(); InputData(); ShowTreeView(); } private Listnodes; private void InputData() { nodes = new List () { new TreeNode(){ParentID=0, NodeID=1, NodeName = "Chapter1" }, new TreeNode(){ParentID=0, NodeID=2, NodeName="Chapter2"}, new TreeNode(){ParentID=0,NodeID=3, NodeName="Chapter3"}, new TreeNode(){ParentID=1, NodeID=4, NodeName="Section1.1"}, new TreeNode(){ParentID=1, NodeID=5, NodeName="Section1.2"}, new TreeNode(){ParentID=2, NodeID=6, NodeName="Section2.1"}, new TreeNode(){ParentID=3, NodeID=7, NodeName="Section3.1"}, new TreeNode(){ParentID=6, NodeID=8, NodeName="SubSection2.1.1"}, new TreeNode(){ParentID=6, NodeID=9, NodeName="SubSection2.1.2"}, new TreeNode(){ParentID=2, NodeID=10,NodeName="Section2.2"}, new TreeNode(){ParentID=3, NodeID=11, NodeName="Section3.2"} }; } private void ShowTreeView() { TreeViewItem tv1 = new TreeViewItem(); chapterTree.Items.Add(tv1); GetNodes(0, tv1); } private void GetNodes(int parentID, TreeViewItem tv) { List mainNodes = nodes.Where(x => x.ParentID == parentID).ToList(); foreach(var item in mainNodes) { TreeViewItem tv1 = new TreeViewItem(); tv1.Header = item.NodeName; tv.Items.Add(tv1); GetNodes(item.NodeID, tv1); } } }
运行图:总归是没有databinding方便。刚开始学习WPF,一开始没想过要用数据绑定,总感觉只要能实现自己想要的东西就可以了,不用管实现过程,后来使用了之后发现,使用数据绑定构建MVVM架构的应用还是挺好的。
第二部分将总结给节点添加事件的方法。