在调用StateHasChanged后,组件未重新渲染

3

我已经阅读了文章“Blazor中三种组件间通信的方法”,并尝试做同样的事情。 在@body下有消息组件,根据@body组件中用户的操作,消息需要进行更改。

@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;
    }
 }

消息组件:

@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;
        }
    }
}

消息类

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类被DI注入为单例。如果我在@body组件中调用SetMsg(newMsgm, msgType)方法,则会调用ChangeState()方法但没有任何变化,也就是说组件未重新渲染。如果我改用“Invoke”而不是“InvokeAsync”,则会出现错误:“当前线程未与Dispatcher关联。在触发呈现或组件状态时,请使用InvokeAsync()将执行切换到Dispatcher。” 如果我重新加载页面,就可以看到消息。

我做错了什么?如何强制重新渲染消息组件?


您的消息组件没有参数,因此Blazor将假定它是静态的。如果您将MainLayout的code部分移动到Message组件中,则每当消息更改时,它都会重新呈现自身。为了完整性,您还应该实现IDisposable,以便可以取消订阅MsgChange事件。 - Mister Magoo
1个回答

3

我解决了这个问题,也许能帮到别人。

我定位了问题 - 当在NavigationManager.NavigateTo("some_page")被调用之后更改@body时,StateHasChanged()不会重新渲染消息组件。我尝试了不同的位置来调用 StateHasChanged(),如果我将它移动到Message.razor中,它就会按预期工作。

最好是从头阅读文档而不是文章 :)


1
文档非常重要。 - Imran Faruqi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接