Reputation: 2935
I have two independent components in a Blazor wasm app between whichi am trying to communicate. under certain cases the communication fails and I cannot understand why.
The(simplified) setup is as follows
<ParentComponent>
<HeaderComponent>
<ProgressBar IsLoading="<Set by IsLoading property from header>" />
</HeaderComponent>
<ResultContainer />
</ParentComponent>
The code behind looks something like this:
public class ResultContainerStateManager
{
public event Action OnLoadStart;
public event Action OnLoadFinish;
public NotifyLoadStart() => this.OnLoadStart?.Invoke();
public NotifyLoadFinish() => this.OnLoadFinish?.Invoke();
}
public partial class HeaderComponent
{
[Inject]
public ResultContainerStateManager ResultContainerStateManager { get; set; }
private bool IsLoading { get; set; }
protected override void OnInitialized()
{
this.ResultContainerStateManager.OnLoadStart += () => this.IsLoading = true;
this.ResultContainerStateManager.OnLoadFinish += () => this.IsLoading = false;
base.OnInitializer();
}
}
public partial class ResultContainer
{
[Inject]
public ResultContainerStateManager ResultContainerStateManager { get; set; }
private bool IsLoading { get; set; }
protected override async Task OnParametersSetAsync()
{
<code>
if (shouldLoadData)
{
this.ResultContainerStateManager.NotifyLoadStart();
<more code>
this.ResultContainerStateManager.NotifyLoadFinish();
}
await base.OnParametersSetAsync();
}
}
public partial class ProgressBar
{
[Parameter]
public bool IsLoading { get; set; }
}
Where the IsLoading
parameter from the progress bar is set from the IsLoading
property from HeaderComponent
, like
<div id="headerComponent">
<More html here>
<ProgressBar IsLoading="@this.IsLoading" />
</div>
I don't think it matters, but the progress bar itself uses the MatProgress
component, like so:
@if (this.IsLoading)
{
<MatProgress Indeterminate="true" />
}
else
{
<Other html code>
}
The problem is that the progress bar starts when the ResultContainer
executes the NotifyLoadStart()
method, but it doesn't stop when the NotifyLoadFinish()
method is executed.
I can see when debugging that the IsLoading
property of the HeaderComponent
is set back to false after the NotifyLoadFinish()
call, but it has no Effect on the UI.
What I have tried so far:
ResultContainerStateManager
directly into the Progress barawait Task.Yield()
after each Notify
callthis.StateHasChanged()
calls in the event handlers and after each Notify
call (I know the latter should not change anything at all, since it is not in the same hierarchy)None of that changed anything and I would really like to understand why.
The only success I've had was when using EventCallbacks
instead of the events. But I am using events in lots of other places and they all seem to work fine.
Could somebody tell me why events seem to fail and how this can be fixed?
Upvotes: 0
Views: 294
Reputation: 45764
Try this code
public async Task OnLoadStart()
{
this.IsLoading = true;
await InvokeAsync(() => { StateHasChanged(); });
}
public async Task OnLoadFinish()
{
this.IsLoading = false;
await InvokeAsync(() => { StateHasChanged(); });
}
protected override void OnInitialized()
{
this.ResultContainerStateManager.OnLoadStart += OnLoadStart;
this.ResultContainerStateManager.OnLoadFinish += OnLoadFinish;
}
Change : public event Action OnLoadStart;
To: public event Func<Task> OnLoadStart;
And: public event Action OnLoadFinish;
Tp: public event Func<Task> OnLoadFinish;
Implement IDisposable in the HeaderComponent component:
@implements IDisposable
public void Dispose()
{
this.ResultContainerStateManager.OnLoadStart -= OnLoadStart;
this.ResultContainerStateManager.OnLoadFinish -= OnLoadFinish;
}
Start coding asynchronously wherever you can.
Upvotes: 1