23

我正在尝试在我的 blazor-server-side 应用程序中更改用于标题的字符串。但我无法让 UI 更新。

我尝试使用 StateHasChanged(),但是没有用,所以我环顾四周,发现在制作的FlightFinder Demo 上,它有一个 OnChange 事件 Action,所以我正在尝试实现它。

在我尝试刷新浏览器之前它一直有效,然后我遇到了这个错误

System.InvalidOperationException: '当前线程与渲染器的同步上下文无关。在触发渲染或修改渲染期间访问的任何状态时,使用 Invoke() 或 InvokeAsync() 将执行切换到渲染器的同步上下文。

这就是我所拥有的:

private string _title = "TestSite";
public string Title => _title;

public event Action OnChange;

public void ChangePage(string pageName)
{
   _title = pageName;
   NotifyStateChanged();
}

private void NotifyStateChanged(int navigationType = 0)
{
   OnChange?.Invoke();
}

我所要做的就是调用 ChangePage("some Page Title") 并且它可以工作,除非像我提到的那样我尝试刷新。

我只是想通过另一个组件更改一个组件上的字符串,这听起来并不那么疯狂。如果有更好的方法来制作标题或更改其他组件的内容,我很想听听。

那么,我该怎么做才能确保 m 调用方法在正确的线程上?还是有其他更有效的方法来更改标题?

先感谢您!

4

3 回答 3

37

我刚刚实现了一个这样的状态容器并遇到了同样的错误——但我的服务需要是一个单例。因此,我在 aspnetcore git 上找到了一个示例,该示例完全按照错误消息的说明进行操作。调用InvokeAsync - 不是从您的状态容器,而是当您尝试更改剃刀组件的状态时。

https://github.com/dotnet/aspnetcore/blob/321db9d99f84cf7a67d453384292d9339de748d1/src/Components/test/testassets/BasicTestApp/DispatchingComponent.razor

因此,您的状态容器不需要更改,只需您的组件事件处理程序即可。

@code{
    protected override void OnInitialized()
    {
         _YourService.OnChange += OnMyChangeHandler;
    }

    public void Dispose()
    {
         _YourService.OnChange -= OnMyChangeHandler;
    }

    private async void OnMyChangeHandler(object sender, EventArgs e)
    {
        // InvokeAsync is inherited, it syncs the call back to the render thread
        await InvokeAsync(() => {
            DoStuff();
            StateHasChanged());
        }
    }
}

现在您的服务(如果它是单例)可以立即通知您的所有用户!想想我们过去为了做到这一点而必须跳过的所有障碍。

于 2020-02-22T15:31:12.747 回答
17

我在早上发布了这第一件事,以为我没有时间研究,并认为到有人能够帮助我的时候,我会找到更多时间研究它。尽管我已经花了几天的时间来回走动。

我终于找到了这篇文章,它解释了我正在尝试做的事情称为状态容器。

他们说的是我可以将类作为单例注入,这就是我正在做的事情或范围服务。事实证明,我需要做的就是将其更改为范围服务,并且效果很好!

于 2019-06-06T12:51:55.783 回答
3

不需要复杂的解决方案,如果您将通过以下方式更新事件处理程序中的 GUI,则 Blazor 可以完美运行

this.InvokeAsync(() => this.StateHasChanged());
于 2020-07-13T23:27:06.927 回答