如何修复“当前线程与渲染器的同步上下文无关”?

Posted

技术标签:

【中文标题】如何修复“当前线程与渲染器的同步上下文无关”?【英文标题】:How to fix 'The current thread is not associated with the renderer's synchronization context'? 【发布时间】:2019-10-21 23:42:16 【问题描述】:

我正在尝试在我的 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 调用方法在正确的线程上? 还是有其他更有效的方法来更改标题?

提前谢谢你!

【问题讨论】:

【参考方案1】:

我刚刚实现了一个这样的状态容器并遇到了同样的错误 - 但我的服务需要是单例的。 因此,我在 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());
        
    

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

【讨论】:

它可以与public event Action OnChange; 一起使用吗? @bmiller 非常感谢您对此的回答,大约一个月前它让我摆脱了困境。我在这个帖子中引用了你:***.com/questions/61354233/… 我不确定为什么需要 lambda 表达式。这对我有用:await InvokeAsync(StateHasChanged); 你说得对,不需要 lamda。但是我认为它使正在发生的事情变得更加明显,并且很可能您的“DoStuff()”代码也可能需要在 Invoke 上下文中运行。 @nam 您的服务只是像往常一样调用事件; OnChange?.Invoke(this, EventArgs.Empty); 如果你的服务是单例的,每个页面/用户都应该得到这个事件。【参考方案2】:

我早上发布了第一件事,以为我没有时间研究,并认为当有人能够帮助我时,我会抽出时间进行更多研究。虽然我已经花了几天的时间来回讨论这个问题。

我终于找到了this article,它解释了我正在尝试做的事情被称为状态容器。

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

【讨论】:

在简要阅读了 scoped vs singleton 之后,这很有意义。我仍然会继续提出我的问题,因为我认为 blazor 没有足够的问题和答案,这可能会在某些时候对某人有所帮助。 这对我有用!谢谢【参考方案3】:

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

this.InvokeAsync(() => this.StateHasChanged());

【讨论】:

这与 OP 已经得到的答案有什么不同? (没关系,根据他们自我接受的答案,他们显然更喜欢更改服务类型而不是使用InvokeAsync())。我认为这个答案根本不是有用的贡献。它不会对已经存在的信息添加任何内容。 我说的不是 DalTron 的答案。您的 “真正有效的代码” 与 bmiller 答案中发布的代码字面上 相同,除了在另一个答案中的细微差别之外,它们实际上 解释 i> 代码。 这个解决方案不能解决问题 我投了这个答案,因为@Vaicheslav 正好有 666 分。

以上是关于如何修复“当前线程与渲染器的同步上下文无关”?的主要内容,如果未能解决你的问题,请参考以下文章

如何在google助手的上下文未定义问题中修复参数

如何修复 HTTPS Silverlight 应用程序上下文中的 WCF maxClockSkew 问题?

如何修复“加载应用程序上下文失败,至少必须存在 1 个 JPA 元模型”

如何修复 SharePoint WebPart 代码后面的当前上下文中不存在变量?

如何修复链接库“img/Yellow.svg”不能是上下文相关(/)或页面相关

模块上下文中提供了如何修复索引 [0] 处的 AXIOS_INSTANCE_TOKEN