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

  

  源码:

  

@{
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. FFT/NTT中档题总结

    被DeepinC%怕了,把一些题放到这里来 T1Normal 其实这道题放到中档题也不太合适,个人感觉真的很难,机房里好像都是颓的题解 因为期望的可加性,把每个点的贡献单独处理,即求期望深度 考虑$y ...

  2. Git教程---由浅入深

    初学者很难找到一个由浅入深,学完后能立刻上手的Git教程 Git用户 V&Git专家 Git是一个工具,是目前世界上最先进的分布式版本控制系统(没有之一). 集中式的版本控制系统  V& ...

  3. Git终端命令行的常用操作

    一.git源代码管理的优点 方便多人协同开发.工作 降低代码的管理成本 良好的分支管理机制 二.结构分析 服务端和客户端都有版本控制能力,都能进行代码的提交.合并 结构一: 结构二: 三.工作区的创建 ...

  4. js之好看的鼠标点击-光标特效

    1.光标特效 <script src="https://blog-static.cnblogs.com/files/axqa/bubbleCursor.js">< ...

  5. Linux下离线安装python项目的依赖包

    第一步新建一个site-packages文件夹,把python项目有需要的依赖包名称导出到site-packages下的requirements.txt中 $ pip3 freeze > req ...

  6. FCC---Use the CSS Transform scale Property to Change the Size of an Element

    To change the scale of an element, CSS has the transform property, along with its scale() function. ...

  7. electronr进行签名与公证

    windows: 1.设置package.json的有关window打包的相关内容 "win": { "icon": "build/icons/ico ...

  8. JS 对象定义

    JS 对象 JavaScript 中的所有事物都是对象:字符串.数值.数组.函数... 此外,JavaScript 允许自定义对象. JavaScript 对象 JavaScript 提供多个内建对象 ...

  9. 035.[转] 获取HttpServletRequest请求Body中的内容

    注意: HttpServletRequest 请求中的 body 内容仅能调用 request.getInputStream(), request.getReader()和request.getPar ...

  10. Shell—引入外部脚本文件

    在Shell中要如何调用别的shell脚本,或别的脚本中的变量,函数呢? 方式1:. filename               方式2:source filename    需要注意: 两个点之间 ...