问题
In a Blazor WebAssembly site, suppose I have a class
public class State : IState
{
public bool ShowEasterEggs { get; set; } = false;
}
And I properly register it in my client's Program.cs: builder.Services.AddSingleton<IState, State>();
And I properly inject this into a component:
@inject IState State
@if (State.ShowEasterEggs)
{
<span>EASTER EGGS SHOWN</span>
}
And in some other component, I enable a change to it:
@inject IState State
<input type="checkbox" @bind="State.ShowEasterEggs"/>Show Easter Eggs
I expect that a change to State.ShowEasterEggs from the second component would be detected and any instance of the first component would update automatically. But I find that I need to do some other interaction--changing other values in the first component's parent, to see the change in the first component's instance.
So how does this work, how should it work, and how can I get changes to injected objects to cause an update?
回答1:
You need to use Cascading values and parameters
You would need to have a CascadingValue
component that is parent of any component that will react to the changes.
CascadingValue
will receive a property called Value
that will hold the value you want to the children to see (State
).
And you will get that property in your child components and pass an attribute CascadingParameter
to a property with the same name you passed in CascadingValue
's Value
attribute.
e.g. from the docs
The parent
@inherits LayoutComponentBase
@using BlazorSample.UIThemeClasses
@inject IState State @* Injecting the State *@
<div class="container-fluid">
<div class="row">
<div class="col-sm-3">
<NavMenu />
</div>
<div class="col-sm-9">
<CascadingValue Value="State"> @* Passing State as a Cascading Value*@
<div class="content px-4">
@Body
</div>
</CascadingValue>
</div>
</div>
</div>
Any child component
<input type="checkbox" @bind="State.ShowEasterEggs"/>Show Easter Eggs
@code {
// Getting the Cascading Value as a parameter
[CascadingParameter]
protected State State { get; set; }
}
回答2:
There are various ways to do it. The following one is sort of a service that implements the State pattern and the Notifier pattern:
State.cs
public interface IState
{
event Action Notify;
bool ShowEasterEggs { get; set; }
}
public class State : IState
{
public event Action Notify;
bool showEggs = false;
public bool ShowEasterEggs
{
get => showEggs;
set
{
if (showEggs != value)
{
showEggs = value;
if (Notify != null)
{
Notify?.Invoke();
}
}
}
}
}
Child1.razor
@inject IState State
<input type="checkbox" @bind="State.ShowEasterEggs" />Show Easter Eggs
<hr />
@code {
}
Child2.razor
@inject IState State
@implements IDisposable
@if (State.ShowEasterEggs)
{
<span>EASTER EGGS SHOWN</span>
}
<hr />
@code {
protected override void OnInitialized()
{
State.Notify += OnNotify;
}
public void OnNotify()
{
InvokeAsync(() =>
{
StateHasChanged();
});
}
public void Dispose()
{
State.Notify -= OnNotify;
}
}
Index.razor
@page "/"
<Child1></Child1>
<Child2></Child2>
@code { }
Program.cs
builder.Services.AddSingleton<IState, State>();
AS you've probably noticed, the State service store the state of the check box, and notify subscribers of changes to this state.
Hope this helps...
来源:https://stackoverflow.com/questions/60674120/in-blazor-how-do-i-make-changes-to-an-injected-object-be-reflected-in-all-compo