【问题标题】:How can I set up conditional Layouts with _ViewStart in ASP.NET Core Razor Pages?如何在 ASP.NET Core Razor 页面中使用 _ViewStart 设置条件布局?
【发布时间】:2019-07-14 02:21:43
【问题描述】:

我想根据当前渲染的页面显示不同的布局。

我在网上找不到任何关于此的信息,但我觉得这应该是一个非常常见的用例。

我只有几页。我想为我的注册和登录页面分配独特的布局。

这是我到目前为止所得到的,但在这种情况下我无法使用 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;
    }
}

【问题讨论】:

  • 这段代码遇到了什么问题?你有什么错误吗?
  • 截图显示了为什么它不能编译。
  • 您可以在单个页面中设置布局,而不是使用 ViewStart
  • 您是否建议完全删除 ViewStart 并在每个页面上设置布局?
  • 您可能希望使用 ViewStart 为其他页面设置布局,同时覆盖登录和注册页面的布局

标签: c# asp.net razor-pages


【解决方案1】:

我们最近遇到了类似的问题。我们决定为 ViewData 提供布局名称,方法如下。

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

通过这种方式,您可以使用操作更改布局,或者从视图内部或使用操作过滤器更改布局。我将包含一个操作过滤器,它使用控制器名称执行以下操作,就像您要求的那样,然后您可以全局注册过滤器。


    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)
        {
        }
    }

然后你可以通过像这样替换 services.AddMvc 来全局注册这个过滤器。

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

希望这会有所帮助。

【讨论】:

  • 很遗憾,我没有使用 MVC。
【解决方案2】:

为方便起见,_ViewStart 文件用于设置与 ViewStart 位于同一文件夹中的所有页面及其所有子文件夹的布局。您可以通过多种方式覆盖它,但最简单的方法是在 Razor 页面本身中为 Layout 属性指定不同的值:

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

【讨论】:

    【解决方案3】:

    以上所有内容都没有为我解决问题,但下面的解决方案对我使用 .net 5 razor pages 有效。

    注意:我根据pages文件夹设置布局页面

    RelativePath 为您提供 url 相对路径,例如“/Pages/Admin/Index.cshtml”,然后我将路径拆分为字符串数组。从数组中我得到 使用 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";
    }
    

    【讨论】:

      【解决方案4】:

      您可以尝试使用 ViewData。在下面的代码中,我只更改了联系页面的布局

      联系.cshtml.cs

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

      _ViewStart.cshtml

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

      【讨论】:

        【解决方案5】:

        _ViewStart.cshtml 文件中试试这个:

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

        这是一个对我有用的例子

        【讨论】:

          【解决方案6】:

          另一个不错的选择是使用sections!如果您不想完全重做您的_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>
          

          然后在不同的视图文件中,我可以像这样渲染一个部分:

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

          【讨论】:

            猜你喜欢
            • 2018-11-24
            • 2021-09-25
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2020-05-26
            • 1970-01-01
            • 2018-07-17
            • 2021-10-25
            相关资源
            最近更新 更多