如何分批分层的加载树节点

案例背景:
界面上使用了树控件,需显示大量的节点;
如果一次性加载到客户端,显示渲染会非常慢;
因此,需要分层、分批下载,以缓解每次加载的性能压力,提升用户体验。

案例说明:
新增一个动态表单,挂上本插件,并在界面有一个树控件 F_JD_TreeView;
界面初始化时,仅加载第一层节点;
用户点击节点时,才加载其包含的子节点,而且每次最多加载10个;
单层超过10个节点,通过"点击加载更多..."节点,分批下载

案例效果:
图一 :在动态表单上,添加一个树控件,并挂上插件(示例代码在下面)
20160107 00分批分层加载树节点1.png 

图二 :初始仅加载10个一级节点
20160107 00分批分层加载树节点2.png 

图三 :"点击加载更多...",加载了下一批10个一级节点
20160107 00分批分层加载树节点3.png 

图四 :点击父节点,加载了其第一批10个子节点
20160107 00分批分层加载树节点4.png 

示例代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using Kingdee.BOS;
using Kingdee.BOS.Util;
using Kingdee.BOS.Core;
using Kingdee.BOS.Core.DynamicForm;
using Kingdee.BOS.Core.DynamicForm.PlugIn;
using Kingdee.BOS.Core.DynamicForm.PlugIn.Args;
using Kingdee.BOS.Core.DynamicForm.PlugIn.ControlModel;
using Kingdee.BOS.Core.Metadata;

namespace JDSample.FormPlugIn.DynamicForm
{
    /// <summary>
    /// 分批分层加载树节点
    /// </summary>
    /// <remarks>
    /// 案例背景:
    /// 界面上使用树控件,需显示大量的节点;
    /// 如果一次性加载到客户端,显示渲染会非常慢;
    /// 因此,需要分层、分批下载
    /// 
    /// 案例说明:
    /// 新增一个动态表单,挂上本插件,并在界面有一个树控件 F_JD_TreeView;
    /// 界面初始化时,仅加载第一层节点;
    /// 用户点击节点时,才加载其包含的子节点,而且每次最多加载10个;
    /// 单层超过10个节点,通过"点击加载更多..."节点,分批下载
    /// </remarks>
    [Description("分批分层加载树节点")]
    public class S160107TreeEdit : AbstractDynamicFormPlugIn
    {
        /// <summary>
        /// 本地变量,存储需加载到前端的所有节点信息,以及其是否已经加载标志
        /// </summary>
        private Dictionary<string, NodeInfo> _dctNodes = new Dictionary<string, NodeInfo>();

        /// <summary>
        /// 本地变量,存储已经被加载过的父节点Id,避免重复搜索其子节点,浪费时间
        /// </summary>
        private HashSet<string> _loadedNodeIds = new HashSet<string>();

        /// <summary>
        /// 界面初始化结束,触发此事件,通知插件开始加载树节点:在此事件,加载第一层节点
        /// </summary>
        /// <param name="e"></param>
        public override List<TreeNode> GetTreeViewData(TreeNodeArgs e)
        {
            if (e.Key.EqualsIgnoreCase("F_JD_TreeView") == false)
            {
                // 需加载是其他树控件的节点,略过
                return new List<TreeNode>();
            }

            // 加载全部节点信息到内存
            this.LoadNodes();

            // 记录已经加载过根节点
            this._loadedNodeIds.Add("0");

            // 展开树控件节点
            TreeView tv = this.View.GetControl<TreeView>("F_JD_TreeView");
            tv.SetExpanded(true);

            // 构造根目录下的第一层节点并返回
            List<TreeNode> nodes = this.BuildTreeNodes("0");
            return nodes;
        }

        /// <summary>
        /// 用户点击节点时触发此事件:加载更多子节点
        /// </summary>
        /// <param name="e"></param>
        public override void TreeNodeClick(TreeNodeArgs e)
        {
            if (e.Key.EqualsIgnoreCase("F_JD_TreeView") == false)
            {
                // 点击的是其他树控件,略过
                return;
            }

            // 判断是否已经加载过此节点的子节点,如果加载过,则不再加载
            if (this._loadedNodeIds.Contains(e.NodeId))
            {
                return;
            }

            this._loadedNodeIds.Add(e.NodeId);
            TreeView tv = this.View.GetControl<TreeView>("F_JD_TreeView");
            string parentId = e.NodeId;
            if (parentId.StartsWith("more"))
            {// 当前点击的节点,是"点击加载更多..."
                string[] keys = parentId.Split('|');
                parentId = keys[1];   // 第2部分为父节点部分
                // "点击加载更多..."节点已经被点击过,不再需要了,移除之
                tv.RemoveNode(e.NodeId);
            }

            // 开始加载更多的子节点
            List<TreeNode> childNodes = this.BuildTreeNodes(parentId);
            if (childNodes.Count > 0)
            {
                tv.AddNodes(parentId, childNodes);
            }
        }

        /// <summary>
        /// 构建树控件所需要的节点对象
        /// </summary>
        /// <param name="parentId">父节点Id,为0表示第一层节点</param>
        /// <returns></returns>
        private List<TreeNode> BuildTreeNodes(string parentId)
        {
            List<TreeNode> nodes = new List<TreeNode>();
            // 遍历全部节点,找指定节点中,未加载的子节点的子节点
            int count = 0;
            int index = 0;
            foreach (var item in _dctNodes)
            {
                NodeInfo nodeInfo = item.Value;
                if (nodeInfo.Loaded == false
                    && nodeInfo.ParentId == parentId)
                {
                    nodeInfo.Loaded = true;
                    count++;
                    TreeNode node = new TreeNode()
                    {
                        id = nodeInfo.Id,
                        text = nodeInfo.Caption,
                        parentid = nodeInfo.ParentId,
                    };
                    nodes.Add(node);
                }

                if (count >= 10)
                {// 本次加载超过了10个
                    // 生成一个特殊的节点(加载更多...),并停止本批加载更多子节点
                    TreeNode node = new TreeNode()
                    {
                        // 需要基于如下需求,生成一个特殊的节点Id
                        // 1. 需要与其他普通节点进行区分:以more为前缀
                        // 2. 需要能够提取出父节点Id:包含父节点Id
                        // 3. 每次产生的特殊节点Id不能重复:需包含当前节点索引
                        id = string.Format("more|{0}|{1}", parentId, index),
                        text = "点击加载更多...",
                        parentid = parentId,
                    };
                    nodes.Add(node);
                    break;
                }

                index++;
            }
            return nodes;
        }
        
        /// <summary>
        /// 到数据库加载全部节点信息:本示例直接手工构建一批有层次的节点信息
        /// </summary>
        private void LoadNodes()
        {
            // 节点名称,包含其子节点的数量,以提示用户,可以展开查看子节点
            // 第一层节点
            _dctNodes.Add("1", new NodeInfo() { Id = "1", ParentId = "0", Caption = "江西(100)" });
            _dctNodes.Add("2", new NodeInfo() { Id = "2", ParentId = "0", Caption = "广东(3)" });
            // 循环添加100个第一层节点
            for (int i = 3; i <= 100; i++)
            {
                _dctNodes.Add(i.ToString(), new NodeInfo() 
                { Id = i.ToString(), ParentId = "0", Caption = string.Format("省份{0}(0)", i) });
            }
            
            // 第二层节点:
            _dctNodes.Add("1.1", new NodeInfo() { Id = "1.1", ParentId = "1", Caption = "南昌(0)" });
            _dctNodes.Add("1.2", new NodeInfo() { Id = "1.2", ParentId = "1", Caption = "九江(0)" });
            _dctNodes.Add("1.3", new NodeInfo() { Id = "1.3", ParentId = "1", Caption = "赣州(0)" });
            // 循环添加100个第二层节点
            for (int i = 4; i <= 100; i++)
            {
                _dctNodes.Add(string.Format("1.{0}", i), 
                    new NodeInfo() 
                    { 
                        Id = string.Format("1.{0}", i), 
                        ParentId = "1", 
                        Caption = string.Format("城市{0}(0)", i) 
                    });
            }
            _dctNodes.Add("0201", new NodeInfo() { Id = "0201", ParentId = "02", Caption = "广州(0)" });
            _dctNodes.Add("0202", new NodeInfo() { Id = "0202", ParentId = "02", Caption = "深圳(2)" });
            _dctNodes.Add("0203", new NodeInfo() { Id = "0203", ParentId = "02", Caption = "惠州(0)" });
            // 第三层节点:
            _dctNodes.Add("020201", new NodeInfo() { Id = "020201", ParentId = "0202", Caption = "南山区" });
            _dctNodes.Add("020202", new NodeInfo() { Id = "020202", ParentId = "0202", Caption = "宝安区" });
        }
    }
    /// <summary>
    /// 节点信息对象
    /// </summary>
    class NodeInfo
    {
        /// <summary>
        /// 本节点Id
        /// </summary>
        public string Id { get; set; }
        /// <summary>
        /// 父节点Id
        /// </summary>
        public string ParentId { get; set; }
        /// <summary>
        /// 本节点标题
        /// </summary>
        public string Caption { get; set; }
        /// <summary>
        /// 是否已经加载标志:默认为false,未加载到前端
        /// </summary>
        public bool Loaded { get; set; }
    }
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值