zoukankan      html  css  js  c++  java
  • 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" onchange='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接收到的参数:

       


            
            
           

          

  • 相关阅读:
    API测试之Postman使用完全指南(Postman教程,这篇文章就够了)
    asp.net的webservice
    表和索引的结构(笔记)
    基于Nginx+PHP+Redis的短URL系统的实现 新风宇宙
    数据结构与算法(php版) 新风宇宙
    discuz7.2 昵称替换用户名 新风宇宙
    gVim7.3(Vim7.3)文本编辑器详细配置文件和配色方案 新风宇宙
    Discuz的Memcache缓存实现 新风宇宙
    GitHub使用(二) 从代码库下载代码到本地 新风宇宙
    PHPredis中文文档 新风宇宙
  • 原文地址:https://www.cnblogs.com/ASPNET2008/p/2677837.html
Copyright © 2011-2022 走看看