zoukankan      html  css  js  c++  java
  • WPF TreeView 支持多选

    WPF 控件多选问题

    用过的 WPF 的同学,肯定用过控件的选择功能,例如 ListBox 或者 DataGrid 等。其中有一种控件 ———— TreeView 的多选并没有我们想象中的那么开箱即用。
    之前就遇到一个需求,TreeView 要支持多个选中项,且能从数据端(ViewModel)改变树节点的选中状态,然而原生 TreeView 控件是不支持设置多个选中项的。

    为什么 TreeView 不支持多选呢?

    从 TreeView 这个类可以看出,它是继承于 ItemsControl 的,本质上它就是一个嵌套 ItemsControl 的控件。单个 ItemsControl 的选中非常容易处理,多层嵌套就不一样了,原生控件也没有提供直接可用的接口来实现多选项。

    失败的尝试

    刚开始做多选 TreeView 的时候,首先采用了增加 IsSelected 属性来绑定选中状态,数据结构如下:

    public class TreeNode
    {
        public bool Selected { get; set; }
    
        // other data of tree node...
    }
    

    本以为将 TreeViewItem 的 IsSelected 属性绑定到 Selected 属性,再使用 DataTrigger 让选中项样式高亮使即可轻松搞定,没想到写完后测试却发现不同层级的 TreeViewItem 无法同时处于选中状态。因为双向绑定的存在,控件的 IsSelected 属性实时同步到了 ViewModel 的状态数据中,导致多选失败。
    后来在 Selected 的 set 方法中尝试加入一些条件判断,试图区分用户的点击和控件自动的数据修改,均没有理想的解决所有场景下的操作要求。

    改变思路

    上面的方法中,我花了大量的精力去解决控件 IsSelected 属性与 ViewModel 数据的同步,双向绑定使得数据流的管理极为混乱和复杂,那为什么不把两者的关系解耦呢?

    • 取消 IsSelected 与 Selected 的绑定,只保留 Selected 数据到控件样式的单向绑定。
    • 从 View 的操作出发,将用户的点击事件发送到 ViewModel,ViewModel 可以查到 Ctrl/Shift 按键的状态,此时更新 Selected 将变得非常简单且易维护。通过统一的入口去修改 Selected 属性,而控件的选中状态只由 Selected 数据改变,不随着用户在 View 层的操作而改变。这样的实现方式将极大地怎加选中操作的灵活性。
    • 同时,全选、反选、批量选择等操作也能在 ViewModel 中完成,只要思考业务需求而不必考虑控件交互带来的复杂度。

    总结

    WPF 的双向绑定带给 UI 开发带来极大的便利,却也造成了复杂交互的维护性问题,适当使用单向绑定能有不错的效果。

    当时在解决 TreeView 多选问题的时候,我还没有接触 Web 前端。后来学习 React 的时候,发现我在处理 TreeView 数据流动方向的方式竟然与 React 渲染时的单向数据流有一定的相似之处。

  • 相关阅读:
    c#中使用log4net工具记录日志
    由命名空间函数而引发思考--js中的对象赋值问题
    浅析C#中的Attribute[转]
    剑指offer_输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果
    剑指offer_输入一颗二叉树和一个整数,打印出二叉树中结点值的和为输入整数的所有路径
    剑指offer_输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字
    HashSet TreeSet 中元素顺序问题(未解决)
    找出某个String中出现次数最多的字符,并输出次数(字符较长)
    MyBatis、JDBC、Hibernate区别
    String.equals用法注意
  • 原文地址:https://www.cnblogs.com/cdyang/p/WPF-TreeView-MultiSelect.html
Copyright © 2011-2022 走看看