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接收到的參數:

 

   


        
        
       

      

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM