Рекурсия в представлении 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
Создайте собственный метод расширения 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;
}
}
}
Забавно, что вы должны спросить, потому что я фактически создал один из них только вчера.
Ответ 2
Вы можете легко сделать это, указав каждый <ul>
список в PartialView
, и для каждого нового списка вам нужно просто вызвать Html.RenderPartial("myPartialName");
.
Итак, PartialView Category
может выглядеть так:
<%@ 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>
<% } %>
В вашем представлении вы просто отправляете коллекцию "root" в качестве модели для частичного представления:
<% Html.RenderPartial("Category", ViewData.Model) %>
EDIT:
- Я забыл второй параметр для вызова
Html.RenderPartial()
- конечно, категория должна быть передана как модель.
- Конечно, вы правы в ошибке DRY, которую я сделал - я обновил свой код соответственно.
Ответ 3
Вы можете использовать вспомогательные методы.
@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
Ответ 4
Вы можете повторно использовать html-части с lambdas
Пример
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); %>