你的位置:首页 > ASP.net教程

[ASP.net教程]MVC树控件,mvc中应用treeview,实现复选框树的多层级表单控件


类似于多层级的角色与权限控制功能,用MVC实现MVC树控件,mvc中应用treeview,实现复选框树的多层级表单控件。最近我们的项目中需要用到树型菜单,以前使用WebForm时,树型菜单有微软提供的控件,非常方便,但现在需要在asp.netmvc中使用树形菜单,先说明下我们对树形菜单的需求:

1,支持CheckBox,允许对菜单项进行选择;
2,当选择父菜单时,它下面的子菜单全部选中;
3,当取消父菜单的选中状态时,下面的子菜单也全部取消;
4,比较方便的与MVC结合;

5,能够初始化选中状态。

6,能够以提交表单的方式,一次性将树绑定到后台接收的对象。

 

首先菜单数据对象:

完整的 CheckboxTreeHelper.cs 代码:

 1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Web; 5 using System.Web.Mvc; 6 using System.Web.Mvc.Html; 7 using System.Text; 8  9 /* 10 author:熊学浩 11 time:2016年6月5日 12 description:树形菜单控件(有问题请致信:xiongzaiqiren@163.com),或者请参考【http://www.cnblogs.com/xiongzaiqiren/】 13 */ 14 namespace System.Web.Mvc 15 { 16   /// <summary> 17   /// 菜单数据对象 18   /// </summary> 19   public class CheckboxTreeItem 20   { 21     /// <summary> 22     /// 显示的文本 23     /// </summary> 24     public string Text { get; set; } 25     /// <summary> 26     /// 显示文本对应的值 27     /// </summary> 28     public string Value { get; set; } 29     /// <summary> 30     /// 是否被选中 31     /// </summary> 32     public bool Checked { get; set; } 33     /// <summary> 34     /// 结合表单的辅助属性,View上使用(注意每个层级的索引必需从0开始并且是连续的) 35     /// </summary> 36     public string Index { get; set; } 37  38     /// <summary> 39     /// 子菜单集合 40     /// </summary> 41     public IList<CheckboxTreeItem> Items { get; set; } 42   } 43  44   /// <summary> 45   /// 复选框树控件 46   /// 熊学浩 47   /// 2016年6月3日 48   /// </summary> 49   public static class CheckboxTreeHelper 50   { 51     private static bool baselayer; 52  53     public static String CheckboxTree(this HtmlHelper helper, string Name, CheckboxTreeItem Model, out string this_HtmlDomName, bool isChildNode = false) 54     { 55       if (null == Model) 56       { 57         this_HtmlDomName = string.Empty; 58         return string.Empty; 59       } 60  61       StringBuilder sb = new StringBuilder(); 62       if (!baselayer) 63         sb.Append("<div class=\"CheckboxTree\">"); 64  65       if (!isChildNode) 66         sb.Append("<ul class=\"CBT-ul\">"); 67       sb.Append("<li class=\"CBT-li\">"); 68  69       this_HtmlDomName = Name + "[" + Model.Index + "]"; 70  71       sb.Append("<label style=\"cursor:pointer;\">"); 72       sb.AppendFormat("<input type=\"checkbox\" onchange=\"setCheckboxTreeItemValue(this);\" name=\"{0}\" value=\"{1}\" />", (this_HtmlDomName + ".Checked"), Model.Checked.ToString()); 73       sb.AppendFormat("<span>{0}</span>", Model.Text); 74       sb.Append("</label>"); 75  76       sb.AppendFormat("<input type=\"hidden\" name =\"{0}\" value=\"{1}\" />", (this_HtmlDomName + ".Text"), Model.Text); 77       sb.AppendFormat("<input type=\"hidden\" name =\"{0}\" value=\"{1}\" />", (this_HtmlDomName + ".Value"), Model.Value); 78       sb.AppendFormat("<input type=\"hidden\" name =\"{0}\" value=\"{1}\" />", (this_HtmlDomName + ".Index"), Model.Index); 79  80       if (null != Model.Items) 81       { 82         sb.Append("<ul class=\"CBT-ul\">"); 83         for (var i = 0; i < Model.Items.Count; i++) 84         { 85           string _this_HtmlDomName; 86           sb.Append(CheckboxTree(helper, this_HtmlDomName + ".Items", Model.Items[i], out _this_HtmlDomName, true)); 87         } 88         sb.Append("</ul>"); 89       } 90  91       sb.Append("</li>"); 92       if (!isChildNode) 93         sb.Append("</ul>"); 94  95       if (!baselayer) 96         sb.Append("</div>"); 97  98       return sb.ToString(); 99     }100     public static String CheckboxTree(this HtmlHelper helper, string Name, IList<CheckboxTreeItem> Models)101     {102       if (null == Models) return string.Empty;103       if (Models.Count > 0)104         baselayer = true;105 106       StringBuilder sb = new StringBuilder();107       if (baselayer)108         sb.Append("<div class=\"CheckboxTree\">");109       sb.Append("<ul class=\"CBT-ul\">");110 111       string _this_HtmlDomName;112 113       foreach (CheckboxTreeItem item in Models)114       {115         sb.Append(CheckboxTree(helper, Name, item, out _this_HtmlDomName, true));116       }117 118       sb.Append("</ul>");119       if (baselayer)120         sb.Append("</div>");121 122       return sb.ToString();123     }124   }125 }

 

字段说明:
Text:用于显示的文本,比如:总裁
Value:显示文本对应的ID,比如:0
Index:这个是结合表单的辅助属性,View上使用(注意每个层级的索引必需从0开始并且是连续的)
Checked:当前菜单项是否被选中,用户提交表单后我们可以通过这个属性判断用户的选择项
Items:当前菜单下的子菜单集合

 

树形菜单的输出:

 1 @model List<CheckboxTreeItem> 2  3  4 @using (Html.BeginForm("test", "Home", new { }, FormMethod.Post, new { id = "form", name = "form" })) 5 { 6  @Html.AntiForgeryToken(); 7    8  <link type="text/css" rel="stylesheet" href="@Url.Content("~/Models/CheckboxTree.css")" /> 9  @Html.Raw(Html.CheckboxTree("CheckboxTree", Model))  @*这里是输出显示树形菜单*@10  <script src="@Url.Content("~/Models/CheckboxTree.js")" type="text/javascript"></script>11 }

 

       无论是ajax还是直接post表单,最终的目的都是接收View中的数据,要想传递比较复杂的数据类型,我们需要对ASP.NET MVC Model Binding 有一定了解,之前也讲解过MyTreeViewItem的结果,有普通的数据类型,比如 string,bool,也是对象类型,比如MyTreeViewItem类型的Parent,也是基于集合的属性IList<MyTreeViewItem>,要想让表单中的数据直接传递给Controller,我们需要对表单元素的name进行特殊处理才行。

 

Controller:这是最重要的就是接收参数,它是一个List类型,无论菜单项有多少层,都会按树形数据结构层次组织好,方便我们查询。

 1 public ActionResult test(int id = 0) 2 { 3   ViewBag.IsEdit = id == 0 ? false : true; 4  5   List<CheckboxTreeItem> cb = new List<CheckboxTreeItem>() { 6       new CheckboxTreeItem() { Value="A", Text="一级A", Index="0" }, 7       new CheckboxTreeItem() { Value="B", Text="一级B", Index="1" }, 8       new CheckboxTreeItem() { Value="C", Text="一级C", Index="2", Checked =true, 9       Items=new List<CheckboxTreeItem>() {10         new CheckboxTreeItem() { Value="CA", Text="二级CA", Index="0", Checked =true },11         new CheckboxTreeItem() { Value="CB", Text="二级CB", Index="1", Checked =true,12         Items=new List<CheckboxTreeItem>() {13           new CheckboxTreeItem() { Value="CBA", Text="三级CBA", Index="0", Checked =true },14           new CheckboxTreeItem() { Value="CBB", Text="三级CBB", Index="1", Checked =true },15           }16         },17       }18       },19   };20 21   return View(cb);22 }23 24 [HttpPost]25 [ValidateAntiForgeryToken]26 [ValidateInput(false)]27 public ActionResult test(List<CheckboxTreeItem> CheckboxTree, int id = 0)28 {29   ViewBag.IsEdit = id == 0 ? false : true;30 31   return View(CheckboxTree);32 }

下图是Controller接收到的参数:(运行调试,断点查看第27-31行代码)

 

另外还有自定义样式文件 CheckboxTree.css

 1 /* 2 author:熊学浩 3 time:2016年6月5日 4 description:树形菜单控件(有问题请致信:xiongzaiqiren@163.com),或者请参考【http://www.cnblogs.com/xiongzaiqiren/】 5 */ 6 /* CheckboxTree */ 7 .CheckboxTree { 8   width: 100%; 9   height: 100%;10   text-align: center;11   margin: 0 auto;12 }13 14 .CBT-ul {15   text-align: left;16   list-style-type: disc;17 }18 19   .CBT-ul .CBT-li {20     display: list-item;21     text-align: left;22     margin-left: 10px;23     font-size: 16px;24     line-height: 20px;25     word-wrap: break-word;26     word-break: nomal;27     list-style: inherit;28   }29 .CBT-li label {30   cursor: pointer;31 }32 .CBT-li label input[type="checkbox"] {33   width: 16px;34   height: 16px;35   padding: 0 5px 0 0;36 }37 38 .CBT-li span {39   40 }41 42   .CBT-li a:link, .CBT-li a:visited {43   }44 45   .CBT-li a:hover, .CBT-li a:active {46     color: #ffffff;47     background-color: #657386;48   }49 50   .CBT-li a.active {51     color: #ffffff;52     background-color: #657386;53   }54 55   .CBT-li a span {56     57   }

CheckboxTree.css

用于初始化和设置选择状态改变的自定义javascript文件 CheckboxTree.js

 1 /* 2 author:熊学浩 3 time:2016年6月5日 4 description:树形菜单控件(有问题请致信:xiongzaiqiren@163.com),或者请参考【http://www.cnblogs.com/xiongzaiqiren/】 5 */ 6 /* CheckboxTree */ 7 function setCheckboxTreeItemValue(dom) { 8   try { 9     if (!!dom)10       dom.value = (!!dom.checked)11   }12   catch (e) {13     console.log(e.message);14   }15 };16 function iniCheckboxTree() {17   try {18     var cbList = document.getElementsByTagName("input");19     if (!!cbList && cbList.length > 0) {20       for (var i = 0; i < cbList.length; i++) {21         if (!!cbList[i] && (cbList[i].type == "checkbox")) {22           if (!!cbList[i].value) {23             cbList[i].checked = (cbList[i].value.toLowerCase() == "true") || false;24           }25         }26       }27     }28   }29   catch (e) {30     console.log(e.message);31   }32 };33 34 if (!!window)35   window.onload = iniCheckboxTree();36 else37   iniCheckboxTree();

CheckboxTree.js

最后,UI效果图:

【完】