ASP.Net MVC:如何使用递归技术显示嵌套的父子关系
ASP.Net MVC: How to show nested parent-child relation using recursive technique
我只是想使用递归函数调用在剃须刀中使用 ul
和 li
显示第 n 个关系。假设我有 db table 存储父子关系,如下所示。
table结构
+----+----------+----------+
| ID | Name | ParentID |
+----+----------+----------+
| 1 | Parent 1 | 0 |
+----+----------+----------+
| 2 | child 1 | 1 |
+----+----------+----------+
| 3 | child 2 | 1 |
+----+----------+----------+
| 4 | child 3 | 1 |
+----+----------+----------+
| 5 | Parent | 0 |
+----+----------+----------+
| 6 | child 4 | 4 |
+----+----------+----------+
所以我喜欢在剃刀视图中以这种方式显示嵌套数据
Parent 1
child 1
child 2
child 3
child 4
Parent
所以我尝试了这段代码但无法实现目标。
c#POCO类
public class MenuItem
{
public int Id { get; set; }
public string Name { get; set; }
public int ParentId { get; set; }
public virtual ICollection<MenuItem> Children { get; set; }
}
public class MenuDTO
{
public int Id { get; set; }
public string Name { get; set; }
public int ParentId { get; set; }
public virtual ICollection<MenuItem> Children { get; set; }
}
操作代码
public ActionResult Index()
{
List<MenuItem> allMenu = new List<MenuItem>
{
new MenuItem {Id=1,Name="Parent 1", ParentId=0},
new MenuItem {Id=2,Name="child 1", ParentId=1},
new MenuItem {Id=3,Name="child 2", ParentId=1},
new MenuItem {Id=4,Name="child 3", ParentId=1},
new MenuItem {Id=5,Name="Parent 2", ParentId=0},
new MenuItem {Id=6,Name="child 4", ParentId=4}
};
List<MenuDTO> mi = allMenu
.Select(e => new
{
Id = e.Id,
Name = e.Name,
ParentId = e.ParentId,
Children = allMenu.Where(x => x.ParentId == e.Id).ToList()
}).ToList()
.Select(p => new MenuDTO
{
Id = p.Id,
Name = p.Name,
ParentId = p.ParentId,
Children = p.Children
//Children = p.Children.Cast<MenuDTO>()
}).ToList();
ViewBag.menusList = mi;
return View();
}
剃须刀代码
@{
var menuList = ViewBag.menusList as List<Scaffolding.Controllers.MenuDTO>;
ShowTree(menuList);
}
@helper ShowTree(List<Scaffolding.Controllers.MenuDTO> menusList)
{
if (menusList != null)
{
foreach (var item in menusList)
{
<li>
<span>@item.Name</span>
@if (item.Children.Any())
{
<ul>
@ShowTree(item.Children)
</ul>
}
</li>
}
}
}
在我的例子中,我查询 List allMenu 以获取数据而不是从 db table。当我 运行 我的代码然后我得到低于错误
CS1502: The best overloaded method match for
'ASP._Page_Views_Menu_Index_cshtml.ShowTree(System.Collections.Generic.List)'
has some invalid arguments
告诉我我的代码有什么问题。请帮助我确定并实现我的目标。谢谢
编辑
完整的工作代码如下
@helper ShowTree(List<Scaffolding.Controllers.MenuItem> menusList)
{
<ul>
@foreach (var item in menusList)
{
<li>
<span>@item.Name</span>
@if (item.Children!=null && item.Children.Any())
{
@ShowTree(item.Children)
}
</li>
}
</ul>
}
@{
var menuList = ViewBag.menusList as List<Scaffolding.Controllers.MenuItem>;
@ShowTree(menuList);
}
public ActionResult Index()
{
List<MenuItem> allMenu = new List<MenuItem>
{
new MenuItem {Id=1,Name="Parent 1", ParentId=0},
new MenuItem {Id=2,Name="child 1", ParentId=1},
new MenuItem {Id=3,Name="child 2", ParentId=1},
new MenuItem {Id=4,Name="child 3", ParentId=1},
new MenuItem {Id=5,Name="Parent 2", ParentId=0},
new MenuItem {Id=6,Name="child 4", ParentId=4}
};
List<MenuItem> mi = allMenu
.Where(e => e.ParentId == 0) /* grab only the root parent nodes */
.Select(e => new MenuItem
{
Id = e.Id,
Name = e.Name,
ParentId = e.ParentId,
Children = allMenu.Where(x => x.ParentId == e.Id) /* grab second level children */
.Select(e2 => new MenuItem
{
Id = e2.Id,
Name = e2.Name,
ParentId = e2.ParentId,
Children = allMenu.Where(x2 => x2.ParentId == e2.Id).ToList() /* grab third level children */
}).ToList()
}).ToList();
ViewBag.menusList = mi;
return View();
}
public class MenuItem
{
public int Id { get; set; }
public string Name { get; set; }
public int ParentId { get; set; }
public virtual List<MenuItem> Children { get; set; }
}
您的代码在执行第
行时找不到采用 ICollection<MenuItem>
类型参数的函数 ShowTree
@ShowTree(item.Children)
因为 item.Children 的类型是 ICollection<MenuItem>
。您代码中的 ShowTree 函数采用不同类型的参数 List<MenuDTO>
,这与 ICollection<MenuItem>
不同。结果,运行时报告您看到的 CS1502 错误。
在意识到您正在寻找递归解决方案后,我修改了代码来实现这一点。
操作代码
public ActionResult Index()
{
List<MenuItem> allMenu = new List<MenuItem>
{
new MenuItem {Id=1,Name="Parent 1", ParentId=0},
new MenuItem {Id=2,Name="child 1", ParentId=1},
new MenuItem {Id=3,Name="child 2", ParentId=1},
new MenuItem {Id=4,Name="child 3", ParentId=1},
new MenuItem {Id=5,Name="Parent 2", ParentId=0},
new MenuItem {Id=6,Name="child 4", ParentId=4}
};
List<MenuItem> mi = allMenu
.Where(e => e.ParentId == 0) /* grab only the root parent nodes */
.Select(e => new MenuItem
{
Id = e.Id,
Name = e.Name,
ParentId = e.ParentId,
Children = GetChildren(allMenu, e.Id) /* Recursively grab the children */
}).ToList();
ViewBag.menusList = mi;
return View();
}
/// <summary>
/// Recursively grabs the children from the list of items for the provided parentId
/// </summary>
/// <param name="items">List of all items</param>
/// <param name="parentId">Id of parent item</param>
/// <returns>List of children of parentId</returns>
private static List<MenuItem> GetChildren(List<MenuItem> items, int parentId)
{
return items
.Where(x => x.ParentId == parentId)
.Select(e => new MenuItem
{
Id = e.Id,
Name = e.Name,
ParentId = e.ParentId,
Children = GetChildren(items, e.Id)
}).ToList();
}
Razor 代码
@{
var menuList = ViewBag.menusList as List<Scaffolding.Controllers.MenuItem>;
@ShowTree(menuList);
}
@helper ShowTree(List<Scaffolding.Controllers.MenuItem> menusList)
{
if (menusList != null)
{
foreach (var item in menusList)
{
<li>
<span>@item.Name</span>
@if (item.Children.Any())
{
<ul>
@ShowTree(item.Children)
</ul>
}
</li>
}
}
}
我用这种方法修复并完成了工作
问题出在剃刀代码的逻辑上,我也评论了这一行 //.Where(e => e.ParentId == 0)
在这里我添加了工作代码。
工作代码示例
@helper ShowTree(List<NestedChild.Controllers.MenuItem> menu, int? parentid = 0, int level = 0)
{
var items = menu.Where(m => m.ParentId == parentid);
if (items.Any())
{
if (items.First().ParentId > 0)
{
level++;
}
<ul>
@foreach (var item in items)
{
<li>
@item.Name
</li>
@ShowTree(menu, item.Id, level);
}
</ul>
}
}
@{
var menuList = ViewBag.menusList as List<NestedChild.Controllers.MenuItem>;
@ShowTree(menuList);
}
public ActionResult Index()
{
List<MenuItem> allMenu = new List<MenuItem>
{
new MenuItem {Id=1,Name="Parent 1", ParentId=0},
new MenuItem {Id=2,Name="child 1", ParentId=1},
new MenuItem {Id=3,Name="child 2", ParentId=1},
new MenuItem {Id=4,Name="child 3", ParentId=1},
new MenuItem {Id=5,Name="Parent 2", ParentId=0},
new MenuItem {Id=6,Name="child 4", ParentId=4}
};
List<MenuItem> mi = allMenu
//.Where(e => e.ParentId == 0) /* grab only the root parent nodes */
.Select(e => new MenuItem
{
Id = e.Id,
Name = e.Name,
ParentId = e.ParentId,
//Children = allMenu.Where(x => x.ParentId == e.Id).ToList()
}).ToList();
ViewBag.menusList = mi;
return View();
}
我只是想使用递归函数调用在剃须刀中使用 ul
和 li
显示第 n 个关系。假设我有 db table 存储父子关系,如下所示。
table结构
+----+----------+----------+
| ID | Name | ParentID |
+----+----------+----------+
| 1 | Parent 1 | 0 |
+----+----------+----------+
| 2 | child 1 | 1 |
+----+----------+----------+
| 3 | child 2 | 1 |
+----+----------+----------+
| 4 | child 3 | 1 |
+----+----------+----------+
| 5 | Parent | 0 |
+----+----------+----------+
| 6 | child 4 | 4 |
+----+----------+----------+
所以我喜欢在剃刀视图中以这种方式显示嵌套数据
Parent 1
child 1
child 2
child 3
child 4
Parent
所以我尝试了这段代码但无法实现目标。
c#POCO类
public class MenuItem
{
public int Id { get; set; }
public string Name { get; set; }
public int ParentId { get; set; }
public virtual ICollection<MenuItem> Children { get; set; }
}
public class MenuDTO
{
public int Id { get; set; }
public string Name { get; set; }
public int ParentId { get; set; }
public virtual ICollection<MenuItem> Children { get; set; }
}
操作代码
public ActionResult Index()
{
List<MenuItem> allMenu = new List<MenuItem>
{
new MenuItem {Id=1,Name="Parent 1", ParentId=0},
new MenuItem {Id=2,Name="child 1", ParentId=1},
new MenuItem {Id=3,Name="child 2", ParentId=1},
new MenuItem {Id=4,Name="child 3", ParentId=1},
new MenuItem {Id=5,Name="Parent 2", ParentId=0},
new MenuItem {Id=6,Name="child 4", ParentId=4}
};
List<MenuDTO> mi = allMenu
.Select(e => new
{
Id = e.Id,
Name = e.Name,
ParentId = e.ParentId,
Children = allMenu.Where(x => x.ParentId == e.Id).ToList()
}).ToList()
.Select(p => new MenuDTO
{
Id = p.Id,
Name = p.Name,
ParentId = p.ParentId,
Children = p.Children
//Children = p.Children.Cast<MenuDTO>()
}).ToList();
ViewBag.menusList = mi;
return View();
}
剃须刀代码
@{
var menuList = ViewBag.menusList as List<Scaffolding.Controllers.MenuDTO>;
ShowTree(menuList);
}
@helper ShowTree(List<Scaffolding.Controllers.MenuDTO> menusList)
{
if (menusList != null)
{
foreach (var item in menusList)
{
<li>
<span>@item.Name</span>
@if (item.Children.Any())
{
<ul>
@ShowTree(item.Children)
</ul>
}
</li>
}
}
}
在我的例子中,我查询 List allMenu 以获取数据而不是从 db table。当我 运行 我的代码然后我得到低于错误
CS1502: The best overloaded method match for 'ASP._Page_Views_Menu_Index_cshtml.ShowTree(System.Collections.Generic.List)' has some invalid arguments
告诉我我的代码有什么问题。请帮助我确定并实现我的目标。谢谢
编辑
完整的工作代码如下
@helper ShowTree(List<Scaffolding.Controllers.MenuItem> menusList)
{
<ul>
@foreach (var item in menusList)
{
<li>
<span>@item.Name</span>
@if (item.Children!=null && item.Children.Any())
{
@ShowTree(item.Children)
}
</li>
}
</ul>
}
@{
var menuList = ViewBag.menusList as List<Scaffolding.Controllers.MenuItem>;
@ShowTree(menuList);
}
public ActionResult Index()
{
List<MenuItem> allMenu = new List<MenuItem>
{
new MenuItem {Id=1,Name="Parent 1", ParentId=0},
new MenuItem {Id=2,Name="child 1", ParentId=1},
new MenuItem {Id=3,Name="child 2", ParentId=1},
new MenuItem {Id=4,Name="child 3", ParentId=1},
new MenuItem {Id=5,Name="Parent 2", ParentId=0},
new MenuItem {Id=6,Name="child 4", ParentId=4}
};
List<MenuItem> mi = allMenu
.Where(e => e.ParentId == 0) /* grab only the root parent nodes */
.Select(e => new MenuItem
{
Id = e.Id,
Name = e.Name,
ParentId = e.ParentId,
Children = allMenu.Where(x => x.ParentId == e.Id) /* grab second level children */
.Select(e2 => new MenuItem
{
Id = e2.Id,
Name = e2.Name,
ParentId = e2.ParentId,
Children = allMenu.Where(x2 => x2.ParentId == e2.Id).ToList() /* grab third level children */
}).ToList()
}).ToList();
ViewBag.menusList = mi;
return View();
}
public class MenuItem
{
public int Id { get; set; }
public string Name { get; set; }
public int ParentId { get; set; }
public virtual List<MenuItem> Children { get; set; }
}
您的代码在执行第
行时找不到采用ICollection<MenuItem>
类型参数的函数 ShowTree
@ShowTree(item.Children)
因为 item.Children 的类型是 ICollection<MenuItem>
。您代码中的 ShowTree 函数采用不同类型的参数 List<MenuDTO>
,这与 ICollection<MenuItem>
不同。结果,运行时报告您看到的 CS1502 错误。
在意识到您正在寻找递归解决方案后,我修改了代码来实现这一点。
操作代码
public ActionResult Index()
{
List<MenuItem> allMenu = new List<MenuItem>
{
new MenuItem {Id=1,Name="Parent 1", ParentId=0},
new MenuItem {Id=2,Name="child 1", ParentId=1},
new MenuItem {Id=3,Name="child 2", ParentId=1},
new MenuItem {Id=4,Name="child 3", ParentId=1},
new MenuItem {Id=5,Name="Parent 2", ParentId=0},
new MenuItem {Id=6,Name="child 4", ParentId=4}
};
List<MenuItem> mi = allMenu
.Where(e => e.ParentId == 0) /* grab only the root parent nodes */
.Select(e => new MenuItem
{
Id = e.Id,
Name = e.Name,
ParentId = e.ParentId,
Children = GetChildren(allMenu, e.Id) /* Recursively grab the children */
}).ToList();
ViewBag.menusList = mi;
return View();
}
/// <summary>
/// Recursively grabs the children from the list of items for the provided parentId
/// </summary>
/// <param name="items">List of all items</param>
/// <param name="parentId">Id of parent item</param>
/// <returns>List of children of parentId</returns>
private static List<MenuItem> GetChildren(List<MenuItem> items, int parentId)
{
return items
.Where(x => x.ParentId == parentId)
.Select(e => new MenuItem
{
Id = e.Id,
Name = e.Name,
ParentId = e.ParentId,
Children = GetChildren(items, e.Id)
}).ToList();
}
Razor 代码
@{
var menuList = ViewBag.menusList as List<Scaffolding.Controllers.MenuItem>;
@ShowTree(menuList);
}
@helper ShowTree(List<Scaffolding.Controllers.MenuItem> menusList)
{
if (menusList != null)
{
foreach (var item in menusList)
{
<li>
<span>@item.Name</span>
@if (item.Children.Any())
{
<ul>
@ShowTree(item.Children)
</ul>
}
</li>
}
}
}
我用这种方法修复并完成了工作
问题出在剃刀代码的逻辑上,我也评论了这一行 //.Where(e => e.ParentId == 0)
在这里我添加了工作代码。
工作代码示例
@helper ShowTree(List<NestedChild.Controllers.MenuItem> menu, int? parentid = 0, int level = 0)
{
var items = menu.Where(m => m.ParentId == parentid);
if (items.Any())
{
if (items.First().ParentId > 0)
{
level++;
}
<ul>
@foreach (var item in items)
{
<li>
@item.Name
</li>
@ShowTree(menu, item.Id, level);
}
</ul>
}
}
@{
var menuList = ViewBag.menusList as List<NestedChild.Controllers.MenuItem>;
@ShowTree(menuList);
}
public ActionResult Index()
{
List<MenuItem> allMenu = new List<MenuItem>
{
new MenuItem {Id=1,Name="Parent 1", ParentId=0},
new MenuItem {Id=2,Name="child 1", ParentId=1},
new MenuItem {Id=3,Name="child 2", ParentId=1},
new MenuItem {Id=4,Name="child 3", ParentId=1},
new MenuItem {Id=5,Name="Parent 2", ParentId=0},
new MenuItem {Id=6,Name="child 4", ParentId=4}
};
List<MenuItem> mi = allMenu
//.Where(e => e.ParentId == 0) /* grab only the root parent nodes */
.Select(e => new MenuItem
{
Id = e.Id,
Name = e.Name,
ParentId = e.ParentId,
//Children = allMenu.Where(x => x.ParentId == e.Id).ToList()
}).ToList();
ViewBag.menusList = mi;
return View();
}