如何修复“当前线程与渲染器的同步上下文无关”?
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 分。以上是关于如何修复“当前线程与渲染器的同步上下文无关”?的主要内容,如果未能解决你的问题,请参考以下文章
如何修复 HTTPS Silverlight 应用程序上下文中的 WCF maxClockSkew 问题?
如何修复“加载应用程序上下文失败,至少必须存在 1 个 JPA 元模型”
如何修复 SharePoint WebPart 代码后面的当前上下文中不存在变量?