从任意线程调用 StateHasChanged() 是否安全?
Is it safe to call StateHasChanged() from an arbitrary thread?
从任意线程调用 StateHasChanged()
安全吗?
让我给你一些背景信息。想象一个服务器端 Blazor/Razor 组件应用程序,您有:
- 从任意线程引发
BreakingNews
事件的单例服务 NewsProvider
。
- 一个组件
News.cshtml
获取服务注入并订阅 BreakingNews
事件。引发事件时,组件更新模型并调用 StateHashChanged()
NewsProvider.cs
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
吗?
不,从任意线程调用 StateHasChanged()
是不安全的。
调用 StateHasChanged()
的正确方法是使用 InvokeAsync()
void OnBreakingNews(object sender, BreakingNewsEventArgs e)
{
InvokeAsync(() => {
news.Add(e.News);
StateHasChanged();
});
}
从任意线程调用 StateHasChanged()
安全吗?
让我给你一些背景信息。想象一个服务器端 Blazor/Razor 组件应用程序,您有:
- 从任意线程引发
BreakingNews
事件的单例服务NewsProvider
。 - 一个组件
News.cshtml
获取服务注入并订阅BreakingNews
事件。引发事件时,组件更新模型并调用StateHashChanged()
NewsProvider.cs
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
吗?
不,从任意线程调用 StateHasChanged()
是不安全的。
调用 StateHasChanged()
的正确方法是使用 InvokeAsync()
void OnBreakingNews(object sender, BreakingNewsEventArgs e)
{
InvokeAsync(() => {
news.Add(e.News);
StateHasChanged();
});
}