开原版好像是没有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里加上这个方法就可以了
可以看到层级正确,点击方法明天再说。

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

  1. FineUI开源版(ASP.Net)开发实践-目录

    点我订阅 目前所有博客的截图,方便离线观看,点图片 FineUI初学手册 下载,实例项目搭建 FineUI初学手册-部分JS整理 部分JS整理 ASP.NET-FineUI开发实践-1 实际开发环境是 ...

  2. FineUI开发实践-目录

    点我订阅 目前所有博客的截图,方便离线观看,点图片 FineUI初学手册 下载,实例项目搭建 FineUI初学手册-部分JS整理 部分JS整理 ASP.NET-FineUI开发实践-1 实际开发环境是 ...

  3. FineUI开发实践

    ASP.NET-FineUI开发实践-7 摘要: 下拉显示grid列表.其实很简单,但是试了很多方法,水平有限,主要是都不好使,还是简单的好使了,分享下.先是看了看网上的,是直接写个了extjs控件类 ...

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

    1.加图标和事件 上次已经通过DataSimulateTreeLevelField属性控制了树节点的显示,不用看也知道就是给指定列数据前面加个图标的HTML 可以在SimulateTreeHeper类 ...

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

    现在是这么个问题,在开发中表格是动态出来的,就是标准板是全部字段列出,客户要根据情况列出自己想要的,在增加操作页面的同时要是能用前台自带的功能直接保存到后台就好了,现在的列显示和隐藏是不回发的. 1. ...

  6. ASP.NET MVC5 网站开发实践(二) Member区域–管理列表、回复及删除

    本来想接着上次把这篇写完的,没想到后来工作的一些事落下了,放假了赶紧补上. 目录: ASP.NET MVC5 网站开发实践 - 概述 ASP.NET MVC5 网站开发实践(一) - 项目框架 ASP ...

  7. ASP.NET MVC5 网站开发实践(二) Member区域–我的咨询列表及添加咨询

    上次把咨询的架构搭好了,现在分两次来完成咨询:1.用户部分,2管理部分.这次实现用户部分,包含两个功能,查看我的咨询和进行咨询. 目录: ASP.NET MVC5 网站开发实践 - 概述 ASP.NE ...

  8. ASP.NET MVC5 网站开发实践(二) Member区域 - 咨询管理的架构

    咨询.留言.投诉等功能是网站应具备的基本功能,可以加强管理员与用户的交流,在上次完成文章部分后,这次开始做Member区域的咨询功能(留言.投诉都是咨询).咨询跟文章非常相似,而且内容更少.更简单. ...

  9. ASP.NET MVC5 网站开发实践(二) Member区域 - 修改及删除文章

    上次做了显示文章列表,再实现修改和删除文章这部分内容就结束了,这次内容比较简单,由于做过了添加文章,修改文章非常类似,就是多了一个TryUpdateModel部分更新模型数据.   目录: ASP.N ...

随机推荐

  1. .Echo 命令中经常提到回显,是什么意思?

    C:\>echo on C:\>date /t2006-08-06 星期日 C:\>以上内容是在打开回显的情况下执行的,其实我们想看到的只有2006-08-06 星期日这一行内容,但 ...

  2. PLSQL Developer如何设置自动打开上次编辑的文件

    作为开发人员经常把sql语句保存到文件中以方便下次继续使用,问题是plsqlDev重启后每次都需要手工打开这个文件,好不方便: 以下设置是plsqlDev启动后自动打开上次编辑的文件. 选择配置> ...

  3. HttpClient4.3.6 实现https访问

    package httptest; import java.io.IOException; import java.nio.charset.Charset; import java.security. ...

  4. Important Programming Concepts (Even on Embedded Systems) Part V: State Machines

    Earlier articles in this series: Part I: Idempotence Part II: Immutability Part III: Volatility Part ...

  5. Unity NGUI 网络斗地主 -发牌 脚本交互

    Unity NGUI 网络斗地主 -发牌 脚本交互 @By 灰太龙 Unity4.2.1f4 NGUI 3.0.4 本篇说的问题是脚本与控件的交互! 现在对界面进行了改进,先看副图! 1.制作发牌效果 ...

  6. python PIL except: IOError: decoder jpeg not available

    今天在Python运行环境的服务器弄一个有关图像处理的程序时报这样的错: 1 NameError: global name 'Image' is not defined import Image 了下 ...

  7. PCB板可靠性测试方法择要

    在电子设备中PCB板是所有电子设备的核心,其的可靠性程度会直接影响了产品的耐用性和寿命.因此在我们实验室(上海摩尔实验室)的实际工作中遇到了越来越多的针对PCB板的可靠性的测试要求,现根据一些企业的内 ...

  8. COJ 3007 Mr.Yang的小助手

    传送门:http://oj.cnuschool.org.cn/oj/home/problem.htm?problemID=1037 试题描述: 信息学社团已经逐渐发展壮大,成员也越来越多.现在,有n个 ...

  9. Search for a Range ——LeetCode

    Given a sorted array of integers, find the starting and ending position of a given target value. You ...

  10. QT5.7.0在win10下使用visual studio 2015编译(目标平台 xp)

    环境:win10+vs2015+QT5.7.0 目标:编译出能在windows xp上运行的QT 通过baidu和bing找出来的结果没有一个能成功运行,大部分都能编译成功,并完美解决“exe不是有效 ...