Umbraco 动态 "Where" 过滤器 returns IQueryable 或 DynamicPublishedContentList 不一致
Umbraco dynamic "Where" filter returns either IQueryable or DynamicPublishedContentList inconsistently
我正在尝试使用递归助手在 Umbraco 中创建一个多级下拉菜单,但出于某种原因,我收到一个编译错误,提示我在传递根的 children 时传递了错误的参数帮助程序的元素。
我找到了一些解决方案,但他们没有使用助手,所以我不知道问题出在助手上还是我做错了什么。
我的代码是:
@inherits Umbraco.Web.Mvc.UmbracoTemplatePage
@{ var selection = CurrentPage.Site().Children.Where("Visible"); }
<div class="fleft menu_area">
<button class="btn btn-primary visible-xs" type="button" data- toggle="collapse" data-target="#mainMenu" aria-expanded="false" aria- controls="mainMenu"> <i class="glyphicon glyphicon-th-large"></i> Menu </button>
<div class="collapse navbar-collapse" id="mainMenu">
<ul class="nav navbar-nav">
@CreateListItems(selection)
</ul>
</div>
</div>
@helper CreateListItems(Umbraco.Web.Models.DynamicPublishedContentList collection)
{
foreach (var item in collection)
{
if (item.Children.Where("Visible").Count() > 0)
{
<li class="menuOption dropdown @(item.IsAncestorOrSelf(CurrentPage) ? "current" : null)" data-menu- id="@item.GetPropertyValue("menuOptionIdentifier")">
<a class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false" href="@item.Url">@item.Name</a>
<ul class="dropdown-menu">
@{
CreateListItems(item.Children.Where("Visible")); // THE PROBLEM IS HERE
}
</ul>
</li>
}
else
{
<li class="@(item.IsAncestorOrSelf(CurrentPage) ? "current" : null)"><a href="@item.Url">@item.Name</a></li>
}
}
}
我看到 item.Children.Where("Visible")
正在返回一个 iQueryable,所以我尝试将它分配给一个变量,并且该变量是正确的 DynamicPublishedContentList 类型。我将该变量传递给了助手,但我得到了同样的错误。
我尝试了另一个版本,在助手之外使用 foreachs,而不是传递 DynamicPublishedContentList 我传递了 DynamicPublishedContent 项目,但我也无法使其工作,我遇到了同样的错误。
我尝试将 Where 结果转换为列表,但我也收到错误消息,指出无法从 IQueryable does not contain a definition for 'ToList'
传递那些 children 的正确方法是什么?
有什么想法吗?
你是对的。问题是您正试图将 IQueryable
传递给 DynamicPublishedContentList
。我只是将其全部切换为动态,因此您不必特别担心传递的内容。如果你打算使用动态,你最好避免处理所有的类型转换。
您从对 Where("Visible")
的调用中收到混合消息的原因是 dynamic
不仅仅是常规类型。它基本上标记编译器跳过所有类型检查,所以它发生在运行时。这意味着在运行时,您的动态将编译为对象。
事实证明,当您从显式 DynamicPublishedContentList
调用 .Where("Visible")
时,会调用 Umbraco.Web.PublishedContentExtensions
中的 .Where("Visible")
方法。但是,扩展方法不适用于动态,因为 C# RuntimeBinder 不允许您访问扩展方法。当我们在 CurrentPage.Site().Children
上调用 .Where("Visible")
时,它看不到扩展方法,并且会调用 DynamicPublishedContentList
class 上覆盖的 TryInvokeMember
方法。
这可能是您最简单的解决方案:
@helper CreateListItems(Umbraco.Web.Models.DynamicPublishedContentList collection)
至
@helper CreateListItems(dynamic collection)
或者,您可以使用更强类型的 IPublishedContent。我喜欢这个,因为额外的智能感知有很大帮助。
@inherits Umbraco.Web.Mvc.UmbracoTemplatePage
@{
var root = Model.Content.AncestorOrSelf(1);
var selection = root.Children.Where(n => !n.GetPropertyValue<bool>("umbracoNaviHide")).ToList();
}
<div class="fleft menu_area">
<button class="btn btn-primary visible-xs" type="button" data- toggle="collapse" data-target="#mainMenu" aria-expanded="false" aria- controls="mainMenu"> <i class="glyphicon glyphicon-th-large"></i> Menu </button>
<div class="collapse navbar-collapse" id="mainMenu">
<ul class="nav navbar-nav">
@CreateListItems(selection)
</ul>
</div>
</div>
@helper CreateListItems(List<IPublishedContent> collection)
{
foreach (var item in collection)
{
if (item.Children.Any(n => !n.GetPropertyValue<bool>("umbracoNaviHide")))
{
<li class="menuOption dropdown @(item.IsAncestorOrSelf(Model.Content) ? "current" : null)" data-menu- id="@item.GetPropertyValue("menuOptionIdentifier")">
<a class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false" href="@item.Url">@item.Name</a>
<ul class="dropdown-menu">
@CreateListItems(item.Children.Where(n => !n.GetPropertyValue<bool>("umbracoNaviHide")).ToList())
</ul>
</li>
}
else
{
<li class="@(item.IsAncestorOrSelf(Model.Content) ? "current" : null)"><a href="@item.Url">@item.Name</a></li>
}
}
}
您可以使用 Model.Content
.
获取当前页面作为 IPublishedContent
我正在尝试使用递归助手在 Umbraco 中创建一个多级下拉菜单,但出于某种原因,我收到一个编译错误,提示我在传递根的 children 时传递了错误的参数帮助程序的元素。
我找到了一些解决方案,但他们没有使用助手,所以我不知道问题出在助手上还是我做错了什么。
我的代码是:
@inherits Umbraco.Web.Mvc.UmbracoTemplatePage
@{ var selection = CurrentPage.Site().Children.Where("Visible"); }
<div class="fleft menu_area">
<button class="btn btn-primary visible-xs" type="button" data- toggle="collapse" data-target="#mainMenu" aria-expanded="false" aria- controls="mainMenu"> <i class="glyphicon glyphicon-th-large"></i> Menu </button>
<div class="collapse navbar-collapse" id="mainMenu">
<ul class="nav navbar-nav">
@CreateListItems(selection)
</ul>
</div>
</div>
@helper CreateListItems(Umbraco.Web.Models.DynamicPublishedContentList collection)
{
foreach (var item in collection)
{
if (item.Children.Where("Visible").Count() > 0)
{
<li class="menuOption dropdown @(item.IsAncestorOrSelf(CurrentPage) ? "current" : null)" data-menu- id="@item.GetPropertyValue("menuOptionIdentifier")">
<a class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false" href="@item.Url">@item.Name</a>
<ul class="dropdown-menu">
@{
CreateListItems(item.Children.Where("Visible")); // THE PROBLEM IS HERE
}
</ul>
</li>
}
else
{
<li class="@(item.IsAncestorOrSelf(CurrentPage) ? "current" : null)"><a href="@item.Url">@item.Name</a></li>
}
}
}
我看到 item.Children.Where("Visible")
正在返回一个 iQueryable,所以我尝试将它分配给一个变量,并且该变量是正确的 DynamicPublishedContentList 类型。我将该变量传递给了助手,但我得到了同样的错误。
我尝试了另一个版本,在助手之外使用 foreachs,而不是传递 DynamicPublishedContentList 我传递了 DynamicPublishedContent 项目,但我也无法使其工作,我遇到了同样的错误。
我尝试将 Where 结果转换为列表,但我也收到错误消息,指出无法从 IQueryable does not contain a definition for 'ToList'
传递那些 children 的正确方法是什么?
有什么想法吗?
你是对的。问题是您正试图将 IQueryable
传递给 DynamicPublishedContentList
。我只是将其全部切换为动态,因此您不必特别担心传递的内容。如果你打算使用动态,你最好避免处理所有的类型转换。
您从对 Where("Visible")
的调用中收到混合消息的原因是 dynamic
不仅仅是常规类型。它基本上标记编译器跳过所有类型检查,所以它发生在运行时。这意味着在运行时,您的动态将编译为对象。
事实证明,当您从显式 DynamicPublishedContentList
调用 .Where("Visible")
时,会调用 Umbraco.Web.PublishedContentExtensions
中的 .Where("Visible")
方法。但是,扩展方法不适用于动态,因为 C# RuntimeBinder 不允许您访问扩展方法。当我们在 CurrentPage.Site().Children
上调用 .Where("Visible")
时,它看不到扩展方法,并且会调用 DynamicPublishedContentList
class 上覆盖的 TryInvokeMember
方法。
这可能是您最简单的解决方案:
@helper CreateListItems(Umbraco.Web.Models.DynamicPublishedContentList collection)
至
@helper CreateListItems(dynamic collection)
或者,您可以使用更强类型的 IPublishedContent。我喜欢这个,因为额外的智能感知有很大帮助。
@inherits Umbraco.Web.Mvc.UmbracoTemplatePage
@{
var root = Model.Content.AncestorOrSelf(1);
var selection = root.Children.Where(n => !n.GetPropertyValue<bool>("umbracoNaviHide")).ToList();
}
<div class="fleft menu_area">
<button class="btn btn-primary visible-xs" type="button" data- toggle="collapse" data-target="#mainMenu" aria-expanded="false" aria- controls="mainMenu"> <i class="glyphicon glyphicon-th-large"></i> Menu </button>
<div class="collapse navbar-collapse" id="mainMenu">
<ul class="nav navbar-nav">
@CreateListItems(selection)
</ul>
</div>
</div>
@helper CreateListItems(List<IPublishedContent> collection)
{
foreach (var item in collection)
{
if (item.Children.Any(n => !n.GetPropertyValue<bool>("umbracoNaviHide")))
{
<li class="menuOption dropdown @(item.IsAncestorOrSelf(Model.Content) ? "current" : null)" data-menu- id="@item.GetPropertyValue("menuOptionIdentifier")">
<a class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false" href="@item.Url">@item.Name</a>
<ul class="dropdown-menu">
@CreateListItems(item.Children.Where(n => !n.GetPropertyValue<bool>("umbracoNaviHide")).ToList())
</ul>
</li>
}
else
{
<li class="@(item.IsAncestorOrSelf(Model.Content) ? "current" : null)"><a href="@item.Url">@item.Name</a></li>
}
}
}
您可以使用 Model.Content
.