asp.net mvc中应用treeview

      最近我们的项目中需要用到树型菜单,以前使用WebForm时,树型菜单有微软提供的控件,非常方便,但现在需要在asp.netmvc中使用树形菜单,先说明下我们对树形菜单的需求:
      1:需要支持CheckBox,允许对菜单项进行选择;
      2:当选择父菜单时,它下面的子菜单全部选中;
      3:当取消父菜单的选中状态时,下面的子菜单也全部取消;
      4:要比较方便的与MVC结合。
     
      初步思路:
      思路一:jquery相关的树形菜单插件,由于项目中有应用到jquery,所以不考虑采用其它js框架的产品。
      思路二:asp.net mvc相应的控件,这里指的控制就好比分页控件之类,基本思路就是扩展HtmlHelper来实现,Html逻辑一般都封闭在dll中。
     
      经过一轮筛选后的结果:
     
      思路一:基于js的树形菜单果然有很多,最终我选择了https://github.com/daredevel/jquery-tree,从demo展示来看,它完全能够满足我上面提到的前三个需求。
      思路二:Telerik也有相应的树形菜单控件,它能够很好的结合MVC,最大特点是将View上的树形菜单数据传递给Controller很直观。
     
      最终方案:


      由于上面的两个产品不能完全符合我的要求,所以结合jquery-tree以及Telerik treeview设计理念来实现自己的树形菜单是最佳选择。
      jquery-tree本身只是一个基于前端的菜单,我们要想传递数据给Controller,唯一比较方便的方法就是通过ajax,但这需要开发人员有比较强的js操纵能力。
      Telerik treeview,有点杀鸡用牛刀的意思,Telerik提供了一整UI解决方案,如果我们只用其中的一个功能就引入它,有些不适时宜,但我非常喜欢它给出的思路,它能很好的将View的菜单数据传递给Controller,但Telerik由于提供的是控件,我们不太方便对它的样式做修改,我们更希望能够自由的控制UI显示逻辑。
     
       题外话:关于数据结构
       记的有一年,我去一家公司面试,当时估计是技术人员都不在,所以安排了一位年龄上比较大的面试官来面试我,目测应该是位级别不低的领导,当时不免有点小紧张。经过一番自我介绍以及工作经验介绍后,他现场给我出了一道题:
       写一个程序,打印出公司的组织结构图,比如最上层是CEO,下面是VP......
     
      我当时跟很大一部分.net程序员一样,做过几年项目后,什么数据结构啊,算法呀早就不记得了,那一刻只想到这是和树相关的数据结构,但不知为何,只想到了二叉树,心想总算想到了,于是开始定义二叉树数据结构,采用递归遍历数据,总之脑袋一片空白,写了一会,领导见我还没写完,有些不耐烦了,问我写完吗,我回答说还差一点,他等了一会见我还没写完,就说先给我看看,于时直接过来拿走我未写完的代码,我是多么的想争取那次机会呀,当时多么的舍不得交出去,最后的结果可想而知。
     
      并不是面试官问的问题有多么难,他考的问题只不过是计算机最基础的东西,而我正好忘记了。到现在我也面试过一些候选人,我也比较注意候选人的基础知识,其实说实在的,像做一些.net相关的企业级开发,大部分情况下我们是不会用到复杂数据结构的,算法就更不用说了,只有少数人会用到这些高级的东西。但这些数据结构以及算法知识会让你的视野更加开阔,在特定情况下能够给你一些方向,如果你对那块领域没有接触过,你是不会朝那方面想的。

      这次的树形菜单正好能够解答我以前那位面试官的问题。
     
      树形菜单数据结构:
      首先它属于树形数据结构,但不能定义成二叉树,因为一个总裁下面不可能只有两个副总,一个经理下面也不可能只有两个员工,下属应该是大于等于0的数据。
      下面是我定义的菜单数据对象:
  

public  class MyTreeViewItem
    {
         public IList<MyTreeViewItem> Items {  getset; }
         public  string Value {  getset; }
         public  bool Checked {  getset; }
         public  string Text {  getset; }
         public  string Index {  getset; }
         public MyTreeViewItem Parent {  getset; }
         public  string HtmlDomName {  getset; }
    }

     
       字段说明:
       Text:用于显示的文本,比如:总裁
       Value:显示文本对应的ID,比如:0
       Index:这个是结合表单的辅助属性,View上使用
       Checked:当前菜单项是否被选中,用户提交表单后我们可以通过这个属性判断用户的选择项
       Items:当前菜单下的子菜单集合
       Parent:当前菜单的上级菜单
       HtmlDomName:这个是结合表单的辅助属性,View上使用
      
       树形菜单的输出:
       我上次面试过程中的递归逻辑还是有用的,这里我们仍然采用递归来输出菜单项。我创建了一个Partial View

@model MvcTreeView.Controllers.MyTreeViewItem
<ul>
    <li>
        @if ( null == Model.Parent)
        {
            Model.HtmlDomName =  " TreeView1_checkedNodes[ " + Model.Index +  " ] ";
        }
         else
        {
            Model.HtmlDomName = Model.Parent.HtmlDomName +  " .Items[ " + Model.Index +  " ] ";
        }
        <input name= ' @(Model.HtmlDomName + ".Checked") ' type= " checkbox " οnchange= ' setValue(this) '  value= ' False ' />
        <input  name= ' @(Model.HtmlDomName + ".Text") ' type= " hidden " value= " @Model.Text " />
        <input  name= ' @(Model.HtmlDomName + ".Index") ' type= " hidden " value= " @Model.Index " />
        <span>@Model.Text</span>
        <input  name= ' @(Model.HtmlDomName + ".Value") ' type= " hidden "
                                        value= " @Model.Value " />
        @if ( null != Model.Items)
        {
             for ( var i =  0; i < Model.Items.Count; i++)
            {
            @Html.Partial( " NodeItem ", Model.Items[i])
            }
        }
    </li>
</ul>

   

       View向Controller的数据传递:

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

public  class AboutModel
    {
         public MyTreeViewItem NodeItem {  getset; }

    }



       View:这是主要是加载菜单,至于如何使用jquery-tree,这里就不多说了,大家下可以自己下载demo。 
    

@using (Html.BeginForm())
{
    <div id= " accordion ">
        <h3>
            <a href= " # ">All components  in  default behaviour</a></h3>
        <div id= " example-0 ">
            <div>
             @if ( null != Model.NodeItem)
            {
                @Html.Partial( " NodeItem ", Model.NodeItem)
            }
             
            </div>
        </div>
    </div>
    <input type= " submit " id= " example-0-button " />
}

  

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

[AcceptVerbs(HttpVerbs.Post)]
         public ActionResult About(List<MyTreeViewItem> TreeView1_checkedNodes)
        {
             return View( this.GetAboutModel());
        }

 
        UI效果图:下图也是我上次没有回答出来的面试题答案效果图。

        

 

        下图是Controller接收到的参数:

 

   


        
        
       

      

 

转载于:https://www.cnblogs.com/ASPNET2008/archive/2012/09/09/2677837.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值