惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Google DeepMind News
Google DeepMind News
Attack and Defense Labs
Attack and Defense Labs
GbyAI
GbyAI
月光博客
月光博客
Recent Announcements
Recent Announcements
云风的 BLOG
云风的 BLOG
F
Full Disclosure
宝玉的分享
宝玉的分享
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
爱范儿
爱范儿
博客园 - Franky
V
V2EX
Recorded Future
Recorded Future
WordPress大学
WordPress大学
小众软件
小众软件
Webroot Blog
Webroot Blog
雷峰网
雷峰网
Vercel News
Vercel News
N
News and Events Feed by Topic
PCI Perspectives
PCI Perspectives
Cyberwarzone
Cyberwarzone
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
W
WeLiveSecurity
S
Schneier on Security
博客园 - 三生石上(FineUI控件)
K
Kaspersky official blog
F
Fortinet All Blogs
Security Archives - TechRepublic
Security Archives - TechRepublic
Spread Privacy
Spread Privacy
博客园 - 叶小钗
罗磊的独立博客
D
Docker
Forbes - Security
Forbes - Security
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
The Register - Security
The Register - Security
A
About on SuperTechFans
B
Blog RSS Feed
I
InfoQ
T
Tailwind CSS Blog
G
Google Developers Blog
H
Help Net Security
V
Vulnerabilities – Threatpost
AWS News Blog
AWS News Blog
N
News and Events Feed by Topic
M
MIT News - Artificial intelligence
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
P
Proofpoint News Feed
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
MyScale Blog
MyScale Blog
Latest news
Latest news

博客园 - 大熊(BigBear)

ADO.net实现批量SQL操作. - 大熊(BigBear) - 博客园 Application_AcquireRequestState事件,导致Ajax客户端不能加载 CSLA.Net在Web项目中使用SQL2005的分页 Moss中Form验证中"找不到匹配项"问题的处理 对于知识库系统建设的思考 知识管理中知识地图详解〔转〕 知识管理中的一些概念 Aop面向方面编程之PostSharp框架 [摘]IIS上部署WCF的问题 Linq使用之分组 Silverlight表格绑定中的一点细节处理 页面加载性能的优化 IBatis.Net使用MemCached替换内置缓存策略 .Net下调用Java安全Web服务 Webpart深入(二) Webpart深入(一) ASP.NET MVC 中文文档3 ASP.NET MVC 中文文档2 ASP.net MVC 中文文档1
由一棵树绑定引发的遐想
大熊(BigBear) · 2009-11-25 · via 博客园 - 大熊(BigBear)

作为一个开发人员, 总的写写什么树绑定之类的东东.

为了活的轻松点, 我们不得不想办法偷些懒.来看看树绑定偷懒办法.

1. 首先,声明一个接口ITreeAble<T>。

    /// <summary>

    /// 一个可绑定为树的对象接口

    /// </summary>

    /// <typeparam name="T">泛型的对象类型,ID的数据类型</typeparam>

    public interface ITreeAble<T>

    {

        T ID { get; set; }

        T ParentID { get; set; }

        string Name { get; set; }

        int OrderID { get; set; }

}

这里用泛型,因为主键的类型可能多样,可以是GUID, INT,或者String等等。

2. 实体类,可以绑定为树的,都需要继承这个接口。这里的主键就指定为整型。

    public class ProjectTree : ITreeAble<int>

    {

        #region ITreeAble<int> Members

        public int ID{get; set; }

        public int ParentID{get;set;}

        public string Name{get;set;}

        public int OrderID{get;set;}

        #endregion

        public string LinkUrl { get; set; }

    }

3.  实现绑定的逻辑。

    /// <summary>
    /// 绑定FlyTree
    /// </summary>
    /// <typeparam name="T">主键数据类型</typeparam>
    public class FlyTreeBindHelper<T>
    {
        List<ITreeAble<T>> _dataList = null;
        T _topNodeID;
        FlyTreeView _treeControl = null;
        //获得子节点数据的方法委托
        public delegate List<ITreeAble<T>> GetChildNodes(string parentID);
        public GetChildNodes _GetChildDelegate = null;
        //获得是否保护子节点的方法委托,如果节点有子节点就可以展开,否则就不展开
        public delegate bool CheckHasChildren(string parentID);
        public CheckHasChildren _HasChildren = null;
        //生成节点的方法委托
        public delegate FlyTreeNode GetNewNode(ITreeAble<T> nodeData);
        public GetNewNode _GetNewNode = null;

        /// <summary>
        ///
        /// </summary>
        /// <param name="treeControl">树控件</param>
        /// <param name="getChildNodeDelegate">获取子节点列表</param>
        /// <param name="hasChildrenDelegate">是否有子节点</param>
        public FlyTreeBindHelper(FlyTreeView treeControl, GetNewNode getNewNode, GetChildNodes getChildNodeDelegate, CheckHasChildren hasChildrenDelegate)
        {
            _treeControl = treeControl;
            _GetNewNode = getNewNode;

            if (getChildNodeDelegate != null)
            {
                _GetChildDelegate = getChildNodeDelegate;
                _HasChildren = hasChildrenDelegate;
                //节点展开的事件
                _treeControl.PopulateNodes += new FlyTreeNodeEventHandler(_treeControl_PopulateNodes);
                _treeControl.PostBackOnExpand = true;
            }
        }

        public FlyTreeBindHelper(FlyTreeView treeControl, GetNewNode getNewNode)
            : this(treeControl, getNewNode, null, null)
        {
        }

        /// <summary>
        /// 绑定树
        /// </summary>
        /// <param name="treeControl"></param>
        /// <param name="dataList"></param>
        public void BindTree(List<ITreeAble<T>> dataList, T topNodeID)
        {
            _dataList = dataList;
            _topNodeID = topNodeID;
            List<ITreeAble<T>> firstLevel = (from dl in _dataList
                                             where dl.ParentID.Equals(_topNodeID)
                                             orderby dl.OrderID
                                             select dl).ToList<ITreeAble<T>>();
            foreach (ITreeAble<T> mi in firstLevel)
            {
                FlyTreeNode node = GetNode(mi);
                _treeControl.Nodes.Add(node);
                BindChildNodes(node);
            }
        }

        /// <summary>
        /// 异步绑定树,要设定树的属性PostBackOnExpand="True"
        /// </summary>
        /// <param name="level">绑定的层级,从0开始计数</param>
        /// <param name="topNodeID">顶节点ID</param>
        public void BindTreeAsyn(List<ITreeAble<T>> dataList, T topNodeID, int level)
        {
            _dataList = dataList;
            _topNodeID = topNodeID;
            List<ITreeAble<T>> firstLevel = (from dl in _dataList
                                             where dl.ParentID.Equals(_topNodeID)
                                             orderby dl.OrderID
                                             select dl).ToList<ITreeAble<T>>();
            firstLevel.ForEach((a) => _treeControl.Nodes.Add(GetAsynNode(a)));
            //设定初始展开级别
            _treeControl.ExpandLevel = level;
        }

        private void BindChildNodes(FlyTreeNode node)
        {
            List<ITreeAble<T>> children = (from ml in _dataList
                                           where ml.ParentID.Equals(int.Parse(node.Value))
                                           select ml).ToList<ITreeAble<T>>();
            foreach (ITreeAble<T> mi in children)
            {
                FlyTreeNode newNode = GetNode(mi);
                node.ChildNodes.Add(newNode);
                BindChildNodes(newNode);
            }
        }

        protected FlyTreeNode GetNode(ITreeAble<T> mi)
        {
            FlyTreeNode node = null;
            //如果没有外部实现,采用默认实现
            if (_GetNewNode == null)
                node = new FlyTreeNode(mi.Name, mi.ID.ToString());
            else
                node = _GetNewNode(mi);
            return node;
        }

        protected FlyTreeNode GetAsynNode(ITreeAble<T> mi)
        {
            FlyTreeNode node = GetNode(mi);
            node.PopulateNodesOnDemand = (_HasChildren == null) ? true : _HasChildren(node.Value);
            return node;
        }

        /// <summary>
        /// 节点展开时,绑定子节点
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void _treeControl_PopulateNodes(object sender, NineRays.WebControls.FlyTreeNodeEventArgs e)
        {
            if (_GetChildDelegate == null)
                throw new Exception("GetChildNodes委托为空,请检测构造函数。");
            List<ITreeAble<T>> childrenList = _GetChildDelegate(e.Node.Value);
            childrenList.ForEach((a) => e.Node.ChildNodes.Add(GetAsynNode(a)));
        }
    }

4. 最后来用一下,看看足够简单不。

1. 全部绑定时

            if (!IsPostBack)

            {

                //通过BLL,查询获得对象列表

                List<ProjectTree> orList = TestTreeBLL.Instance.GetAll();

                //将ProjectTree转成接口列表

                List<ITreeAble<int>> datalist = orList.ConvertAll<ITreeAble<int>>((P) => P as ITreeAble<int>);

                //使用Helper来绑定树,GetNewNode参数,构造一个新的树节点的方法,如果传入null,则使用默认的实现。

                FlyTreeBindHelper<int> helper = new FlyTreeBindHelper<int>(flyTreeView, GetNewNode);

                //全部绑定

                helper.BindTree(datalist,0);

            }

        /// <summary>
        /// 生成树节点的自定义实现
        /// </summary>
        /// <param name="mi"></param>
        /// <returns></returns>
        protected FlyTreeNode GetNewNode(ITreeAble<int> mi)
        {
            return new FlyTreeNode(mi.Name, mi.ID.ToString());
        }

2. 点击树节点, 异步加载子节点.

           FlyTreeBindHelper<int> helper2 = new FlyTreeBindHelper<int>(flyTreeView, null, GetChidren, HasChildren);

            if (!IsPostBack)

            {

                //通过BLL,查询获得对象列表

                List<ProjectTree> orList = TestTreeBLL.Instance.GetAll();

                //将ProjectTree转成接口列表

                List<ITreeAble<int>> datalist = orList.ConvertAll<ITreeAble<int>>((P) => P as ITreeAble<int>);

              //异步绑定

                helper2.BindTreeAsyn(datalist, 0, 0);

            }

要注意的地方是,与全部绑定不同,new FlyTreeBindHelper必须写在if (!IsPostBack)外边,每次加载时都运行一次,以绑定树节点的展开事件。

并且要多传入两个参数:GetChidren, HasChildren。

         protected List<ITreeAble<int>> GetChidren(string parentID)

        {

            List<ProjectTree> orList = TestTreeBLL.Instance.Find("ParentID=" + parentID);

            //将ProjectTree转成接口列表

            return orList.ConvertAll<ITreeAble<int>>((P) => P as ITreeAble<int>);

        }

        protected bool HasChildren(string parentID)

        {

            return true;

        }

GetChidren方法,是作为一个委托传入构造函数的,用于展开节点时获取子节点的数据。

HasChildren方法,也是作为一个委托传入构造函数,这个参数可以为null,他获取当前节点是否有子节点,如果有就会在树节点上显示

可展开的符号,如果没有子节点,就不能展开。 当传入Null作为参数时,所有节点都会显示可展开的符号。

总结: 这里用的FlyTree控件, 要支持别的控件, 可进一步改造. 办法总比困难多.