最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

c# - Blazor: Determine Layout based upon Route - Stack Overflow

programmeradmin1浏览0评论

Is it possible to do something like this:

<Router AppAssembly="@typeof(Routes).Assembly">
    <Found Context="routeData">
        <RouteView RouteData="@routeData" Path="/admin/*" DefaultLayout="@typeof(AdminLayout)" />
        <RouteView RouteData="@routeData" Path="/user/*" DefaultLayout="@typeof(UserLayout)" />
        <FocusOnNavigate RouteData="@routeData" Selector="h1"/>
    </Found>
</Router>

I've found this question: Change layout in Blazor page based on URL

But it doesn't quite do what I want with multiple layout files. Thanks.

Is it possible to do something like this:

<Router AppAssembly="@typeof(Routes).Assembly">
    <Found Context="routeData">
        <RouteView RouteData="@routeData" Path="/admin/*" DefaultLayout="@typeof(AdminLayout)" />
        <RouteView RouteData="@routeData" Path="/user/*" DefaultLayout="@typeof(UserLayout)" />
        <FocusOnNavigate RouteData="@routeData" Selector="h1"/>
    </Found>
</Router>

I've found this question: Change layout in Blazor page based on URL

But it doesn't quite do what I want with multiple layout files. Thanks.

Share Improve this question asked Jan 29 at 16:30 Jon BarkerJon Barker 1,82817 silver badges25 bronze badges
Add a comment  | 

3 Answers 3

Reset to default 2

The easiest way is to set your layout in the _imports.razor file:

Simply structure your pages in folders:

  • Pages

    • Folder1
      • _imports.razor <= add the line @layout Folder1Layout
      • Page11.razor
      • Page12.razor
    • Folder2
      • _imports.razor <= add the line @layout Folder2Layout
      • Page21.razor
      • Page22.razor
      • Folder21
        • _imports.razor <= add the line @layout Folder21Layout
        • Page211.razor
  • Layouts

    • Folder1Layout.razor
    • Folder2Layout.razor
    • Folder21Layout.razor

You can add also any attributes you want in the _imports.razor to apply them to the pages in the same folder. For example for pages to manage user account, you want the user with authorizations:

@layout ManageLayout
@attribute [Microsoft.AspNetCore.Authorization.Authorize]

In your case, Folder1 can be admin and Folder2 user

Something like this. You can use pattern matching if you have multiple options, and be more precise with the Uri match if you wish.

@inject NavigationManager NavigationManager

<Router AppAssembly="typeof(Program).Assembly">
    <Found Context="routeData">
        <RouteView RouteData="routeData" DefaultLayout="_defaultLayout" />
        <FocusOnNavigate RouteData="routeData" Selector="h1" />
    </Found>
</Router>

@code {
    private Type _defaultLayout =>
        this.NavigationManager.Uri.Contains("admin")
            ? typeof(Layout.AdminLayout)
            : typeof(Layout.MainLayout);
}

This is what I came up with before anyone else responded. See the other answers for a simpler approach.

Routes.razor

<Router AppAssembly="@typeof(Routes).Assembly">
    <Found Context="routeData">
        
        <ReSolverRouteLayout @ref=resolverRouteLayout
              RouteData="@routeData" 
              DefaultLayout="@typeof(MainLayout)"
              InitializeMappings="InitializeMappings" />
        <FocusOnNavigate RouteData="@routeData" Selector="h1"/>
    </Found>
</Router>

@code
{
    private ReSolverRouteLayout resolverRouteLayout = null!;

    private void InitializeMappings()
    {
        resolverRouteLayout.AddRouteLayoutMapping("/console/", typeof(ConsoleLayout));
        resolverRouteLayout.AddRouteLayoutMapping("/program/", typeof(ProgramLayout));
    }
}

ReSolverRouteLayout.cs

public class ReSolverRouteLayout : RouteView
{
    private Dictionary<string, Type> routePrefixLayoutLookup = new();

    [Inject]
    public required NavigationManager NavigationManager { get; set; }

    [Parameter]
    public required Action InitializeMappings { get; set; }

    /// <summary>
    /// Adds a route/layout mapping (called by children)
    /// </summary>
    public void AddRouteLayoutMapping(string routePrefix, Type layout)
    {
        routePrefixLayoutLookup[routePrefix] = layout;
    }

    /// <summary>
    /// Renders the layout/body. Stolen from RouteView
    /// </summary>
    protected override void Render(RenderTreeBuilder builder)
    {
        InitializeMappings();

        var pageLayoutType = GetLayoutTypeForRouteOrDefault();

        builder.OpenComponent<LayoutView>(0);
        builder.AddComponentParameter(1, nameof(LayoutView.Layout), pageLayoutType);
        builder.AddComponentParameter(2, nameof(LayoutView.ChildContent), (RenderFragment)RenderPageWithParameters);
        builder.CloseComponent();
    }

    /// <summary>
    /// Looks up the defined mappings and attempts to find a relevant layout.
    /// </summary>
    /// <returns></returns>
    private Type GetLayoutTypeForRouteOrDefault()
    {
        var match = routePrefixLayoutLookup.SingleOrDefault(each => NavigationManager.Uri.Contains(each.Key)).Value;
        if(match != null)
            return match;

        return DefaultLayout;
    }

    /// <summary>
    /// Stolen from base class.
    /// </summary>
    private void RenderPageWithParameters(RenderTreeBuilder builder)
    {
        builder.OpenComponent(0, RouteData.PageType);

        foreach (var kvp in RouteData.RouteValues)
        {
            builder.AddComponentParameter(1, kvp.Key, kvp.Value);
        }

        builder.CloseComponent();
    }
}
发布评论

评论列表(0)

  1. 暂无评论