从任意线程调用StateHasChanged()是否安全?

让我给你一些背景。想象一下您拥有的服务器端Blazor/Razor组件应用程序:

  • 单例服务NewsProvider,它从任意线程引发BreakingNews事件。
  • 组件News.cshtml,可获取服务注入(inject)并订阅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;
        }
    }
    

    启动文件
    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();
        });
    }
    

    关于c# - 从任意线程调用StateHasChanged()是否安全?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/54496040/

    10-12 18:49