简体   繁体   English

如何在 ASP.NET Core Razor 页面中使用 _ViewStart 设置条件布局?

[英]How can I set up conditional Layouts with _ViewStart in ASP.NET Core Razor Pages?

I want to display different layouts based on the current rendered Page.我想根据当前呈现的页面显示不同的布局。

I can't find anything online about this but I feel like this should be an extremely common use case.我在网上找不到任何关于此的信息,但我觉得这应该是一个非常常见的用例。

I only have a few pages.我只有几页。 I would like to assign unique layouts to both my Register and Login pages.我想为我的注册和登录页面分配独特的布局。

This is what I've got so far but I am unable to use the ControllerContext in this situation.这是我到目前为止所得到的,但在这种情况下我无法使用 ControllerContext。

@{
    string controllerName = this.ControllerContext.RouteData.Values["controller"].ToString();
    dynamic Layout;
    switch (controllerName)
    {
        case "Register":
            Layout = "_RegisterLayout";
            break;
        case "Login":
            Layout = "_LoginLayout";
            break;
        default:
            Layout = "_Layout";
            break;
    }
}

在此处输入图片说明

As a convenience, the _ViewStart file is used to set the layout for all pages in the same folder as the ViewStart, and all its subfolders.为方便起见,_ViewStart 文件用于为 ViewStart 所在文件夹及其所有子文件夹中的所有页面设置布局。 You can override that in a number of ways, but the simplest way in your case is to specify a different value for the Layout property in the Razor Page itself:您可以通过多种方式覆盖它,但在您的情况下,最简单的方法是在 Razor 页面本身中为Layout属性指定不同的值:

@page
@model MyApp.Pages.Account.LoginModel
@{
    Layout = "/path/to/login-layout.cshtml;
}
<h1>Login</h1>
...

We recently ran into a similar problem.我们最近遇到了类似的问题。 We decided to provide the layout name with ViewData, Here's how.我们决定为 ViewData 提供布局名称,方法如下。

Layout = (string)ViewData["LayoutName"] ?? "DefaultLayout";

This way you can change the layout using the action, or from inside the view or using an Action filter.通过这种方式,您可以使用操作、从视图内部或使用操作过滤器更改布局。 I will include an Action filter that does the following using the Controller name, like you asked, and then you can register the filter globally.我将包含一个 Action 过滤器,它使用 Controller 名称执行以下操作,如您所问,然后您可以全局注册过滤器。


    public class LayoutNameFilter : IActionFilter
    {
        public void OnActionExecuted(ActionExecutedContext context)
        {
            var result = context.Result as ViewResult;
            var controllerName = context.RouteData.Values["controller"].ToString();
            switch (controllerName)
            {
                case "Register":
                    result.ViewData["LayoutName"] = "_RegisterLayout";
                    break;
                case "Login":
                    result.ViewData["LayoutName"] = "_LoginLayout";
                    break;
                default:
                    result.ViewData["LayoutName"] = "_Layout";
                    break;
            }
        }

        public void OnActionExecuting(ActionExecutingContext context)
        {
        }
    }

And then you can register this filter globally by replacing the services.AddMvc like this.然后你可以通过像这样替换 services.AddMvc 来全局注册这个过滤器。

services.AddMvc(options =>
            {
                options.Filters.Add(new SampleFilter());
            })

Hope this helps.希望这可以帮助。

All the above did not solve the issue for me but the solution below works for me using .net 5 razor pages.以上所有都没有为我解决问题,但下面的解决方案适用于我使用 .net 5 razor 页面。

Note: i set the layout page based on the pages folder注意:我根据 pages 文件夹设置了布局页面

the RelativePath gives you the url relative path like "/Pages/Admin/Index.cshtml" then i split the path to string array. RelativePath 为您提供 url 相对路径,如“/Pages/Admin/Index.cshtml”,然后我将路径拆分为字符串数组。 from the array i get the folder name using pathArray[2].从数组中,我使用 pathArray[2] 获取文件夹名称。

var path = ((Microsoft.AspNetCore.Mvc.RazorPages.CompiledPageActionDescriptor)ViewContext.ActionDescriptor).RelativePath;
string[] pathArray = path.Split('/');
string pageFolder = pathArray[2];
if (pageFolder != null && pageFolder.ToLower()=="admin")
{
    Layout = "_AdminLayout";
}
else
{
    Layout = "_Layout";
}

You can try with ViewData.您可以尝试使用 ViewData。 In the following code, I have changed the layout only for the contact page在以下代码中,我仅更改了联系页面的布局

Contact.cshtml.cs联系方式.cshtml.cs

    public void OnGet()
    {
        ViewData["page"] = "Contact";
        Message = "Your contact page.";
    }

_ViewStart.cshtml _ViewStart.cshtml

@{

    if (ViewData["page"] != null && !string.IsNullOrWhiteSpace(ViewData["page"].ToString()))
    {
        Layout = "_ContactLayout";
    }
    else
    {
        Layout = "_Layout";
    }
}

Try this in _ViewStart.cshtml file :_ViewStart.cshtml文件中试试这个:

@{
    if(ViewData["Layout"] == "Layout1")
        Layout = "_Layout";
    else Layout = "_Layout2";
}

That is an example that is working for me这是一个对我有用的例子

Another great option is to use sections !另一个不错的选择是使用部分 If you do not want to completely redo your _Layout or you do not want to have duplicate code in several different layout files.如果你不想完全重做你的_Layout或者你不想在几个不同的布局文件中有重复的代码。

Here is a section I made in my Layout:这是我在布局中制作的一个部分:

<main role="main" class="pb-3">

    @* PageHeader is used if you want to put something outside of the bootstrap container. *@
    @await RenderSectionAsync("PageHeader", false);

    <div class="container">
        @RenderBody()
    </div>
</main>

Then in a different view file, I can render a section like this:然后在不同的视图文件中,我可以渲染这样的部分:

@section PageHeader
{
    <section class="container-fluid bg-light py-3">
    ...
    </section>
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM