Here's a Blazor Notification Pattern implementation that uses a Scoped service to maintain the data. I've used a simple country select to demonstrate the principles. selectionIds doesn't mean a lot out of context.
The first step is to separate the data and state from the component:
public class CountryData
{
public string? Country { get; private set; }
public event EventHandler? CountryChanged;
public void SetCountry(string? value )
{
this.Country = value;
this.CountryChanged?.Invoke( this, EventArgs.Empty );
}
}
Registered as a Scoped Service
builder.Services.AddScoped<CountryData>();
A CountryDisplay component to dispay the country.
@implements IDisposable
@inject CountryData CountryData
<div class="alert alert-primary m-2">@this.CountryData.Country</div>
@code {
protected override void OnInitialized()
=> this.CountryData.CountryChanged += OnCountryChanged;
private void OnCountryChanged(object? sender, EventArgs e)
=> this.StateHasChanged();
public void Dispose()
=> this.CountryData.CountryChanged -= OnCountryChanged;
}
And a CountrySelector component to modify it:
@inject CountryData CountryData
<div class="bg-light m-2 pt-2 p-4 border border-1">
<h3>Country Selector</h3>
<InputSelect class="form-select" @bind-Value:get="this.CountryData.Country" @bind-Value:set="this.CountryData.SetCountry">
@if (this.CountryData.Country is null)
{
<option selected disabled value=""> -- Select a Country -- </option>
}
@foreach (var country in CountryProvider.CountryList)
{
<option value="@country">@country</option>
}
</InputSelect>
</div>
@code {
// NOTE - @bind-Value:get may give you an error. It's a SDK issue. The code will compile.
}
CountryLayout
@inherits LayoutComponentBase
<PageTitle>SO76864163</PageTitle>
<div class="page">
<div class="sidebar">
<NavMenu />
</div>
<main>
<div class="top-row px-4">
<a href="https://docs.microsoft.com/aspnet/" target="_blank">About</a>
</div>
<article class="content px-4">
<CountryDisplay />
@Body
</article>
</main>
</div>
@code {
private CountryData _countryData = new();
}
And Index:
@page "/"
@layout CountryLayout
<PageTitle>Index</PageTitle>
<h1>Hello, world!</h1>
Welcome to your new app.
<SurveyPrompt Title="How is Blazor working for you?" />
<CountrySelector />
And Counter:
@page "/counter"
@layout CountryLayout
<PageTitle>Counter</PageTitle>
<h1>Counter</h1>
<p role="status">Current count: @currentCount</p>
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
<CountrySelector />
@code {
private int currentCount = 0;
private void IncrementCount()
{
currentCount++;
}
}