2009-06-02 46 views
23

我有一个嵌套的数据对象的类别内的一组项目。每个类别都可以包含子类别,并且对子类别的深度没有限制。 (文件系统将具有类似的结构。)它看起来是这样的:ASP.NET MVC视图中的递归

class category 
{ 
    public int id; 
    public string name; 
    public IQueryable<category> categories; 
    public IQueryable<item> items; 
} 
class item 
{ 
    public int id; 
    public string name; 
} 

我传递的类别列表,以我的观点为IQueryable<category>。我想输出这些类别作为一组嵌套的无序列表(<ul>)块。我可以嵌套foreach循环,但随后子类别的深度将受到嵌套的foreach块的数量的限制。在WinForms中,我使用递归来完成类似的处理来填充TreeView,但我还没有看到在ASPX MVC视图中使用递归的任何示例。

递归可以在ASPX视图中完成吗?是否有其他视图引擎包含视图输出的递归?

+1

当我写这个问题,我不认为我的理解IQueryable`和`IEnumerable`之间`的区别。我现在使用`IEnumerable`,因为视图没有做任何查询,只应该枚举数据。 – CoderDennis 2014-07-10 21:13:57

回答

33

像这样创建您自己的HtmlHelper扩展方法:

namespace System.Web.Mvc 
{ 
    public static class HtmlHelperExtensions 
    { 
     public static string CategoryTree(this HtmlHelper html, IEnumerable<Category> categories) 
     { 
      string htmlOutput = string.Empty; 

      if (categories.Count() > 0) 
      { 
       htmlOutput += "<ul>"; 
       foreach (Category category in Categories) 
       { 
        htmlOutput += "<li>"; 
        htmlOutput += category.Name; 
        htmlOutput += html.CategoryTree(category.Categories); 
        htmlOutput += "</li>"; 
       } 
       htmlOutput += "</ul>"; 
      } 

      return htmlOutput; 
     } 
    } 
} 

滑稽,你应该问,因为我实际创建其中之一就在昨天。

+0

我喜欢这段代码。看起来奇怪的是编写这样一个专门的帮助函数,但是这会比Tomas的回答中的递归部分视图执行得更好吗? – CoderDennis 2009-06-04 00:33:07

+1

我99%肯定这里的表现会更好。 'RenderPartial'有一些开销,作为一个简单的辅助方法,你可以拥有尽可能少的开销。 – Charlino 2009-06-04 04:33:29

25

你可以很容易地通过在PartialView让每个<ul>名单做,并为每个新的列表,你需要开始你只需要调用Html.RenderPartial("myPartialName");

所以Category PartialView看起来是这样的:

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<IEnumerable<Category>>" %> 
<% foreach(Category cat in ViewData.Model) { %> 
    <li><p><%= cat.name %></p> 
     <% if (cat.categories.Count > 0) { 
       Html.RenderPartial("Category", cat.Categories); 
      } %></li> 
<% } %> 

在您看来,您只需发送 “根” 集合作为模型的局部视图:

<% Html.RenderPartial("Category", ViewData.Model) %> 

编辑:

  • 我忘记了Html.RenderPartial()调用的第二个参数 - 当然是类别h作为模型通过。
  • 当然,你对我所犯的DRY错误是正确的 - 我已经相应地更新了我的代码。
+0

在局部视图中,它如何将cat.categories设置为子类别局部视图的模型? – CoderDennis 2009-06-04 00:01:47

+0

RenderPartial方法可以将第二个参数用作模型。就我个人而言,我不会在你的页面上做循环,只是将它传递给你的类别集合并开始循环 - 这种方式更加干燥。 – Charlino 2009-06-04 04:36:04

6

您可以重复使用lambda表达式


public class Category 
    { 
     public int id; 
     public string name; 
     public IEnumerable categories; 
    } 
<% 
     Action<IEnumerable<Category>> categoriesMacros = null; 
     categoriesMacros = categories => { %> 
     <ul> 
      <% foreach(var c in categories) { %> 
       <li> <%= Html.Encode(c.name)%> </li> 
       <% if (c.categories != null && c.categories.Count() > 0) categoriesMacros(c.categories); %> 
      <% } %> 
     </ul> 
     <% }; %> 

    <% var categpries = (IEnumerable<Category>)ViewData["categories"]; %> 
    <% categoriesMacros(categpries); %> 
18

您可以使用辅助方法HTML部分。

@model Models.CategoryModel 

@helper TreeView(List<Models.CategoryModel> categoryTree) 
{ 
    foreach (var item in categoryTree) 
    { 
    <li> 
     @if (item.HasChild) 
     { 
      <span>@item.CategoryName</span> 
      <ul> 
       @TreeView(item.ChildCategories) 
      </ul> 
     } 
     else 
     { 
      <span class="leaf @item.CategoryTreeNodeType.ToString()" id="@item._CategoryId">@item.CategoryName</span> 
     } 
    </li> 
    } 
} 

<ul id="categorytree"> 
    <li>@Model.CategoryName 
    @TreeView(Model.ChildCategories) 
    </li> 
</ul> 

更多信息可以在此链接上找到: http://weblogs.asp.net/scottgu/archive/2011/05/12/asp-net-mvc-3-and-the-helper-syntax-within-razor.aspx