问题描述
从任意线程调用StateHasChanged()
是否安全?
Is it safe to call StateHasChanged()
from an arbitrary thread?
让我给您一些背景信息.想象一下您拥有的服务器端Blazor/Razor组件应用程序:
Let me give you some context. Imagine a Server-side Blazor/Razor Components application where you have:
- 单例服务
NewsProvider
,它从任意线程引发BreakingNews
事件. - 一个组件
News.cshtml
,该组件获取注入的服务并预订BreakingNews
事件.引发事件时,组件将更新模型并调用StateHashChanged()
- A singleton service
NewsProvider
that raisesBreakingNews
events from an arbitrary thread. - A component
News.cshtml
that gets the service injected and subscribes toBreakingNews
event. When the event is raised, the component updates the model and callsStateHashChanged()
using System;
using System.Threading;
namespace BlazorServer.App
{
public class BreakingNewsEventArgs: EventArgs
{
public readonly string News;
public BreakingNewsEventArgs(string news)
{
this.News = news;
}
}
public interface INewsProvider
{
event EventHandler<BreakingNewsEventArgs> BreakingNews;
}
public class NewsProvider : INewsProvider, IDisposable
{
private int n = 0;
public event EventHandler<BreakingNewsEventArgs> BreakingNews;
private Timer timer;
public NewsProvider()
{
timer = new Timer(BroadCastBreakingNews, null, 10, 2000);
}
void BroadCastBreakingNews(object state)
{
BreakingNews?.Invoke(this, new BreakingNewsEventArgs("Noticia " + ++n));
}
public void Dispose()
{
timer.Dispose();
}
}
}
News.cshtml
@page "/news"
@inject INewsProvider NewsProvider
@implements IDisposable
<h1>News</h1>
@foreach (var n in this.news)
{
<p>@n</p>
}
@functions {
EventHandler<BreakingNewsEventArgs> breakingNewsEventHandler;
List<string> news = new List<string>();
protected override void OnInit()
{
base.OnInit();
breakingNewsEventHandler = new EventHandler<BreakingNewsEventArgs>(OnBreakingNews);
this.NewsProvider.BreakingNews += breakingNewsEventHandler;
}
void OnBreakingNews(object sender, BreakingNewsEventArgs e)
{
this.news.Add(e.News);
StateHasChanged();
}
public void Dispose()
{
this.NewsProvider.BreakingNews -= breakingNewsEventHandler;
}
}
Startup.cs
using Microsoft.AspNetCore.Blazor.Builder;
using Microsoft.Extensions.DependencyInjection;
using BlazorServer.App.Services;
namespace BlazorServer.App
{
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
// Since Blazor is running on the server, we can use an application service
// to read the forecast data.
services.AddSingleton<WeatherForecastService>();
services.AddSingleton<INewsProvider, NewsProvider>();
}
public void Configure(IBlazorApplicationBuilder app)
{
app.AddComponent<App>("app");
}
}
}
它显然有效,但是我不知道StateHasChanged()
是否是线程安全的.如果不是,如何安全地呼叫StateHashChanged()
?是否有与Control.BeginInvoke
类似的东西?我应该使用SyncrhonizationContext.Post
吗?
it apparently works, but I don't know if StateHasChanged()
is thread safe. If it isn't, how can I call StateHashChanged()
safely?. Is there something similar to Control.BeginInvoke
? Should I use SyncrhonizationContext.Post
?
推荐答案
否,从任意线程调用StateHasChanged()
是不安全的.
No, calling StateHasChanged()
from an arbitrary thread is not safe.
调用StateHasChanged()
的正确方法是使用 InvokeAsync()
The correct way to call StateHasChanged()
is by using InvokeAsync()
void OnBreakingNews(object sender, BreakingNewsEventArgs e)
{
InvokeAsync(() => {
news.Add(e.News);
StateHasChanged();
});
}
这篇关于从任意线程调用StateHasChanged()是否安全?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!