ASP.NET-FineUI开发实践-13(一)

开原版好像是没有gird树,有一个扩展列下的模拟树列,就是不能展开,专业版有,开原版我弄了弄,思路是有,就是不是很好实现。这篇博客直接写出了(一)说明一个肯定是写不完的。

FineUI重在封装,改这个我也不打算大量的js实现,最起码前台传几个属性就可以了,后台就都实现了,这是初衷,就是有点慢,太慢的话以后会改成前台实现的。以前我修改的或新建的不管是前后台方法都是可以通用的,尽量避免一个页面写一遍,那不是好代码。

1.核心

对于显示树层级,主要的就是缩进,这个弄好了就可以了,好在列有个DataSimulateTreeLevelField属性,根本就不用担心,这里传的是层级,有就传,没有就创造,先放着。当然不能有也只能重写数据源,这也是树grid慢的原因之一。

考虑完显示就是考虑展开和收起,方法先不谈,方法是被触发的,这里就要靠点击触发展开收起方法,专业版是个箭头,我也找了个图标,每个行放一个,这就用到了重写数据源,有很多地方可以写:绑定之前,绑定之后渲染之前,行绑定事件里,也可以跟踪DataSimulateTreeLevelField属性,他就是加了个图标,他怎么加的我怎么加就可以了。图标的触发就是jq了,其实完全可以写成自定义事件就是给grid加个事件,这个也是后话。

触发完了才是展开和收起的方法,一下就让我想到了删除和添加,不就是删除指定行和添加指定行么,但是添加有难度,删除了数据丢了我加谁,但是通过实验我看见js执行的删除没有真的删除数据源,只是把显示的扔了,这就好办了,重新绑一下又回来了(这个是从Demo里删除后需要保存想到的),那么只有删除,控制了删除和重新载入数据源就可以实现展开了。删除方法    store.removeAt(rowIndex); 重新载入.f_loadData(); 很容易能找到。

2.参数

刚说用参数实现了,看到专业版用到的参数有  是否开启树,树字段的列名,树ID,父ID

说谢谢就可以拿来用了,目前够用了。注意我这里的树ID和父ID不是数据源,而是列名ColumnID

        /// <summary>
        /// 是否启用树
        /// </summary>
        [Category(CategoryName.OPTIONS)]
        [DefaultValue(null)]
        [Description("是否启用树")]
        public bool EnableTree
        {
            get
            {
                object obj = FState["EnableTree"];
                return obj == null ? false : (bool)obj;
            }
            set
            {
                FState["EnableTree"] = value;
                if (value)
                {
                    EnableRowClickEvent = true;
                }
            }
        }
        /// <summary>
        /// 树节点列名
        /// </summary>
        [Category(CategoryName.OPTIONS)]
        [DefaultValue(null)]
        [Description("树节点列名")]
        public string TreeName
        {
            get
            {
                object obj = FState["TreeName"];
                return obj == null ? "" : (string)obj;
            }
            set
            {
                FState["TreeName"] = value;
            }
        }

        /// <summary>
        /// 主键ID
        /// </summary>
        [Category(CategoryName.OPTIONS)]
        [DefaultValue(null)]
        [Description("主键ID")]
        public string TreeDataIDField
        {
            get
            {
                object obj = FState["TreeDataIDField"];
                return obj == null ? "" : (string)obj;
            }
            set
            {
                FState["TreeDataIDField"] = value;
            }
        }
        /// <summary>
        /// 父节点列名
        /// </summary>
        [Category(CategoryName.OPTIONS)]
        [DefaultValue(null)]
        [Description("父节点列名")]
        public string TreeDataParentIDField
        {
            get
            {
                object obj = FState["TreeDataParentIDField"];
                return obj == null ? "" : (string)obj;
            }
            set
            {
                FState["TreeDataParentIDField"] = value;
            }
        }

3.显示方法

首先我找到了用到DataSimulateTreeLevelField属性的方法,方法名称为Grid.AfterDataBind

很明显绑定之后触发的,好吧一切从这里开始。

意思就是如果有这样的列,拿出来,这是我写的

如果开着树,列名不为空,找到列。

再往下,其实现在DataSimulateTreeLevelField是没有值的,写我的

得到层级方法GetLevelNub,通过什么得到呢?数据源,看我传的参数,数据源绑定后变成了Rows,行的集合,操作这个就可以了,根本就不用考虑是DataTable还是IEnumerable

 /// <summary>
        /// 得到当然行的层级
        /// </summary>
        /// <param name="row">当前行</param>
        /// <param name="Rows">行数据集</param>
        /// <returns>层级</returns>
        private int GetLevelNub(GridRow row, GridRowCollection Rows)
        {
            int lub = 0;
            //ID所在列
            int IDindex = FindColumn(TreeDataIDField).ColumnIndex;
            //父ID所在列
            int ParentIDindex = FindColumn(TreeDataParentIDField).ColumnIndex;
            //如果过是第第一级就是0
            if (row.Values[ParentIDindex].ToString() == "" || row.Values[ParentIDindex].ToString() == "0")
            {
                return lub;
            }
            else
            {
                foreach (GridRow gr in Rows)
                {
                    //如果有父级
                    if (gr.Values[IDindex].ToString() == row.Values[ParentIDindex].ToString())
                    {
                        //层级加1
                        lub++;
                        //查看父级的父级
                        int nub = GetLevelNub(gr, Rows);
                        lub += nub == 0 ? 1 : nub;
                    }
                }
            }
            return lub;
        }

这个方法就是个逻辑的问题,循环得到父级就可以了。这里直接用TreeDataIDField就可以了,因为是参数。

这样就可以了,先看一下下。

我新建了页面,新建了数据源,

<f:Grid EnableCollapse="true" Width="800px" Height="400px" runat="server" DataKeyNames="Id,Name"
        ID="Grid1" EnableTree="true" TreeName="name" TreeDataIDField="id" TreeDataParentIDField="topID" ShowBorder="true"
        ShowHeader="true" Title="树表格" >
        <Columns>
            <f:RowNumberField />
            <f:BoundField ColumnID="name" ExpandUnusedSpace="true" DataField="name" HeaderText="名称" >
            </f:BoundField>
            <f:BoundField  ColumnID="id" DataField="id" Width="50px" HeaderText="ID">
            </f:BoundField>
            <f:BoundField  ColumnID="topID" DataField="topID" Width="50px" HeaderText="topID">
            </f:BoundField>
            <f:BoundField DataField="levelcode" Width="100px" HeaderText="层级编号">
            </f:BoundField>
            <f:BoundField ColumnID="levelnub" DataField="levelnub" Width="100px" HeaderText="层级数">
            </f:BoundField>
            <f:BoundField DataField="subitem" Width="100px" HeaderText="是否为子菜单">
            </f:BoundField>
            <f:BoundField DataField="url" Width="100px" HeaderText="地址">
            </f:BoundField>
        </Columns>
    </f:Grid>

OK缩进起效了。但是层级不对,我的下级2和28是下级1 之后的,这是由于数据源没有按层级排序,看来要写个通过父ID给树结构从新排序的方法。

4.重新排序方法

        /// <summary>
        /// 对rows进行重新排序
        /// </summary>
        private void SortTreeRows()
        {
            GridRowCollection newrows = new GridRowCollection();
            //复制到新列表
            foreach (GridRow row in Rows)
            {
                newrows.Add(row);
            }
            //清空
            Rows.Clear();
            int pidindex = FindColumn(TreeDataParentIDField).ColumnIndex;
            int idindex = FindColumn(TreeDataIDField).ColumnIndex;
            //记录根节点
            GridRowCollection onerows = new GridRowCollection();
            //int i = 0;
            foreach (GridRow row in newrows)
            {
                if (row.Values[pidindex].ToString() == "" || row.Values[pidindex].ToString() == "0")
                {
                    //row.RowIndex = i;
                    //i++;
                    //保存跟节点
                    Rows.Add(row);
                    onerows.Add(row);
                }
            }
            int c = onerows.Count;
            //循环根节点插入子节点
            for (int j = 0; j < c; j++)
            {
                GridRow row = onerows[j];
                //注意起始index计算,从新插入的行开始下一次插入
                BuildTree(Rows.Count - c + j, row, newrows);
            }
            for (int i = 0; i < Rows.Count; i++)
            {
                Rows[i].RowIndex = i;
            }
        }
        /// <summary>
        /// 重构行
        /// </summary>
        /// <param name="j">插入的index</param>
        /// <param name="row">当前row</param>
        /// <param name="rows">集合</param>
        private void BuildTree(int j, GridRow row, GridRowCollection rows)
        {
            //得到下层节点index
            string nexindex = GetNextIndex(row, rows);
            if (nexindex != "")
            {
                string[] s = nexindex.Split(‘,‘);
                int c = Rows.Count;
                for (int i = 0; i < s.Length; i++)
                {
                    GridRow dr = rows[Convert.ToInt32(s[i])];
                    //重新计算下一次插入的行号
                    int index = j + i + 1 + (Rows.Count - c);
                    if (Rows.Count != c)
                    {
                        index = index - 1;
                    }
                    //dr.RowIndex = index;
                    Rows.Insert(index, dr);
                    //循环子节点
                    BuildTree(index, dr, rows);
                }
            }
        }

        /// <summary>
        /// 得到下级行号
        /// </summary>
        /// <param name="row">本节点</param>
        /// <param name="Rows">集合</param>
        /// <returns>集合以,隔开</returns>
        private string GetNextIndex(GridRow row, GridRowCollection Rows)
        {
            string topindex = "";
            int pridindex = FindColumn(TreeDataParentIDField).ColumnIndex;
            int idindex = FindColumn(TreeDataIDField).ColumnIndex;
            foreach (GridRow gr in Rows)
            {
                //父ID等于本ID添加到集合
                if (gr.Values[pridindex].ToString() != "" && gr.Values[pridindex].ToString() == row.Values[idindex].ToString())
                {
                    topindex += topindex == "" ? gr.RowIndex.ToString() : "," + gr.RowIndex.ToString();
                }
            }
            return topindex;
        }

逻辑着实的复杂,大体思路是这样滴,先把数据集复制,清空数据集,先找到第一层,Add到Rows,通过第一层找到下一层insert到第一层下,然后逐级insert插入新的子集实现排序,这个方法看着挺恶心,我脑袋也就这样了,各位大大可以帮我写写。

在AfterDataBind里加上这个方法就可以了

可以看到层级正确,点击方法明天再说。

时间: 2024-07-30 19:00:22

ASP.NET-FineUI开发实践-13(一)的相关文章

ASP.NET5+EntityFramework7开发实践(三)

1.说明 在<ASP.NET5+EntityFramework7开发实践(一)>介绍过仓储模式,只是没有在控制器中如何使用? 本章重新补充一下.注意,也会使用ASP.NET5中的依赖注入. 2.仓储模式 先看接口: 1 public interface IRoleRepository:IDisposable 2 { 3 //IEnumerable和IQueryable 4 //二者在EF都会延迟加载,不同的是: 5 //IEnumerable是数据加载到内存,刷选在内存中的数据上执行 6 //

FineUI开发实践-目录

FineUI初学手册 下载,实例项目搭建 ASP.NET-FineUI开发实践-1 实际开发环境是FineUI 4.0.4,编辑页面回发,__doPostBack应用 ASP.NET-FineUI开发实践-2 1.Window控件显示2.显示隐藏控件4.直接通过行号修改指定列内容5.获取iframe ASP.NET-FineUI开发实践-3 1.参照模拟数据库分页通过缓存重写内存分页,优化页面响应速度2.得到指定行指定列的值后台3.按钮至少选择一项的通用方法,OnClientClick+=累加.

ASP.NET-FineUI开发实践-13(二)

1.加图标和事件 上次已经通过DataSimulateTreeLevelField属性控制了树节点的显示,不用看也知道就是给指定列数据前面加个图标的HTML 可以在SimulateTreeHeper类里看到实现方法,不多说了,原理就是循环行累加上图片就可以了,注意图片的ID和样式 /// <summary> /// 给树赋值 /// </summary> private void SetValueTree() { if (EnableTree) { foreach (GridRow

ASP.NET5+EntityFramework7开发实践(一)

 1.创建项目 创建“空白解决方案”,名为GiveCase. 在解决方案里,添加ASP.NET5 Empty模板项目,名为GiveCase.Web.  2.实体类 实体基类: 1 /// <summary> 2 /// 实体 抽象基类 3 /// </summary> 4 /// <typeparam name="TKey">主键类型</typeparam> 5 public abstract class EntityBase<TK

ASP.NET-FineUI开发实践-9(四)

现在是这么个问题,在开发中表格是动态出来的,就是标准板是全部字段列出,客户要根据情况列出自己想要的,在增加操作页面的同时要是能用前台自带的功能直接保存到后台就好了,现在的列显示和隐藏是不回发的. 1.FineUI引用的extjs是ext-part1.js,这就不说了,以前截过图,这个文件是压缩的,参数也是简化的不好看,其实这个就是ext-all.js,ext-all哪来的呢,就是extjs官方实例里下的,下来之后也是压缩的,旁边还有个不压缩的,ext-all-debug.js ,完全可以看,那我

ASP.NET MVC5 网站开发实践(二) Member区域 - 添加文章

转自:http://www.cnblogs.com/mzwhj/p/3592895.html 上次把架构做好了,这次做添加文章.添加文章涉及附件的上传管理及富文本编辑器的使用,早添加文章时一并实现. 要点: 富文本编辑器采用KindEditor.功能很强大,国人开发,LGPL开源,自己人的好东西没有理由不支持. 附件的上传同样基于KindEditor实现,可以上传图片,flash,影音,文件等. 目录 ASP.NET MVC5 网站开发实践 - 概述 ASP.NET MVC5 网站开发实践(一)

ASP.NET程序开发范例宝典

在整理资料时发现一些非常有用的资料源码尤其是初学者,大部分是平时用到的知识点,可以参考其实现方法,分享给大家学习,但请不要用于商业用途. 如果对你有用请多多推荐给其他人分享. 点击对应章节标题下载本章节下所有源代码. 目录: 第2章 HTML开发与实践 15 2.1 框架的使用 16 实例009 使用FrameSet框架布局聊天室 16 实例010 使用IFrame框架布局企业管理系统 17 2.2 滚屏的实现 18 实例011 滚动显示博客公告 18 实例012 滚屏效果并实现超级链接 20

MVC5 网站开发实践 1、建立项目

目录 MVC5 网站开发实践 概述 一.建立项目 1.建立团队项目 在办公室和家里使用不同的电脑,为了方便代码的共享将项目建立为团队项目. 如图打开vs2013→新建→团队项目(图1),会自动打开Visual Studio Online页面(图2),输入微软通行证登录(没有账号去注册一个,免费),跳转到图3界面. 在图3界面输入项目名称和描述,点击Creatr project等待项目创建完成,完成后跳转到图4界面. 在图4中点击Open in Visual Studio,自动启动 vs,并显示团

【小程序】微信小程序开发实践

帐号相关流程 注册范围 企业 政府 媒体 其他组织 换句话讲就是不让个人开发者注册. :) 填写企业信息 不能使用和之前的公众号账户相同的邮箱,也就是说小程序是和微信公众号一个层级的. 填写公司机构信息,对公账户信息 绑定管理员微信 企业认证 公司对公账户对微信进行打款 账户自动验证后,自动认证通过,并将认证资金退回公司对公账户,费用在1元内随机 小程序发布流程 开发实践 这次的demo项目为农历和公历的转换器,重在体验开发流程. AppID(小程序ID) 做上面的那些步骤就是为了得到小程序ID