如何解决“当前线程未与渲染器的同步上下文关联”的问题?

Dal*_*ron 2 c# asp.net-core blazor blazor-server-side .net-core-3.0

我正在尝试在blazor服务器端应用程序中更改用于标题的字符串。但是我无法更新用户界面。

我尝试使用StateHasChanged(),但是没有用,所以我环顾四周,发现在制作的FlightFinder演示中,它具有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();
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

先感谢您!

bmi*_*ler 26

我刚刚实现了一个像这样的状态容器并遇到了同样的错误 - 但我的服务需要是一个单例。所以我在 aspnetcore git 上找到了一个例子,它完全按照错误消息所说的去做。调用InvokeAsync -- 不是从您的状态容器而是在您尝试更改 razor 组件的状态时调用。

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());
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

现在您的服务(如果它是单身人士)可以立即通知您的所有用户!想想我们过去必须跳过的所有箍环。

  • 我不确定为什么需要 lambda 表达式。这对我有用:`await InvokeAsync(StateHasChanged);` (3认同)

Via*_*lav 19

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

this.InvokeAsync(() => this.StateHasChanged());
Run Code Online (Sandbox Code Playgroud)

  • 我投票赞成这个答案,因为@Vaicheslav 正好有 666 分。 (3认同)
  • 这与OP已经得到的答案有什么不同?(没关系,根据他们自我接受的答案,他们显然更喜欢更改服务类型而不是使用“InvokeAsync()”)。我认为这个答案根本不是有用的贡献。它不会对已经存在的信息添加任何内容。 (2认同)

Dal*_*ron 6

我在早上发布了第一件事,以为我没有时间去研究,并以为到了有人能够帮助我,我本来会抽出更多的时间研究它。尽管我已经花了几天时间来回进行此操作。

我终于找到这篇文章,解释了我要做的事情叫做状态容器。

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

  • 在简要阅读了有作用域的vs单例的内容之后,这很有意义。我仍然会继续提出问题,因为我认为blazor没有足够的问题和答案,这可能会在某个时候帮助某人。 (2认同)