_Layout.cshtml 上的 MVC 决策
MVC Decision making on _Layout.cshtml
所以我环顾四周,似乎找不到合适的解决方案来解决我的问题。
问题
在我的布局中,我希望能够根据数据库中的内容选择运行时是否存在导航项:
当前布局(导航栏)
<div class="navbar-collapse collapse">
<ul class="nav navbar-nav">
<li>@Html.ActionLink("Dashboard", "Index", "Dashboard")</li>
<li>@Html.ActionLink("NzbGet", "Index", "NzbGet")</li>
<li>@Html.ActionLink("Plex", "Index", "Plex")</li>
<li>@Html.ActionLink("Settings", "Index", "Settings")</li>
</ul>
</div>
我如何决定要显示哪一个:
public PrincipleExtension(ISettingsService<SabNzbSettingsDto> sab)
{
SabService = sab;
}
private ISettingsService<SabNzbSettingsDto> SabService { get; set; }
public bool IsApplicationEnabled(IPrincipal principal, Applications application)
{
switch (application)
{
case Applications.SabNZBD:
return SabService.GetSettings().Enabled;
//...
}
return false;
}
现在 PrincipleExtension
最初是 IPrincipal
上的扩展方法。但现在这是不可能的,因为我正在使用 IoC 容器并且不想对任何依赖项进行硬编码。
所以在它是静态方法之前我可以做到 User.IsApplicationEnabled(Applications.SabNZBD)
。
我如何才能检查应用程序现在是否在布局中将启用标志设置为 true?有什么想法吗?
谢谢。
我会创建一个全局 ActionFilter 并覆盖 OnActionExecuting 方法,以便为每个请求将您的标志放在 ViewBag 中。您还可以创建一个 HtmlHelper 扩展方法。
将您的菜单 HTML 移动到 PartialView 并将其 return 作为来自控制器操作的 ActionResult。
<div class="navbar-collapse collapse">
<ul class="nav navbar-nav">
@foreach (var item in Model)
{
<li><a href="@item.Url">@item.Name</a></li>
}
</ul>
</div>
让控制器确定要显示的菜单项并将新模型发送到 PartialView。
public ActionResult ProductsMenu()
{
var listOfAvailableProducts = GetAvialableProducts(Principal); //to implement elsewhere
var productsMenuItems = new List<ProductMenuItem>();
for(var i in listOfAvailableProducts)
{
productsMenuItems.Add(new ProductMenuItem
{
Id = i.id,
Name = i.name,
Url = "//example.com/there"
}
);
}
return PartialView("/path/to/_ProductsMenu.cshtml", productsMenuItems);
}
然后在 _Layout.cshtml razor 视图中这样调用它:
@{
Html.RenderAction("ActionName","ControllerName");
}
您可能想看一下名为 MVCSitemapProvider 的 nuget 包。
它具有 bootstrap 互操作性,您可以使用它在运行时动态生成导航,让您可以完全灵活地在任何给定时间检查导航的 state/status。
这link表明您可以随时动态生成导航节点:
public class StoreDetailsDynamicNodeProvider
: DynamicNodeProviderBase
{
public override IEnumerable<DynamicNode> GetDynamicNodeCollection(ISiteMapNode node)
{
using (var storeDB = new MusicStoreEntities())
{
// Create a node for each album
foreach (var album in storeDB.Albums.Include("Genre"))
{
DynamicNode dynamicNode = new DynamicNode();
dynamicNode.Title = album.Title;
dynamicNode.ParentKey = "Genre_" + album.Genre.Name;
dynamicNode.RouteValues.Add("id", album.AlbumId);
yield return dynamicNode;
}
}
}
}
这种方法的另一个好处是它恢复了 Sitemap.xml 式的功能,允许您同时分配静态和动态导航。
这是我的菜单显示模板的示例:
@model MenuHelperModel
<div class="navbar navbar-inverse navbar-static-top hidden-print">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#navContainer">
<span class="sr-only">Toggle Navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a href="~/" class="navbar-brand">AH Operations <i class="glyphicon glyphicon-home"></i></a>
</div>
<div class="collapse navbar-collapse" id="navContainer">
<ul class="nav navbar-nav" role="menu" aria-labelledby="dropdownMenu">
@foreach (var node in Model.Nodes)
{
if (node.Title == "Separator")
{
<li class="nav-divider"></li>
}
else if (node.Children.Any())
{
if (node.IsCurrentNode || node.IsInCurrentPath)
{
<li class="active dropdown">
@Html.DisplayFor(m => node)
@Html.DisplayFor(m => node.Children)
</li>
}
else
{
<li class="dropdown">
@Html.DisplayFor(m => node)
@Html.DisplayFor(m => node.Children)
</li>
}
}
else
{
if (node.IsCurrentNode || node.IsInCurrentPath)
{
<li class="active">
@Html.DisplayFor(m => node)
</li>
}
else
{
<li>
@Html.DisplayFor(m => node)
</li>
}
}
}
</ul>
@Html.Partial("_LoginPartial")
</div>
</div>
要使其与 Bootstrap 3 中删除的无限 n+1 子菜单样式一起使用,请添加此 CSS:
.navbar-user {
font-size: 14px !important;
}
.dropdown-submenu {
position: relative;
}
.dropdown-submenu > .dropdown-menu {
top: 0;
left: 100%;
margin-top: -6px;
margin-left: -1px;
-webkit-border-radius: 0 6px 6px 6px;
-moz-border-radius: 0 6px 6px 6px;
border-radius: 0 6px 6px 6px;
}
.dropdown-submenu > a:after {
display: block;
content: " ";
float: right;
width: 0;
height: 0;
border-color: transparent;
border-style: solid;
border-width: 5px 0 5px 5px;
border-left-color: #cccccc;
margin-top: 5px;
margin-right: -10px;
}
.dropdown-submenu:hover > a:after {
border-left-color: #ffffff;
}
.dropdown-submenu.pull-left {
float: none;
}
.dropdown-submenu.pull-left > .dropdown-menu {
left: -100%;
margin-left: 10px;
-webkit-border-radius: 6px 0 6px 6px;
-moz-border-radius: 6px 0 6px 6px;
border-radius: 6px 0 6px 6px;
}
所以我环顾四周,似乎找不到合适的解决方案来解决我的问题。
问题
在我的布局中,我希望能够根据数据库中的内容选择运行时是否存在导航项:
当前布局(导航栏)
<div class="navbar-collapse collapse">
<ul class="nav navbar-nav">
<li>@Html.ActionLink("Dashboard", "Index", "Dashboard")</li>
<li>@Html.ActionLink("NzbGet", "Index", "NzbGet")</li>
<li>@Html.ActionLink("Plex", "Index", "Plex")</li>
<li>@Html.ActionLink("Settings", "Index", "Settings")</li>
</ul>
</div>
我如何决定要显示哪一个:
public PrincipleExtension(ISettingsService<SabNzbSettingsDto> sab)
{
SabService = sab;
}
private ISettingsService<SabNzbSettingsDto> SabService { get; set; }
public bool IsApplicationEnabled(IPrincipal principal, Applications application)
{
switch (application)
{
case Applications.SabNZBD:
return SabService.GetSettings().Enabled;
//...
}
return false;
}
现在 PrincipleExtension
最初是 IPrincipal
上的扩展方法。但现在这是不可能的,因为我正在使用 IoC 容器并且不想对任何依赖项进行硬编码。
所以在它是静态方法之前我可以做到 User.IsApplicationEnabled(Applications.SabNZBD)
。
我如何才能检查应用程序现在是否在布局中将启用标志设置为 true?有什么想法吗?
谢谢。
我会创建一个全局 ActionFilter 并覆盖 OnActionExecuting 方法,以便为每个请求将您的标志放在 ViewBag 中。您还可以创建一个 HtmlHelper 扩展方法。
将您的菜单 HTML 移动到 PartialView 并将其 return 作为来自控制器操作的 ActionResult。
<div class="navbar-collapse collapse">
<ul class="nav navbar-nav">
@foreach (var item in Model)
{
<li><a href="@item.Url">@item.Name</a></li>
}
</ul>
</div>
让控制器确定要显示的菜单项并将新模型发送到 PartialView。
public ActionResult ProductsMenu()
{
var listOfAvailableProducts = GetAvialableProducts(Principal); //to implement elsewhere
var productsMenuItems = new List<ProductMenuItem>();
for(var i in listOfAvailableProducts)
{
productsMenuItems.Add(new ProductMenuItem
{
Id = i.id,
Name = i.name,
Url = "//example.com/there"
}
);
}
return PartialView("/path/to/_ProductsMenu.cshtml", productsMenuItems);
}
然后在 _Layout.cshtml razor 视图中这样调用它:
@{
Html.RenderAction("ActionName","ControllerName");
}
您可能想看一下名为 MVCSitemapProvider 的 nuget 包。
它具有 bootstrap 互操作性,您可以使用它在运行时动态生成导航,让您可以完全灵活地在任何给定时间检查导航的 state/status。
这link表明您可以随时动态生成导航节点:
public class StoreDetailsDynamicNodeProvider
: DynamicNodeProviderBase
{
public override IEnumerable<DynamicNode> GetDynamicNodeCollection(ISiteMapNode node)
{
using (var storeDB = new MusicStoreEntities())
{
// Create a node for each album
foreach (var album in storeDB.Albums.Include("Genre"))
{
DynamicNode dynamicNode = new DynamicNode();
dynamicNode.Title = album.Title;
dynamicNode.ParentKey = "Genre_" + album.Genre.Name;
dynamicNode.RouteValues.Add("id", album.AlbumId);
yield return dynamicNode;
}
}
}
}
这种方法的另一个好处是它恢复了 Sitemap.xml 式的功能,允许您同时分配静态和动态导航。
这是我的菜单显示模板的示例:
@model MenuHelperModel
<div class="navbar navbar-inverse navbar-static-top hidden-print">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#navContainer">
<span class="sr-only">Toggle Navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a href="~/" class="navbar-brand">AH Operations <i class="glyphicon glyphicon-home"></i></a>
</div>
<div class="collapse navbar-collapse" id="navContainer">
<ul class="nav navbar-nav" role="menu" aria-labelledby="dropdownMenu">
@foreach (var node in Model.Nodes)
{
if (node.Title == "Separator")
{
<li class="nav-divider"></li>
}
else if (node.Children.Any())
{
if (node.IsCurrentNode || node.IsInCurrentPath)
{
<li class="active dropdown">
@Html.DisplayFor(m => node)
@Html.DisplayFor(m => node.Children)
</li>
}
else
{
<li class="dropdown">
@Html.DisplayFor(m => node)
@Html.DisplayFor(m => node.Children)
</li>
}
}
else
{
if (node.IsCurrentNode || node.IsInCurrentPath)
{
<li class="active">
@Html.DisplayFor(m => node)
</li>
}
else
{
<li>
@Html.DisplayFor(m => node)
</li>
}
}
}
</ul>
@Html.Partial("_LoginPartial")
</div>
</div>
要使其与 Bootstrap 3 中删除的无限 n+1 子菜单样式一起使用,请添加此 CSS:
.navbar-user {
font-size: 14px !important;
}
.dropdown-submenu {
position: relative;
}
.dropdown-submenu > .dropdown-menu {
top: 0;
left: 100%;
margin-top: -6px;
margin-left: -1px;
-webkit-border-radius: 0 6px 6px 6px;
-moz-border-radius: 0 6px 6px 6px;
border-radius: 0 6px 6px 6px;
}
.dropdown-submenu > a:after {
display: block;
content: " ";
float: right;
width: 0;
height: 0;
border-color: transparent;
border-style: solid;
border-width: 5px 0 5px 5px;
border-left-color: #cccccc;
margin-top: 5px;
margin-right: -10px;
}
.dropdown-submenu:hover > a:after {
border-left-color: #ffffff;
}
.dropdown-submenu.pull-left {
float: none;
}
.dropdown-submenu.pull-left > .dropdown-menu {
left: -100%;
margin-left: 10px;
-webkit-border-radius: 6px 0 6px 6px;
-moz-border-radius: 6px 0 6px 6px;
border-radius: 6px 0 6px 6px;
}