Recursividad en una vista ASP.NET MVC
asp.net-mvc recursion (4)
Cree su propio método de extensión HtmlHelper así:
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;
}
}
}
Es curioso que lo preguntes porque en realidad creé uno de estos ayer.
Tengo un objeto de datos anidados para un conjunto de elementos dentro de las categorías. Cada categoría puede contener subcategorías y no hay un límite establecido para la profundidad de las subcategorías. (Un sistema de archivos tendría una estructura similar.) Se ve más o menos así:
class category
{
public int id;
public string name;
public IQueryable<category> categories;
public IQueryable<item> items;
}
class item
{
public int id;
public string name;
}
Estoy pasando una lista de categorías a mi vista como IQueryable<category>
. Quiero mostrar las categorías como un conjunto de bloques anidados de listas desordenadas ( <ul>
). Podría anidar bucles foreach, pero la profundidad de las subcategorías estaría limitada por la cantidad de bloques foreach anidados. En WinForms, he realizado un proceso similar utilizando la recursividad para llenar un TreeView
, pero no he visto ningún ejemplo de uso de recursividad dentro de una vista ASPX MVC.
¿Puede la recursión hacerse dentro de una vista ASPX? ¿Hay otros motores de vista que incluyan recursividad para la salida de vista?
Puede hacerlo fácilmente haciendo que cada lista <ul>
PartialView
en una vista PartialView
, y para cada nueva lista que necesita para comenzar, simplemente llame a Html.RenderPartial("myPartialName");
.
Entonces la Category
PartialView podría verse así:
<%@ 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>
<% } %>
En su Vista, simplemente envíe la colección "raíz" como modelo para la vista parcial:
<% Html.RenderPartial("Category", ViewData.Model) %>
EDITAR:
- Había olvidado el segundo parámetro de la llamada
Html.RenderPartial()
; por supuesto, la categoría debe pasarse como modelo. - Por supuesto, tienes razón sobre el error SECO que cometí, he actualizado mi código en consecuencia.
Puedes reutilizar partes html con lambdas
Ejemplo
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); %>
Puedes usar métodos de ayuda.
@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>
Puede encontrar más información en este enlace: http://weblogs.asp.net/scottgu/archive/2011/05/12/asp-net-mvc-3-and-the-helper-syntax-within-razor.aspx