问题
I want to create a recursive menu with recursive elements. My first approach was to use Partial Views in order to re-use code.. Alas, when I run the code, it throws a "System.InvalidOperationException" "Stack empty" error.
I am mapping data from a web service with AutoMapper, which results in the following entity:
public interface INavigationItemContract
{
int Id { get; set; }
string Title { get; set; }
int ParentId { get; set; }
string Url { get; set; }
bool DisplayInMenu { get; set; }
decimal SortOrder { get; set; }
IEnumerable<IPageBaseContract> Pages { get; set; }
IEnumerable<INavigationItemContract> Sites { get; set; }
}
The partial view to initialize the menu (_Menu.cshtml):
@model IEnumerable<INavigationItemContract>
<div class="navbar navbar-default" role="navigation">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
</div>
<div class="navbar-collapse collapse">
<ul class="nav navbar-nav">
<li><a href="/">Home</a></li>
@foreach (var navigationItem in Model)
{
@Html.Partial("_MenuItem", navigationItem);
}
</ul>
</div>
</div>
The partial to display the menu item (_MenuItem.cshtml):
@model INavigationItemContract
@if (Model.Pages != null && Model.Pages.Any())
{
if (Model.Pages.Count() == 1 || !Model.DisplayInMenu)
{
// Only one page, so this will be the default.
// Other option is that the pages should not be displayed, so then we'll only display the link to the site.
<li><a href="@Model.Url">@Model.Title</a></li>
}
else
{
<li>
<a href="#">@Model.Title</a>
<ul class="dropdown-menu">
@foreach (var page in Model.Pages)
{
<li><a href="@page.RelativeUrl">@page.Title</a></li>
}
@foreach (var site in Model.Sites)
{
@Html.Partial("_MenuItem", site)
}
</ul>
</li>
}
}
When replacing the
@Html.Partial("_MenuItem", site)
with
<li>@site.Title</li>
everything works like a charm (except for the fact that it is not the desired result).
I have tried the following approaches as well:
- Create a DisplayTemplate
- Use Html.RenderPartial instead of Html.Partial
The exception occurs in the _MenuItem.cshtml:
@Html.Partial("_MenuItem", site)
It does not occur the first time the partial is called (in the _Menu.cshtml), only in the _MenuItem.cshtml itself, when it is calling itself.
Why am I getting this exception? And what might be the solution?
回答1:
I have found a workaround. The exception still puzzles me, but I can continue to render the menu (even though I do not have the ability to set a breakpoint on the helper code)..
@model IEnumerable
@helper RecursiveMenuItem(INavigationItemContract menuItem)
{
if (menuItem.Pages != null && menuItem.Pages.Any())
{
if (menuItem.Pages.Count() == 1 || !menuItem.DisplayInMenu)
{
// Only one page, so this will be the default.
// Other option is that the pages should not be displayed, so then we'll only display the link to the site.
<li><a href="@menuItem.Url">@menuItem.Title</a></li>
}
else
{
<li>
<a href="#">@menuItem.Title</a>
<ul class="dropdown-menu">
@foreach (var page in menuItem.Pages)
{
<li><a href="@page.Url">@page.Title</a></li>
}
@foreach (var site in menuItem.Sites)
{
@RecursiveMenuItem(site)
}
</ul>
</li>
}
}
}
<div role="navigation">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
</div>
<div class="navbar-collapse collapse">
<ul class="nav navbar-nav">
<li><a href="">Home</a></li>
@foreach (var menuItem in Model)
{
@RecursiveMenuItem(menuItem)
}
</ul>
</div>
</div>
回答2:
Not sure, but shouldn't you explicit the enumeration to use in the model by replacing :
@foreach (var navigationItem in Model)
by
@foreach (var navigationItem in Model.Sites)
for instance ?
来源:https://stackoverflow.com/questions/24280534/using-recursive-partial-view-in-mvc-raises-stack-empty-invalidoperationexception