• 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 渲染时的单向数据流有一定的相似之处。

  • 相关阅读:
    Friends ZOJ
    2^x mod n = 1 HDU
    Paint the Grid Reloaded ZOJ
    Treap 模板
    bzoj进度条
    。。。
    bzoj
    。。。
    bzoj
    题解continue
  • 原文地址:https://www.cnblogs.com/cdyang/p/WPF-TreeView-MultiSelect.html
Copyright © 2020-2023  润新知