最近项目中有一个需求,将树形结构的数据,以表格的形式展示在页面中,下图是最终呈现效果:

  

  源码:

  

@{
Layout = null;
} <!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Asp.Net Mvc自定义控件之树形结构数据生成表格 - WPF特工队内部资料</title>
    <style type="text/css">
table.hovertable {
font-family: verdana, arial, sans-serif;
font-size: 11px;
color: #333333;
border-width: 1px;
border-color: #999999;
border-collapse: collapse;
} table.hovertable th {
background-color: #c3dde0;
border-width: 1px;
padding: 8px;
border-style: solid;
border-color: #a9c6c9;
} table.hovertable tr {
background-color: #d4e3e5;
} table.hovertable td {
border-width: 1px;
padding: 8px;
border-style: solid;
border-color: #a9c6c9;
text-align: center;
} table.hovertable td.td-left {
text-align: left;
}
</style>
</head>
<body>
@Html.TabTree(ViewData["Source"] as List<V_TabTree>, @classname: "hovertable")
</body>
</html>

后台代码:

namespace FLSoft.WebUI
{
public class Data
{
/// <summary>
/// 构建数据源
/// </summary>
/// <returns></returns>
public static List<V_TabTree> GetData()
{
List<V_TabTree> _datas = new List<V_TabTree>();
//
#region 深度测试 var 深度测试 = new V_TabTree("测试1", )
{
Childs = new List<V_TabTree>() {
new V_TabTree("测试1-1",){
Childs = new List<V_TabTree>(){
new V_TabTree("测试1-1-1",){
Childs =new List<V_TabTree>(){
new V_TabTree("测试1-1-1-1"),
new V_TabTree("测试1-1-1-2")
}
},
new V_TabTree("测试1-1-2",){
Childs =new List<V_TabTree>(){
new V_TabTree("测试1-1-2-1"),
new V_TabTree("测试1-1-2-2")
}
}
}
},
new V_TabTree("测试1-2",){
Childs = new List<V_TabTree>(){
new V_TabTree("测试1-2-1",){
Childs =new List<V_TabTree>(){
new V_TabTree("测试1-2-1-1")
}
}
}
}
}
};
#endregion #region 高压配电柜
var 高压配电柜 = new V_TabTree("高压配电柜", )
{
Childs = new List<V_TabTree>() {
new V_TabTree("真空断路器",){
Childs = new List<V_TabTree>(){
new V_TabTree("固定牢固无松动,外表清洁完好,分合闸无异常")
}
},
new V_TabTree("“五防”功能",){
Childs = new List<V_TabTree>(){
new V_TabTree("工作正常")
}
},
new V_TabTree("接线端子",){
Childs = new List<V_TabTree>(){
new V_TabTree("无烧毁或松动")
}
},
new V_TabTree("微机综保",){
Childs = new List<V_TabTree>(){
new V_TabTree("上下级联动协调")
}
}
}
};
#endregion #region 阀门 var 阀门 = new V_TabTree("阀门", )
{
Childs = new List<V_TabTree>() {
new V_TabTree("阀门保养",){
Childs = new List<V_TabTree>(){
new V_TabTree("检查各零件部件的腐蚀、磨损程度,发现损坏则更换或整修"),
new V_TabTree("清除垃圾油污,并加注润滑脂1"),
new V_TabTree("清除垃圾油污,并加注润滑脂2")
}
},
new V_TabTree("计量仪表",){
Childs = new List<V_TabTree>(){
new V_TabTree("计量准确")
}
}
}
};
#endregion #region 阀门2 var 阀门2 = new V_TabTree("阀门2", )
{
Childs = new List<V_TabTree>() {
new V_TabTree("阀门保养",){
Childs = new List<V_TabTree>(){
new V_TabTree("检查各零件部件的腐蚀、磨损程度,发现损坏则更换或整修"),
new V_TabTree("清除垃圾油污,并加注润滑脂")
}
}
}
};
#endregion #region 电容器柜 var 电容器柜 = new V_TabTree("电容器柜", )
{
Childs = new List<V_TabTree>() {
new V_TabTree("电力电容",){
Childs = new List<V_TabTree>(){
new V_TabTree("无漏油、过热、膨胀现象,绝缘正常")
}
},
new V_TabTree("接触器",){
Childs = new List<V_TabTree>(){
new V_TabTree("触头无烧损痕迹、闭合紧密")
}
},
new V_TabTree("熔断器",){
Childs = new List<V_TabTree>(){
new V_TabTree("无烧损痕迹")
}
}
}
};
#endregion _datas.Add(深度测试);
_datas.Add(高压配电柜);
_datas.Add(阀门);
_datas.Add(阀门2);
_datas.Add(电容器柜);
return _datas;
}
}
/// <summary>
/// 表格树数据模型
/// </summary>
public class V_TabTree
{
#region 构造函数 public V_TabTree()
{
this.Depth = ;
this.Childs = new List<V_TabTree>();
}
public V_TabTree(String value)
: this()
{
this.Value = value;
}
public V_TabTree(String value, Int32 depth)
: this(value)
{
this.Depth = depth;
} #endregion /// <summary>
/// 主键
/// </summary>
public Int32 ID { get; set; }
/// <summary>
/// 所属父节点
/// </summary>
public Int32 ParentID { get; set; }
/// <summary>
/// 节点内容
/// </summary>
public String Value { get; set; }
/// <summary>
/// 子字节
/// </summary>
public List<V_TabTree> Childs { get; set; }
/// <summary>
/// 节点深度
/// </summary>
public Int32 Depth { get; private set; }
/// <summary>
/// 节点是否已生成
/// </summary>
public Boolean IsGenerate { get; set; }
/// <summary>
/// 添加子节点
/// </summary>
/// <param name="node"></param>
public virtual void Addchildren(V_TabTree node)
{
this.Childs.Add(node);
} /// <summary>
/// 获取当前节点的深度
/// 参考:
/// --| 菜单1
/// ----|菜单1.1
/// ------|菜单1.1.1
/// ------|菜单1.1.2
/// ----|菜单1.2
/// ------|菜单1.2.1
/// ------|菜单1.2.2
/// 如上是一个三级节点,但是顶级节点的深度为4,表示这个菜单1的所有子节点总和
/// </summary>
/// <returns></returns>
public virtual Int32 GetDepth()
{
Int32 _depth = ;
//获取当前节点的深度
if (this.Childs.Count > )
{ } return _depth;
}
} /// <summary>
/// 创建HTML Table数据模型
/// </summary>
public class V_Tab
{
public V_Tab()
{
this.Ths = new List<V_Tr>();
this.Trs = new List<V_Tr>();
}
/// <summary>
/// 表格标题
/// </summary>
public List<V_Tr> Ths { get; set; }
/// <summary>
/// 表格内容
/// </summary>
public List<V_Tr> Trs { get; set; } } /// <summary>
/// 创建HTML Table 列数据模型
/// </summary>
public class V_Td
{
public V_Td()
{
this.Colspan = ;
this.Rowspan = ;
} /// <summary>
/// 显示内容
/// </summary>
public String Value { get; set; }
/// <summary>
/// 标题合并列数
/// </summary>
public Int32 Colspan { get; set; }
/// <summary>
/// 标题合并行数
/// </summary>
public Int32 Rowspan { get; set; }
} /// <summary>
/// 创建HTML Table行数据模型
/// </summary>
public class V_Tr
{
public V_Tr()
{
this.Tds = new List<V_Td>();
}
/// <summary>
/// 行样式名称
/// </summary>
public String ClassName { get; set; }
/// <summary>
/// 列数据集合
/// </summary>
public List<V_Td> Tds { get; set; }
} /// <summary>
/// TabTree 自定义控件
/// </summary>
public static class MvcHtmlStringExtensions
{
/// <summary>
/// 构建表格
/// </summary>
/// <param name="helper"></param>
/// <returns></returns>
public static MvcHtmlString TabTree(this HtmlHelper helper, V_Tab values, String classname)
{
StringBuilder htmlStr = new StringBuilder();
if (values == null) return new MvcHtmlString("<TABLE></TABLE>");
htmlStr.Append("<TABLE class= " + classname + ">");
if (values.Ths != null)
{
foreach (var th in values.Ths)
{
htmlStr.Append("<TR>");
if (th.Tds != null)
{
foreach (var td in th.Tds)
{
htmlStr.Append("<TH colspan =" + td.Colspan + " rowspan =" + td.Rowspan + " >");
htmlStr.Append(td.Value + "</TH>");
}
}
htmlStr.Append("</TR>");
}
}
if (values.Trs != null)
{
foreach (var tr in values.Trs)
{
htmlStr.Append("<TR>");
if (tr.Tds != null)
{
foreach (var td in tr.Tds)
{
htmlStr.Append("<TD colspan =" + td.Colspan + " rowspan =" + td.Rowspan + " >");
htmlStr.Append(td.Value + "</TD>");
}
}
htmlStr.Append("</TR>");
}
}
htmlStr.Append("</TABLE>");
return new MvcHtmlString(htmlStr.ToString());
} /// <summary>
/// 构建表格
/// </summary>
/// <param name="helper"></param>
/// <param name="tab"></param>
/// <returns></returns>
public static MvcHtmlString TabTree(this HtmlHelper helper, List<V_TabTree> source, String classname)
{
StringBuilder htmlStr = new StringBuilder();
V_Tab _tab = new V_Tab();
_tab.Trs = BuildTr(source);
return TabTree(helper, _tab, classname);
} /// <summary>
/// 将树形的数据构建为HTML Table数据模型
/// </summary>
/// <param name="values"></param>
/// <returns></returns>
private static List<V_Tr> BuildTr(List<V_TabTree> values)
{
List<V_Tr> _trs = new List<V_Tr>();
foreach (var value in values)
{
_trs.AddRange(GenerateTr(value)); //一个顶级节点的行数由value.Depth属性来确定
}
return _trs;
}
/// <summary>
/// 仅满足1级节点合并
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
private static List<V_Tr> BuildTr(V_TabTree value)
{
List<V_Tr> _trs = new List<V_Tr>();
//Depth属性用于判断当前的数据产生Tr的数量
for (int i = ; i < value.Depth; i++)
{
V_Tr _tr = new V_Tr();
if (i == )
{
V_Td _td = new V_Td() { Value = value.Value, Rowspan = value.Depth };
_tr.Tds.Add(_td);
}
//检测是否包含子节点,如果包含
if (value.Childs != null && value.Childs.Count > )
{
//顶级节点的深度与其子节点数目相等时,后续表格的列都是一对一的
if (value.Depth == value.Childs.Count)
{
_tr.Tds.AddRange(BuildTd(value.Childs[i]));
}
else //如果几点深度大于子节点时,需要计算循环深度
{
//父节点的级别与所有子节点的深度总和相等
}
}
_trs.Add(_tr);
}
return _trs;
} /// <summary>
/// 仅满足1-2级节点合并
/// </summary>
/// <param name="parentNode"></param>
/// <returns></returns>
private static List<V_Tr> BuildTrEx(V_TabTree parentNode)
{
List<V_Tr> _trs = new List<V_Tr>();
V_Tr _tr = new V_Tr(); //当包含一个数据节点时,创建第一个TR
_tr.Tds = BuildTd(parentNode); //填充TR包含的所有的TD
_trs.Add(_tr); //填充TR集合
if (parentNode.Depth > ) //判断Depth>1表示这个节点下面还包含TR行
{
if (parentNode.Childs.Count > ) //如果当前节点包含多个子节点,需要循环遍历
{
//后续描述的"当前节点",是当前For循环上下文的节点,不是指的参数节点
var _childNodes = parentNode.Childs;
for (int i = ; i < _childNodes.Count; i++) //在循环子节点时,子节点的第一个项已经赋值给Parent节点了
{
//所以只处理Depth>1的业务,parentNode的子节点(childNodes)还包含可以循环子节点
if (_childNodes[i].Depth > ) //表示当前这个节点后续的TR行包含多个
{
//继续循环当前节点的子节点(顶级节点的子节点的子节点判断,有点绕)
for (int ii = ; ii < _childNodes[i].Childs.Count; ii++)
{
if (ii > )
{
//因为是当前节点的二级节点,那么第一条数据被上父节点给取走了,循环就需要从i+1开始
_trs.AddRange(BuildTrEx(_childNodes[i].Childs[ii]));
}
}
}
else //如果当前节点的Depth =1 ,表示这个节点已经被赋值给Parent节点了,
{
if (i > )
{
_trs.AddRange(BuildTrEx(_childNodes[i])); //取子节点递归查找
}
} }
}
else //二级节点只有一项时
{
for (int i = ; i < parentNode.Childs[].Childs.Count - ; i++)
{
_trs.AddRange(BuildTrEx(parentNode.Childs[].Childs[i + ]));
}
}
} return _trs;
} /// <summary>
/// 多级节点嵌套合并
/// </summary>
/// <param name="parentNode">父节点</param>
/// <returns></returns>
private static List<V_Tr> GenerateTr(V_TabTree parentNode)
{
List<V_Tr> _trs = new List<V_Tr>();
if (!parentNode.IsGenerate)
{
V_Tr _tr = new V_Tr();
_tr.Tds = BuildTd(parentNode);
_trs.Add(_tr);
}
if (parentNode.Depth > ) //有多级深度
{
//检测其子节点是否包含深度,肯定是要添加一个循环遍历的
List<V_TabTree> childNodes = parentNode.Childs;
for (int i = ; i < childNodes.Count; i++)
{
_trs.AddRange(GenerateTr(childNodes[i]));
}
}
return _trs;
} private static List<V_Td> BuildTd(V_TabTree value)
{
List<V_Td> _tds = new List<V_Td>();
value.IsGenerate = true;
V_Td _td = new V_Td() { Value = value.Value, Rowspan = value.Depth > ? value.Depth : };
_tds.Add(_td);
if (value.Depth > )
{
_tds.AddRange(BuildTd(value.Childs[]));
}
return _tds;
} } }

全部源码:Asp.Net Mvc自定义控件之树形结构数据生成表格-WPF特工队内部资料.rar

  

  

Asp.Net Mvc自定义控件之树形结构数据生成表格 - WPF特工队内部资料的更多相关文章

  1. ASP.NET MVC 5 学习教程:生成的代码详解

    原文 ASP.NET MVC 5 学习教程:生成的代码详解 起飞网 ASP.NET MVC 5 学习教程目录: 添加控制器 添加视图 修改视图和布局页 控制器传递数据给视图 添加模型 创建连接字符串 ...

  2. Asp.net mvc 5 CRUD代码自动生成工具- vs.net 2013 Saffolding功能扩展

    Asp.net mvc 5 CRUD代码自动生成工具 -Visual Studio.net2013 Saffolding功能扩展 上次做过一个<Asp.net webform scaffoldi ...

  3. 在ASP.NET MVC下实现树形导航菜单

    在需要处理很多分类以及导航的时候,树形导航菜单就比较适合.例如在汽车之家上: 页面主要分两部分,左边是导航菜单,右边显示对应的内容.现在,我们就在ASP.NET MVC 4 下临摹一个,如下: 实现的 ...

  4. ASP.NET MVC 3 配置EF自动生成模型

    Tools(工具) =>  扩展工具 => Nuget Tools(工具) => Nuget=>程序包管理器控制台 Nuget 程序包管理器 => Install-Pac ...

  5. 如何在FineUIMvc(ASP.NET MVC)中显示复杂的表格列数据(列表和对象)?

    起源 最初,这个问题是知识星球内的一个网友提出的,如何在FineUIMvc中展现复杂的列数据? 在FineUIPro中,我们都知道有一个 TemplateField 模板列可以使用,我们只需要在后台定 ...

  6. [转]Asp.net MVC 利用PartialView 构造自定义菜单

    本文转自:http://www.cnblogs.com/huyq2002/archive/2012/01/06/2314838.html 在VS2010中利用Asp.net MVC自带的模板生成的菜单 ...

  7. 在 ASP.NET MVC 中使用 HTTPS (SSL/TLS)

    某些安全性较高的网页,如网上支付或用户登陆页面,可能会使用到https(SSL/TLS)来提高安全性.本文介绍了如何在ASP.NET MVC中强制某action使用https和如何进行向https页面 ...

  8. ASP.NET MVC:Razor 引入命名空间

    原文:ASP.NET MVC:Razor 引入命名空间 页面中引用 c# @using MvcApplication83.Models @using MvcApplication83.Common 行 ...

  9. ASP.NET MVC:创建 ModelBinder 自动 Trim 所有字符串

    ASP.NET MVC:创建 ModelBinder 自动 Trim 所有字符串 2010-12-29 21:32 by 鹤冲天, 4289 阅读, 14 评论, 收藏, 编辑 用户输入的字符串前后的 ...

随机推荐

  1. 【洛谷5794】[THUSC2015] 解密运算(模拟)

    点此看题面 大致题意: 对于一个字符串,我们在其末尾添加一个'.',将字符串视作一个环,则可以从\(n+1\)个位置断开得到\(n+1\)个新串.现将这\(n+1\)个新串按字典序排序('.'的字典序 ...

  2. C语言程序设计100例之(19):欢乐的跳

    例19   欢乐的跳 题目描述 一个n个元素的整数数组,如果数组两个连续元素之间差的绝对值包括了[1,n-1]之间的所有整数,则称之符合“欢乐的跳”,如数组1 4 2 3符合“欢乐的跳”,因为差的绝对 ...

  3. Java大数类 BigInteger

    package bigint; /** * This class encapsulates a BigInteger, i.e. a positive or negative integer * wi ...

  4. Selenium(十三):验证码的处理、WebDriver原理

    1. 验证码的处理 对于Web应用来说,大部分的系统在用户登录时都要求用户输入验证码.验证码的类型很多,有字母数字的.有汉字的,甚至还需要用户输入一道算术题的答案的.对于系统来说,使用验证码可以有效地 ...

  5. Scrapy框架-爬虫程序相关属性和方法汇总

    一.爬虫项目类相关属性 name:爬虫任务的名称 allowed_domains:允许访问的网站 start_urls: 如果没有指定url,就从该列表中读取url来生成第一个请求 custom_se ...

  6. CSS样式继承性

    CSS样式继承介绍 外层元素身上的样式会被内层元素所继承. 当内层元素身上的样式与外层的元素身上的样式相同时内层元素样式会覆盖外层元素样式. 并不是所有的样式都能够继承,只有文本与字体样式属性才能够被 ...

  7. 模版引擎Handlebars和Mustache

    Handlebars是一款很高效的模版引擎,提供语意化的模版语句,最大的兼容Mustache模版引擎, 提供最大的Mustache模版引擎兼容, 无需学习新语法即可使用; 下面这个是基本的模版表达式, ...

  8. LG1344 「USACO4.4」Pollutant Control 最小割

    问题描述 LG1344 题解 我太菜了,我一开始竟然没有看出这是个最小割裸题... 两个询问. 第一个询问,直接跑最小割就好了. 第二个询问,建图的时候边权建 \(1\) ,代表割掉这条边需要 \(1 ...

  9. This compilation unit is not on the build path of java project (此编译单元不在java项目的生成路径上)

    This compilation unit is not on the build path of a Java project 解决办法​ 索发现,大致是因为项目文件缺失. 解决办法:找到项目根目录 ...

  10. Redis思维导图

    Redis基本数据结构 1.String 1.1 数据结构 long len byte数组长度 long free 可用数组长度 char buff[] 数据内容 1.2 命令 键值:设置值通过字符串 ...