Humza Malik MindFreak
Humza Malik MindFreak

Reputation: 315

Is there any way to communicate to main layout of blazor pages

Here I want to pass some title to the mainlayout.razor page so that my components or pages can update the title of header. Is there any possible way in blazor to do this ? Any help will be appreciated.

@inherits LayoutComponentBase

<div class="page">
    <div class="sidebar">
        <NavMenu />
    </div>

    <div class="main">
        <div class="top-row px-4 bg-success">
            <button onclick="toggleNav()">
                <span class="oi oi-menu"></span>
            </button>
            <div class="text-center">
                hey there
            </div>
        </div>

        <div class="content px-4">
            @Body
        </div>
    </div>
    
</div>

@code
{

}

and my child component is a router page with @page directive to navigate between pages i want that component to update this mainlayout is there any possible way ? Thanks in advance for any help.

Regards,

Upvotes: 21

Views: 8734

Answers (3)

mbuchok
mbuchok

Reputation: 409

While this has already been answered, I just want to provide the approach I've been using as well, which seems like more work than the accepted answer. But I'm providing it anyway :-)

In my Program.cs I use DI with a base model

builder.Services.AddSingleton<BaseViewModel>();

And in my BaseViewModel I have

protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}

private string _title;
public string Title
{
    get => _title;
    set
    {
        if (_title != value)
        {
            _title = value;
            OnPropertyChanged();
        }
    }
}

In my MainLayout I inject the ViewModel

@inject BaseViewModel ViewModel

Then in my OnInitializedAsync method in my MainLayout I bind an OnPropertyChanged event to update my MainLayout

protected override async Task OnInitializedAsync()
{
    await base.OnInitializedAsync();
    ViewModel.PropertyChanged += OnPropertyChanged;
}

private async void OnPropertyChanged(object sender, PropertyChangedEventArgs e)
{
    await InvokeAsync(StateHasChanged);
}

In your child page, inject the same ViewModel

@inject BaseViewModel ViewModel

Now when you update the Title property in a child page, it should also update in your MainLayout

Upvotes: 0

Benjamin Caure
Benjamin Caure

Reputation: 2403

From .Net 8 (available on Nov. 2023), Blazor will support Section outlets, which are designed for this:

_Imports.razor

@using Microsoft.AspNetCore.Components.Sections

MainLayout.razor

<SectionOutlet SectionName="page-title" />

MyPage.razor

<SectionContent SectionName="page-title">My Page Title</SectionContent>

Upvotes: 13

enet
enet

Reputation: 45596

You should wrap the view portion of the MainLayout component with the CascadingValue component whose value is a reference to the MainLayout itself, so that you can reference the MainLayout component, say, from the Counter component, from which you assign a value string to the property Title defined in the MainLayout component. This property also contain a call to the StateHasChanged method to refresh the display...

 @page "/counter"



// Gets a reference to the MainLayout component
    [CascadingParameter]
    public MainLayout Layout { get; set; }


    protected override void OnInitialized()
    {
        Layout.Title = "Greetings from Counter";

    }

MainLayout.razor

@inherits LayoutComponentBase

<CascadingValue Value="this">
    <div class="page">
        <div class="sidebar">
            <NavMenu />
        </div>

        <div class="main">
            <div class="top-row px-4">
                @Title
                <LoginDisplay />
                <a href="https://learn.microsoft.com/aspnet/" target="_blank">About</a>
            </div>

            <div class="content px-4">
                @Body
            </div>
        </div>
    </div>

</CascadingValue>

@code
{
    private string title;

    public string Title
    {
        get => title;
        set
        {
            title = value;
            InvokeAsync(() => StateHasChanged());
        }
    }
}

Upvotes: 26

Related Questions