zoukankan      html  css  js  c++  java
  • WPF中TreeView控件数据绑定和后台动态添加数据(一)

    数据绑定:

    更新内容:补充在MVVM模式上的TreeView控件数据绑定的代码。

    xaml代码:

    <TreeView Name="syntaxTree" ItemsSource="{Binding TreeNodes}">
                                    <TreeView.ItemTemplate>
                                        <HierarchicalDataTemplate DataType="{x:Type local:TreeNode}" ItemsSource="{Binding Path=ChildNodes}">
                                            <TextBlock Text="{Binding NodeName}"/>
                                        </HierarchicalDataTemplate>
                                    </TreeView.ItemTemplate>
    </TreeView>

    TreeView中的ItemsSource绑定的是一个名为TreeNodes的TreeNode的列表,即List<TreeNode>TreeNodes。HierarchicalDataTemplate中的ItemsSource绑定的TreeNodes中的每个节点的ChildNodes属性。

    ViewModel.cs中的代码(有删减):

    public class ViewModel : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        private List<TreeNode> treenodes = new List<TreeNode>();
        public List<TreeNode> TreeNodes
        {
           get { return treenodes; }
           set
           {
              treenodes = value;
              if (PropertyChanged != null)
                 PropertyChanged(this, new PropertyChangedEventArgs("TreeNodes"));
           }
        }
    
        public ViewModel()
        {
        // Nodes是我已经获得的一组节点
           TreeNodes = 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;
        }
    }

    使用MVVM模式,那么xaml.cs文件就会变得非常简单了,基本只有一句代码了:

    this.DataContext = new ViewModel();

    该模式的好处就是使得UI设计和后端代码分开,只通过数据绑定进行连接。尝试用了几次,真的还蛮方便。


    TreeView数据绑定需要使用层次结构数据模板(HierarchicalDataTemplate)来显示分层数据。XAML代码如下:

    <TreeView Name="chapterTree" Grid.Column="0">
                <TreeView.ItemTemplate>
                    <HierarchicalDataTemplate ItemsSource="{Binding Path=ChildNodes}">
                        <StackPanel>
                            <Label Content="{Binding Path=NodeName}"/>
                        </StackPanel>
                    </HierarchicalDataTemplate>
                </TreeView.ItemTemplate>
            </TreeView>

    其中,ItemsSource绑定的对象ChildNodes应该是一个集合类型:List<TreeNode>,Label中绑定的是TreeNode的NodeName属性,TreeNode类定义如下所示:

    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 TreeNode()
            {
                ChildNodes = new List<TreeNode>();
            }
        }

    因为是树形结构,因此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 List<TreeNode> nodes;
            private void InputData()
            {
                nodes = new List<TreeNode>()
                {
                    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<TreeNode> getNodes(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 = getNodes(node.NodeID, otherNodes);
                return mainNodes;
            }
        }

    需要注意的就是NodeID是不断增加的,每个节点都有自己的ID,而其ParentID就看它是属于哪个父节点的了。getNodes()是一个递归方法,就是不断读取某个节点的子节点。运行结果如图所示:

     

    后台动态添加TreeView:

    一开始,没用数据绑定,就直接在xaml.cs中使用treeview,虽然后来用了数据绑定之后发现还是绑定更方便,但是这种在后台构建treeview的方法没准哪天也能用到,就记录一下吧。

    XAML文件,使用一个TreeView控件

    <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="60*"/>
                <ColumnDefinition Width="100*"/>
            </Grid.ColumnDefinitions>
            <TreeView Name="chapterTree" Grid.Column="0"/>
        </Grid>

    XAML.CS文件,同样使用递归方法,就是不断的新建treeviewitem控件。

    public partial class DynamicTreeView : Window
        {
            public DynamicTreeView()
            {
                InitializeComponent();
                InputData();
                ShowTreeView();
            }
    
            private List<TreeNode> nodes;
            private void InputData()
            {
                nodes = new List<TreeNode>()
                {
                    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<TreeNode> 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架构的应用还是挺好的。

     第二部分将总结给节点添加事件的方法。

  • 相关阅读:
    linux的msl
    kubernetes资源调度之LimitRange
    使用setfacl实现子目录继承父目录权限 转载
    k8s glusterfs,GlusterFS Volume 添加ACL支持
    windows10环境下编译python3版pjsua库
    Java单链表反转
    Linux常用命令
    slice()和splice()区别
    js文件三斜杠注释///reference path用途,js文件引用另一个js文件的写法
    【UML】如何记忆UML类图的画法
  • 原文地址:https://www.cnblogs.com/larissa-0464/p/10227483.html
Copyright © 2011-2022 走看看