Reputation: 353
I have read the article "3 Ways to Communicate Between Components in Blazor" and have tried to do the same. I have message component under the @body and depending on user actions in the @body components message has to be changed
@inject ClientMessage clientMessage
@inherits LayoutComponentBase
@using Site.Shared.Components
<div class="sidebar">
<AdminMenu />
</div>
<div class="main">
<div class="content px-4">
@Body
</div>
<Message/>
</div>
@code
{
protected async Task ChangeState()
{
await InvokeAsync(StateHasChanged);
}
protected override void OnInitialized()
{
clientMessage.MsgChange += ChangeState;
}
}
Message component:
@inject ClientMessage clientMessage
<div style="@(IsVisble ? "display:block" : "display:none")" class="@MsgClass" role="alert">
@if (clientMessage != null)
{
@clientMessage.Message
}
</div>
@code {
public bool IsVisble
{
get
{
if (string.IsNullOrEmpty(@clientMessage.Message))
{
return false;
}
return true;
}
}
public string MsgClass
{
get
{
if (clientMessage == null)
{
return string.Empty;
}
string msgClass;
switch (clientMessage.MsgType)
{
case EMsgType.Info:
msgClass = "alert alert-info";
break;
case EMsgType.Success:
msgClass = "alert alert-success";
break;
case EMsgType.Warning:
msgClass = "alert alert-warning";
break;
case EMsgType.Error:
msgClass = "alert alert-danger";
break;
case EMsgType.NoMsg:
default:
msgClass = string.Empty;
break;
}
return msgClass;
}
}
}
Message class
public class ClientMessage
{
public event Func<Task> MsgChange;
public ClientMessage(string msg, EMsgType msgType)
{
this.Message = msg;
this.MsgType = msgType;
NotifyStateChanged();
}
public void SetMsg(string msg, EMsgType msgType)
{
this.Message = msg;
this.MsgType = msgType;
NotifyStateChanged();
}
public string Message { get; set; }
public EMsgType MsgType { get; set; }
private void NotifyStateChanged()
{
if (MsgChange != null)
{
MsgChange.Invoke();
}
}
}
ClientMessage class is injected as a singleton by DI. If I invoke SetMsg(newMsgm, msgType) in the @body components then ChangeState() method is invoked but nothing happened, I mean component is not re-rendered. If I instead "InvokeAsync" use "Invoke" I have an error "The current thread is not associated with the Dispatcher. Use InvokeAsync() to switch execution to the Dispatcher when triggering rendering or component state.". If I reload the page I can see Message.
What do I wrong and how can I force to re-render message component?
Upvotes: 4
Views: 7684
Reputation: 353
I resolved this issue. Maybe it will help someone.
I localized the problem - when @body was changed after NavigationManager.NavigateTo("some_page") had been invoked StateHasChanged() does not re-rendered message component. I tried different places where I can fire StateHasChanged() and if I moved it to Message.razor it stars to work as expected.
It is better to read the documentation at the beggining than articles:)
Upvotes: 3