从MVC区域的_Layout.cshtml向共同的_Layout.cshtml添加数据

3
我有一个 ASP.NET MVC 4 网站,分为多个区域。每个区域都有一个 Views/Shared/_Layout.cshtml 视图,引用了一个共享的通用布局。在通用布局中,我有一个侧边栏,其中包含一系列项目。我希望能够拥有一个共享的项目列表,可以被所有的 _Layout.cshtml 视图访问,以汇总一组链接。

Area1/Views/Shared/_Layout.cshtml:

@{
   SidebarItems.Add("Area1 Item");
   Layout = "~/Views/Shared/_Layout.cshtml";
}

Views/Shared/_Layout.cshtml:

@{
   SidebarItems.Add("Common Item");
}
<ul>
@foreach (var item in SidebarItems)
{
   <li>@item</li>    @* List should contain two items: "Area1 Item", and "Common Item" *@
}
</ul>

我尝试了两种方法:
1. 为每个区域创建一个自定义的 WebViewPage<T> 类,该类继承自一个共同的自定义 WebViewPage<T> 类,并将 SidebarItems 集合作为共同基类的属性。但这并不起作用,因为似乎 Razor 在移动布局时会分配一个新的 WebPageView
2. 创建一个静态类和一个静态集合,每个 _Layout 调用该集合以添加项。这成功地累积了列表项,但由于它是静态类,其生命周期与应用程序域相关联,这意味着侧边栏从访问多个请求的每个区域中累积项,而不是每个请求的列表。
我正在考虑使用 HttpRequest.Items 属性,但这似乎生存时间过短 - 项目列表在请求之间不会更改,并且完全取决于显示的区域视图。
另一种选择是将列表的呈现推入到在每个区域的_Layout中呈现的section中。这不是最理想的,因为我希望在代码中有一个单一的点来呈现列表,但是也可以做到。
有什么建议吗?
1个回答

4
你可以尝试使用ViewBag来实现。
我通过向ViewBag添加一个名为Items的属性进行了快速测试。这将从每个区域(通过添加自己的项目)和从主布局(通过添加公共项目)中填充。然后,将使用它来渲染来自主布局的项目列表。 Area1\Views\Shared_Layout.cshtml
@{
    ViewBag.Title = "_Layout";
    Layout = "~/Views/Shared/_Layout.cshtml";

    if (ViewBag.Items == null){ViewBag.Items = new List<String>();}
    ViewBag.Items.Add("Area1 item");
}

<h2>Area1 Layout</h2>

@RenderBody()

Views\Shared_Layout.cshtml (part of it)

@{
    if (ViewBag.Items == null){ViewBag.Items = new List<String>();}
    ViewBag.Items.Add("Common Item");
}
<ul>
@foreach (var item in ViewBag.Items)
{
    <li>@item</li>    @* List should contain two items: "Area1 Item", and "Common Item" *@
}
</ul>

我不太喜欢这段代码的外观,因为它重复了很多次并且扩散了ViewBag.Items的使用。通过使用Html助手将项目添加到列表并呈现列表,可以使其更加清晰。例如,您可以创建以下2个Html助手:

public static class HtmlHelpers
{
    public static void AddCommonListItems(this HtmlHelper helper, params string[] values)
    {
        if(helper.ViewContext.ViewBag.Items == null) helper.ViewContext.ViewBag.Items=new List<String>();
        helper.ViewContext.ViewBag.Items.AddRange(values);
    }

    public static MvcHtmlString CommonList(this HtmlHelper helper)
    {
        if (helper.ViewContext.ViewBag.Items == null)
            return new MvcHtmlString(new TagBuilder("ul").ToString());

        var itemsList = new TagBuilder("ul");
        foreach (var item in helper.ViewContext.ViewBag.Items)
        {
            var listItem = new TagBuilder("li");
            listItem.SetInnerText(item);
            itemsList.InnerHtml += listItem.ToString();
        }
        return new MvcHtmlString(itemsList.ToString());

    }
}

接下来,您的视图将变得更加清晰,因为它们只会使用这些助手并避免重复代码:

Area1\Views\Shared_Layout.cshtml(使用新的Html助手)

@{
    ViewBag.Title = "_Layout";
    Layout = "~/Views/Shared/_Layout.cshtml";

    Html.AddCommonListItems("Area1 item", "Area1 item 2");
}

<h2>Area1 Layout</h2>

@RenderBody()

Views\Shared_Layout.cshtml (部分,使用新的Html助手)

@{Html.AddCommonListItems("Common Item");}
@Html.CommonList()

看起来很好用。简直不敢相信我忘记了 ViewBag。如果没有其他问题,明天会接受它。 - Lucas
太好了!(不太满意助手的名称,您可能可以想出更适合您业务需求的名称...) - Daniel J.G.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接