【问题标题】:Update state of all Blazor pages更新所有 Blazor 页面的状态
【发布时间】:2023-02-24 19:25:40
【问题描述】:

我正在构建一个 Blazor 客户端应用程序 (WebAssembly)。 有没有办法在当前显示的所有页面上触发当前状态的更新?

在我的应用程序中,我从侧边栏更改了语言,我希望该更改能够刷新当前显示的组件和页面。重新加载页面对我来说不是一个好的解决方案,因为应用程序保持了很多状态,我更愿意避免在本地存储或类似存储中持久存在。

我通过显式连接一个事件来触发页面中的 StateHasChanged() 使其工作,但这需要我在每个页面上都这样做。

我用默认的 Blazor 模板重现了这个问题来说明行为。 侧边栏和页面使用一个非常简单的通用状态服务:

public class StateService
{
    public int CurrentCount { get; set; }
}

in Program.cs:
builder.Services.AddScoped<StateService>();

【问题讨论】:

    标签: blazor blazor-webassembly


    【解决方案1】:

    使用事件。

    见 - How can I trigger/refresh my main .RAZOR page from all of its sub-components within that main .RAZOR page when an API call is complete?

    public class StateService
    {
        public event EventHandler? CounterChanged;
    
        private int _currentCount;
        public int CurrentCount
        {
            get => _currentCount;
            set
            {
                _currentCount = value;
                this.CounterChanged?.Invoke(this, EventArgs.Empty);
            }
        }
    }
    

    您还可以使用私有 setter 实现 CurrentCount,然后实现触发事件的 setter 方法。

        public int CurrentCount {get; private set;}
    
        public void SetCount(int value)
        {
            this.CurrentCount = value;
            this.CounterChanged?.Invoke(this, EventArgs.Empty);
        }
    
    //...
    @code{
        [Inject] private StateService Service {get; set;} = default!;
    
        protected override void OnInitialized()
            => this.Service.CounterChanged += this.OnStateChanged;
    
        private void OnStateChanged(object? sender, EventArgs e)
           => this.InvokeAsync(StateHasChanged);
    
        public void Dispose()
            => this.Service.CounterChanged -= this.OnStateChanged; 
    }
    

    如果你想在很多组件中实现这一点,那么创建一个实现必要功能的基础组件,然后从中继承:

    using Microsoft.AspNetCore.Components;
    
    namespace SO75555251;
    
    public class MyComponentBase : ComponentBase, IDisposable
    {
        [Inject] private StateService Service { get; set; } = default!;
    
        private bool _firstRender = true;
    
        // I do this here so if any of the normal lifecycle methods are overridden
        // without a call to base then everything works 
        public override Task SetParametersAsync(ParameterView parameters)
        {
            parameters.SetParameterProperties(this);
            if (_firstRender)
                this.Service.CounterChanged += this.OnStateChanged;
    
            _firstRender = false;
            return base.SetParametersAsync(parameters);
        }
    
        private void OnStateChanged(object? sender, EventArgs e)
        => this.InvokeAsync(StateHasChanged);
    
        public virtual void Dispose()
            => this.Service.CounterChanged -= this.OnStateChanged;
    }
    
    @page "/"
    @inherits MyComponentBase
    
    <PageTitle>Index</PageTitle>
    
    <h1>Hello, world!</h1>
    //...
    

    【讨论】:

    • 是的,这确实有效。不过,我希望避免在项目的每个页面上都执行此操作。如果找不到侵入性较小的方法,我将使用这种方法。
    猜你喜欢
    • 2021-04-18
    • 2021-03-20
    • 2020-09-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-06
    相关资源
    最近更新 更多