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

  

  源码:

  

@{
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. Linux 解压xz格式文件及安装xz

    1.安装xz命令 # yum install epel-release -y # yum install xz -y 2.将xz文件解压为tar文件 # xz -d test.tar.xz 3.将ta ...

  2. C# show Environment property info name and value retrieve, Maximize the Console Window based on window resolution

    using System.Reflection; static void ShowEnvironmentInfoDemo() { Type type = typeof(Environment); Pr ...

  3. ASP.NET Core Web 应用程序系列(三)- 在ASP.NET Core中使用Autofac替换自带DI进行构造函数和属性的批量依赖注入(MVC当中应用)

    在上一章中主要和大家分享了在ASP.NET Core中如何使用Autofac替换自带DI进行构造函数的批量依赖注入,本章将和大家继续分享如何使之能够同时支持属性的批量依赖注入. 约定: 1.仓储层接口 ...

  4. netcore3.0使用Session

    首先需要明确一点,netcore使用session不能直接使用,必须引用nuget包并做注册之后才能使用. 例如下面的例子,若未注册session服务会报 HttpContext.Session.Se ...

  5. 洗牌算法及 random 中 shuffle 方法和 sample 方法浅析

    对于算法书买了一本又一本却没一本读完超过 10%,Leetcode 刷题从来没坚持超过 3 天的我来说,算法能力真的是渣渣.但是,今天决定写一篇跟算法有关的文章.起因是读了吴师兄的文章<扫雷与算 ...

  6. 松软科技web课堂:字符串方法和属性

    字符串方法帮助您处理字符串. 字符串方法和属性 原始值,比如“Bill Gates”,无法拥有属性和方法(因为它们不是对象). 但是通过 JavaScript,方法和属性也可用于原始值,因为在执行方法 ...

  7. Web 安全总结

    同源策略 如果两个 URL 的协议.域名和端口都相同,我们就称这两个 URL 同源. 同源策略限制了来自不同源的 JavaScript 脚本对当前 DOM 对象读和写的操作. 同源策略限制了不同源的站 ...

  8. Cesium专栏-裁剪效果(基于3dtiles模型,附源码下载)

    Cesium Cesium 是一款面向三维地球和地图的,世界级的JavaScript开源产品.它提供了基于JavaScript语言的开发包,方便用户快速搭建一款零插件的虚拟地球Web应用,并在性能,精 ...

  9. 并发编程~~~多线程~~~计算密集型 / IO密集型的效率, 多线程实现socket通信

    一 验证计算密集型 / IO密集型的效率 IO密集型: IO密集型: 单个进程的多线程的并发效率高. 计算密集型: 计算密集型: 多进程的并发并行效率高. 二 多线程实现socket通信 服务器端: ...

  10. Scrapy对接Selenium

    首先pip安装selenium,然后下载浏览器驱动 WebDrive下载地址 chrome的webdriver:http://chromedriver.storage.googleapis.com/i ...