• DXP TreeList 目录树


    DXP TreeList 目录树

    1.需求背景

    需要一个支持勾选拖动节点保存各节点顺序的目录树。

    image

    2.创建目录树

    treeList控件中添加两个colunm 用来显示绑定数据显示值。

    image

    接下来对treeList的属性进行设置

    // 设置列不显示
    treeList.OptionsView.ShowColumns = false;
    // 设置序号列不显示
    treeList.OptionsView.ShowIndicator = false;
    // 设置垂直线不显示
    treeList.OptionsView.ShowVertLines = false;
    // 设置水平线不显示
    treeList.OptionsView.ShowHorzLines = false;
    // 设置焦点框为行焦点
    treeList.OptionsView.FocusRectStyle = DevExpress.XtraTreeList.DrawFocusRectStyle.RowFocus;
    // 隐藏第一列(数据列)
    treeListColumn1.Visible = false;
    // 设置不可编辑
    treeList.OptionsBehavior.Editable = false;
    // 设置显示复选框
    treeList.OptionsView.ShowCheckBoxes = true;
    // 设置勾选父节点,子节点自动全选
    treeList.OptionsBehavior.AllowRecursiveNodeChecking = true;

    添加节点

    private TreeListNode AppendNode(PrjTableNode node, int pid)
    {
    TreeListNode treeListNode = null;
    Actionint> ac = (arg1, arg2) =>
    {
    treeListNode = treeList.AppendNode(new object[] { node, node.Alias }, pid, 0, 0, 0);
    };
    var tt = treeList.Invoke(ac, new object[] { node, pid });
    SetNodeCheckState(treeListNode);
    return treeListNode;
    }

    主要用到treeList.AppendNode()方法,方法定义如下

    AppendNode(object nodeData, int parentNodeId, int imageIndex, int selectImageIndex, int stateImageIndex)
    • nodeData : object 类型的参数,这里传入object[]数组对象,数组对应treeList的列,这里第一列是数据,第二列用来显示,因此需要将第一列隐藏。
    • parentNodeId :父节点ID
    • imageIndex : 节点图标索引,这里没有图标就给任意一个数字
    • selectImageIndex : 节点被选择后显示的图标索引
    • stateImageIndex : 状态图标索引

    此时目录树就创建好了。

    2.1 设置目录树选中节点的背景色

    添加CustomDrawNodeCell事件

    // 设置行背景色
    treeList.CustomDrawNodeCell -= TreeList_CustomDrawNodeCell;
    treeList.CustomDrawNodeCell += TreeList_CustomDrawNodeCell;

    设置颜色

    private void TreeList_CustomDrawNodeCell(object sender, DevExpress.XtraTreeList.CustomDrawNodeCellEventArgs e)
    {
    if (e.Node.Selected)
    {
    e.Appearance.BackColor = Color.FromArgb(192, 192, 255);
    }
    }

    2.2 控制目录树节点的勾选框是否显示

    添加CustomDrawNodeCheckBox事件

    // 控制复选框显隐
    treeList.CustomDrawNodeCheckBox -= TreeList_CustomDrawNodeCheckBox;
    treeList.CustomDrawNodeCheckBox += TreeList_CustomDrawNodeCheckBox;
    private void TreeList_CustomDrawNodeCheckBox(object sender, DevExpress.XtraTreeList.CustomDrawNodeCheckBoxEventArgs e)
    {
    // 满足逻辑条件的 ,将 e.Handled = true 即可
    if ((e.Node.GetValue(treeListColumn1) as PrjTableNode)?.Type == ConstClass1.PRJ_TYPE_ID)
    {
    //e.Handled = true;
    }
    }

    2.3 节点拖拽

    这里的需求是只允许同级节点内部拖动,也不允许拖动到节点子集。

    设置属性OptionsDragAndDrop.DragNodesMode = DragNodesMode.Single

    添加DragOver,DragDropAfterDragNode事件

    // 设置节点拖拽
    treeList.OptionsDragAndDrop.DragNodesMode = DragNodesMode.Single;
    // 处理拖动时的逻辑
    treeList.DragOver -= TreeList_DragOver;
    treeList.DragOver += TreeList_DragOver;
    // 处理拖动结束时的逻辑
    treeList.DragDrop -= TreeList_DragDrop;
    treeList.DragDrop += TreeList_DragDrop;
    // 处理拖动后的逻辑
    treeList.AfterDragNode -= TreeList_AfterDragNode;
    treeList.AfterDragNode += TreeList_AfterDragNode;

    DragOver 用来处理拖动时的逻辑

    当有节点需要禁止拖动时,满足逻辑时,设置 e.Effect = DragDropEffects.None;即可

    private void TreeList_DragOver(object sender, DragEventArgs e)
    {
    var currNode = treeList.FocusedNode;
    var curNodeData = currNode.GetValue(treeListColumn1) as PrjTableNode;
    if (curNodeData == null)
    {
    return;
    }
    if (!curNodeData.CanDrag)
    {
    e.Effect = DragDropEffects.None;
    }
    }

    DragDrop 用来处理拖动结束时的逻辑

    private void TreeList_DragDrop(object sender, DragEventArgs e)
    {
    // 当前节点的父节点变化,则不允许拖动
    var dragNode = e.Data.GetData(typeof(TreeListNode)) as TreeListNode;
    var sourceParent = dragNode.ParentNode.GetValue(treeListColumn1) as PrjTableNode;
    var targetNode = treeList.CalcHitInfo(treeList.PointToClient(MousePosition)).Node;
    if (targetNode == null)
    {
    return;
    }
    PrjTableNode targetNodeParent = null;
    if (targetNode.ParentNode != null)
    {
    targetNodeParent = targetNode.ParentNode.GetValue(treeListColumn1) as PrjTableNode;
    }
    // 发生跨级移动
    if (sourceParent.Id != targetNodeParent.Id)
    {
    e.Effect = DragDropEffects.None;
    return;
    }
    // 移到子集
    if (AjustDirection(sender, e) == DragInsertPosition.AsChild)
    {
    e.Effect = DragDropEffects.None;
    return;
    }
    }
    ///
    /// 移动过程中的方向
    ///
    ///
    ///
    ///
    private DragInsertPosition AjustDirection(object sender, DragEventArgs e)
    {
    var tl = sender as TreeList;
    //var dragNode = e.Data.GetData(typeof(TreeListNode)) as TreeListNode;
    //var hit = tl.CalcHitInfo(tl.PointToClient(new Point(e.X, e.Y)));
    var pi = typeof(TreeList).GetProperty("Handler", BindingFlags.Instance | BindingFlags.NonPublic);
    var handler = (TreeListHandler)pi.GetValue(tl, null);
    return handler.StateData.DragInfo.DragInsertPosition;
    }

    AfterDragNode 用来处理拖动结束后的逻辑

    private void TreeList_AfterDragNode(object sender, AfterDragNodeEventArgs e)
    {
    // TODO:...
    }

    3.总结

    treeList是一个很强大的控件,用来处理树状结构。本次需求中,处理节点拖拽话费了较长时间,也网上找了很多博文,但是都没有直接解决我的问题,因此在这里做个笔记。

    后记:纸上得来终觉浅,绝知此事要躬行

  • 相关阅读:
    通过图卷积网络从单词语义学习到句子句法,用于基于方面的情感分析
    K8S访问控制------认证(authentication )、授权(authorization )体系
    【计算机图形学入门】笔记1:图形学概述
    mysql索引最左前缀法则、使用场景
    简单实现vue2响应式
    腾讯云多Kubernetes集群高可用运维实践
    【Git】Git 学习笔记_操作远程仓库
    APP逆向案例之(一)过 app 更新提示
    LiveNVR流媒体服务Onvif/RTSP平台支持云端录像服务器上面集中录像存储在部署LiveNVR的服务器上面
    JavaSe-JAVA的多态
  • 原文地址:https://www.cnblogs.com/ycit/p/17604994.html