zoukankan      html  css  js  c++  java
  • 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

    全部代码:

    https://github.com/Larissa1990/WPF_TreeView

  • 相关阅读:
    在ChemDraw中输入千分号的方法
    将几何画板x轴坐标值换成弧度制的方法
    几何画板怎么会出现符号乱码
    几何画板绘制正方形网格的技巧
    怎么用ChemDraw 15.1 Pro绘制彩色结构
    深入理解:单一入口、MVC、ORM、CURD、ActiveRecord概念
    IIS下PHP的ISAPI和FastCGI比较
    非常好用的两个PHP函数 serialize()和unserialize()
    为什么要让我们的“领域模型”裸奔?
    依赖注入
  • 原文地址:https://www.cnblogs.com/larissa-0464/p/12441607.html
Copyright © 2011-2022 走看看