WPF控件之TreeView扩展应用(二)

发布于:2022-07-24 ⋅ 阅读:(388) ⋅ 点赞:(0)

        这周,咱们来玩目录树多选的应用,走起。

        多选,我目前掌握两种种方法表示,比如改变节点颜色,在treeviewitem中添加复选框,当然,还是以通俗易懂的来讲解,本次我用的是第二种方法

        开始还是老样子,如图(不做概述了)

来看下这次的目录树对象,稍微复杂点(有点长了就不截图了) ,看代码

    public class TreeModel : BindableObject
    {
        private string name;
        /// <summary>
        /// 节点名字
        /// </summary>
        public string Name
        {
            get => name;
            set
            {
                name = value;
                OnPropertyChanged();
            }
        }

        private bool? isCheck;
        /// <summary>
        /// 是否被选中(注:true是钩,false是空的,null是方块)
        /// </summary>
        public bool? IsCheck
        {
            get => isCheck;
            set
            {
                isCheck = value;
                OnPropertyChanged();
            }
        }

        /// <summary>
        /// 父节点
        /// </summary>
        public TreeModel Parent { get; set; }

        /// <summary>
        /// 子节点
        /// </summary>
        public ObservableCollection<TreeModel> Children { get; set; } = new ObservableCollection<TreeModel>();
    }

接下来看view界面,也是直接上代码,没什么陌生的知识点,布局是一个treeview和一个button(注意需要这个Microsoft.Xaml.Behaviors.WPF包哈)

    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition />
            <RowDefinition Height="auto" />
        </Grid.RowDefinitions>
        <TreeView ItemsSource="{Binding Trees}">
            <TreeView.ItemTemplate>
                <HierarchicalDataTemplate ItemsSource="{Binding Children}">
                    <Grid>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition />
                            <ColumnDefinition />
                        </Grid.ColumnDefinitions>
                        <CheckBox IsChecked="{Binding IsCheck, Mode=OneWay}">
                            <i:Interaction.Triggers>
                                <i:EventTrigger EventName="Click">
                                    <i:InvokeCommandAction Command="{Binding DataContext.ClickCommand, RelativeSource={RelativeSource AncestorType=Window, Mode=FindAncestor}}" CommandParameter="{Binding}" />
                                </i:EventTrigger>
                            </i:Interaction.Triggers>
                            <TextBlock Grid.Column="1" Text="{Binding Name}" />
                        </CheckBox>
                    </Grid>
                </HierarchicalDataTemplate>
            </TreeView.ItemTemplate>
        </TreeView>

        <Button
            Grid.Row="1"
            Height="60"
            Command="{Binding ShowCommand}"
            Content="选择后请点我" />
    </Grid>

最后来看业务逻辑部分,看代码,没什么难的逻辑

    public class TreeViewModel : BindableObject
    {
        /// <summary>
        /// 目录树
        /// </summary>
        public ObservableCollection<TreeModel> Trees { get; set; }

        /// <summary>
        /// 存储勾选的节点
        /// </summary>
        public List<TreeModel> SelectItem { get; set; } = new List<TreeModel>();

        /// <summary>
        /// 点击节点命令
        /// </summary>
        public DelegateCommand<TreeModel> ClickCommand { get; private set; }

        /// <summary>
        /// 展示命令
        /// </summary>
        public DelegateCommand ShowCommand { get; private set; }

        public TreeViewModel()
        {
            Trees = new ObservableCollection<TreeModel>();
            ClickCommand = new DelegateCommand<TreeModel>(Click);
            ShowCommand = new DelegateCommand(Show);
            CreateTree();
        }

        /// <summary>
        /// 初始化生成目录树
        /// </summary>
        public void CreateTree()
        {
            for (int i = 0; i < 3; i++)
            {
                TreeModel treeModel = new TreeModel()
                {
                    Name = $"我是第{i}",
                    IsCheck = false,
                };
                for (int j = 0; j < 5; j++)
                {
                    treeModel.Children.Add(new TreeModel()
                    {
                        Name = $"我是第{i}的第{j}个孩子",
                        IsCheck = false,
                        Parent = treeModel,
                    });
                }
                Trees.Add(treeModel);
            }
        }

        public void Click(TreeModel param)
        {
            try
            {
                var result = Trees.FirstOrDefault(x => x.Name == param.Name);

                if (result != null)
                {
                    SelectAll(result);
                }
                else
                {
                    Select(param);
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        /// <summary>
        /// 全选
        /// </summary>
        /// <param name="param"></param>
        private void SelectAll(TreeModel param)
        {
            try
            {
                int count = 0;
                List<TreeModel> lists = new List<TreeModel>();

                foreach (var item in param.Children) //这里是获取之前点击了几个孩子
                {
                    if (item.IsCheck == true)
                    {
                        count++;
                    }
                    else
                    {
                        lists.Add(item);
                    }
                }

                if (count == param.Children.Count) //相等表示之前是全选状态,现在为取消全选,否则反之
                {
                    param.IsCheck = false;
                    foreach (var item in param.Children)
                    {
                        var result = SelectItem.FirstOrDefault(x => x.Name == item.Name);
                        if (result != null)
                        {
                            SelectItem.Remove(result);
                            item.IsCheck = false;
                        }
                    }
                }
                else
                {
                    param.IsCheck = null;
                    foreach (var item in lists)
                    {
                        var result = SelectItem.FirstOrDefault(x => x.Name == item.Name);
                        if (result == null)
                        {
                            SelectItem.Add(item);
                            item.IsCheck = true;
                        }
                    }
                }

            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        /// <summary>
        /// 单选
        /// </summary>
        /// <param name="param"></param>
        private void Select(TreeModel param)
        {
            try
            {
                var result = SelectItem.FirstOrDefault(x => x.Name == param.Name);

                var value = param.Parent;

                if (result != null)//表示之前点击过,现在是取消选择,否则反之
                {
                    var list = SelectItem.Where(x => x.Parent == value).ToList();
                    if (list.Count == value.Children.Count)//数量相等表示取消全选
                    {
                        value.IsCheck = false;
                    }

                    SelectItem.Remove(result);
                    param.IsCheck = false;
                }
                else
                {
                    SelectItem.Add(param);
                    var list = SelectItem.Where(x => x.Parent == value).ToList();
                    if (list.Count == value.Children.Count)//数量相等表示全选
                    {
                        value.IsCheck = null;
                    }

                    param.IsCheck = true;
                }

            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        private void Show()
        {
            MessageBox.Show($"已选择{SelectItem.Count}节点");
        }
    }

运行看结果图,如图

 补充:

(1)这次案例需求简单,所有目录树就简单,但在实际开发中,得注意,最好给一个属性来区分不同的节点

(2)如果数据多了,超出设置界面的大小,这次我没有加滚动条控件(ScrollViewer),读者们可以自己加上,随便我给出滑轮实现滚动条滚动的代码

        public void PreviewMouseWheel(object sender, MouseWheelEventArgs e)
        {
            try
            {
                ScrollViewer scrollviewer = sender as ScrollViewer;
                if (e.Delta > 0)
                {
                    scrollviewer.LineUp();
                }
                else
                {
                    scrollviewer.LineDown();
                }
                e.Handled = true;
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

(3)代码在这:https://github.com/TQtong/TreeViewExtensionApplication_1.git

结束:

        希望能扩展你们的思想,那么咱们下周见,希望各位指出不足之处,


网站公告

今日签到

点亮在社区的每一天
去签到