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?
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:)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With