Asp.net core 如何从另一个razor组件重新渲染razor组件

Asp.net core 如何从另一个razor组件重新渲染razor组件,asp.net-core,razor,blazor,Asp.net Core,Razor,Blazor,我似乎无法根据从另一个组件执行的操作重新渲染razor组件。例如: 假设我们有一个组件库“ComponentVariables”,其中定义了一个变量“buttonClickCount”,以跟踪按钮被单击的次数,以及增加变量的方法 ComponentVariables.cs 然后它被_Imports.razor中的所有组件继承,带有@inherits ComponentVariables home组件具有以下代码 家用剃须刀 @buttonClickCount 该按钮是在Clicker.raz

我似乎无法根据从另一个组件执行的操作重新渲染razor组件。例如:

假设我们有一个组件库“ComponentVariables”,其中定义了一个变量“buttonClickCount”,以跟踪按钮被单击的次数,以及增加变量的方法

ComponentVariables.cs 然后它被_Imports.razor中的所有组件继承,带有
@inherits ComponentVariables

home组件具有以下代码

家用剃须刀

@buttonClickCount
该按钮是在Clicker.razor组件中创建的。以及引用组件库中的方法的onclick。和一个包含计数的div(也来自组件基)

响片剃须刀

点击我
@按钮计数
@代码
{
}
现在,home.razor和clicker.razor都在ComponentVariables.cs中使用相同的变量来显示值。但是,当我单击时,只有Clicker组件被重新命名。i、 e.主页始终显示0,而单击器随着您的单击而增加


非常感谢您的帮助。

您使用了继承。因此,似乎您操作同一个变量是因为它们有名称,但实际上,它们都是具有唯一值的唯一实例

如果要在不同组件之间交换值,有三种方法。描述他们。根据您的描述,我建议使用AppState方法。我已经写了答案

我已经复制了之前答案的相关部分,并添加了一些新的想法

让我们首先定义
AppState
。此类使用.NET事件或委托在值更改时发出通知

public class AppState
{
    private Int32 _clickCounter = 0;

    public Int32 ClickCounter
    {
        get => _clickCounter;
        set
        {
            _clickCounter = value;
            AppStateChanged?.Invoke(nameof(ClickCounter), this);
        }
    }

    public event AppStateChangedHandler AppStateChanged;
}
处理程序
公共委托void AppStateChangedHandler(字符串propertyName,AppState)。更改处理程序包括对象本身和已更改的
propertyName
。如果更改是相关的,订阅事件的组件可以使用它进行筛选

AppState被添加到依赖项注入系统中。对于Blazor WASM,它应该是一个单例依赖项。不过,对于Blazor服务器,它应该是一个有范围的服务器

public static async Task Main(string[] args)
{
    var builder = WebAssemblyHostBuilder.CreateDefault(args);
    builder.RootComponents.Add<App>("#app");

    ...
    builder.Services.AddSingleton(new AppState());
    ... 
   
    await builder.Build().RunAsync();
}
使用AppState中相应的属性,而不是递增(并读取)局部变量

为了简化对变更事件的订阅并减少每个组件中的样板文件,我们创建了一个名为
AppStateAwareRecomponentBase
的抽象库。这应该是一个普通的.cs文件

public abstract class AppStateAwareComponentBase : ComponentBase, IDisposable
{
    [Inject]
    protected AppState AppState { get; private set; }

    protected override void OnInitialized()
    {
        base.OnInitialized();

        AppState.AppStateChanged += AppStateChanged;
    }

    protected abstract Boolean HandleAppStateChanged(String propertyName, AppState state);

    private async void AppStateChanged(String propertyName, AppState state)
    {
        Boolean changesOccured = HandleAppStateChanged(propertyName, state);
        if (changesOccured == true)
        {
            await InvokeAsync(StateHasChanged);
        }
    }

    public void Dispose()
    {
        AppState.AppStateChanged -= AppStateChanged;
    }
}
此类已订阅更改事件,但不知道如何准确处理它。因此,它有一个名为
HandleAppStateChanged
的抽象方法,需要在以后的具体类中实现。此类确定布局更改是否是后续结果。如果需要布局更新,子调用将返回
true
。父类(
AppStateAwareComponentBase
)通过调用
InvokeAsync(StateHasChanged)
启动布局更新

如果
AppState
是通过
[Inject]
注入的,并且
IDisposable
的实现保证在从树中删除组件时删除对委托的订阅

我创建了一个
CounterHeader
组件,作为从AppStateAwareComponentBase继承的类

@inherits AppStateAwareComponentBase

<span>Current App Global Counter: @_counter </span>

@code{

   private Int32 _counter = 0;

   protected override Boolean HandleAppStateChanged(String propertyName, AppState state)
   {
       if(propertyName != nameof(AppState.ClickCounter)) {
           return false;
       }
       
       _counter = state.ClickCounter;
       return true;
   }
}
@继承AppStateAwareComponentBase
当前应用程序全局计数器:@\u计数器
@代码{
专用Int32_计数器=0;
受保护的重写布尔HandleAppStateChanged(字符串propertyName,AppState)
{
if(propertyName!=nameof(AppState.ClickCounter)){
返回false;
}
_计数器=状态。单击计数器;
返回true;
}
}

其他想法

这是“AppState”的基本版本。然而,对于所有这些状态转换都有类似的框架,或者您可以使用一种更解耦的方式,比如组件的消息总线,称为


每个应用程序可以有多个“状态”,如
ShoopingCardState
UserState
等,以将其拆分为不同的较小部分。

您使用了继承。因此,看起来您操作同一个变量是因为它们有名称,但实际上,它们都是具有唯一值的唯一实例。也许,您可以描述一下使用这种方法想要实现什么?我开始更多地使用调试器,并注意到每个razor组件都调用了base。这意味着我怀疑你是对的。那么在这种情况下,我将如何在所有组件中引用相同的变量,并使它们随着所述变量的更新而动态变化?有三种方法来处理它。根据您的描述,我建议您使用AppState。我已经写了答案。或者你可以看一看,非常感谢!我只是浏览了这两个链接。它们看起来非常有用,尤其是appstate。然而,接下来的问题是,是否有可能根据变量的变化将重新渲染限制在特定组件上?因为这是我处境中最重要的部分。@VictoryObot,事件或代表呢<代码>
public static async Task Main(string[] args)
{
    var builder = WebAssemblyHostBuilder.CreateDefault(args);
    builder.RootComponents.Add<App>("#app");

    ...
    builder.Services.AddSingleton(new AppState());
    ... 
   
    await builder.Build().RunAsync();
}
@page "/Counter"
@inject AppState appState

<h1>Counter</h1>

<p>Current count: @appState.ClickCounter</p>

<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>

@code {

    private void IncrementCount()
    {
        appState.ClickCounter++;
    }
}
public abstract class AppStateAwareComponentBase : ComponentBase, IDisposable
{
    [Inject]
    protected AppState AppState { get; private set; }

    protected override void OnInitialized()
    {
        base.OnInitialized();

        AppState.AppStateChanged += AppStateChanged;
    }

    protected abstract Boolean HandleAppStateChanged(String propertyName, AppState state);

    private async void AppStateChanged(String propertyName, AppState state)
    {
        Boolean changesOccured = HandleAppStateChanged(propertyName, state);
        if (changesOccured == true)
        {
            await InvokeAsync(StateHasChanged);
        }
    }

    public void Dispose()
    {
        AppState.AppStateChanged -= AppStateChanged;
    }
}
@inherits AppStateAwareComponentBase

<span>Current App Global Counter: @_counter </span>

@code{

   private Int32 _counter = 0;

   protected override Boolean HandleAppStateChanged(String propertyName, AppState state)
   {
       if(propertyName != nameof(AppState.ClickCounter)) {
           return false;
       }
       
       _counter = state.ClickCounter;
       return true;
   }
}