Blazor 组件:从子组件更新模型时刷新父组件

gla*_*asa 20 c# asp.net-core blazor blazor-server-side

我在 ASP.NET Core 3 预览版 4 中使用服务器端 Blazor 组件。

我有一个父组件和子组件,使用相同的共享模型,如下所示:

模型 :

public class CountModel
{
    public int Count { get; set; }

    public void Increment()
    {
        Count++;
    }
}
Run Code Online (Sandbox Code Playgroud)

父组件:

@page "/count"

<CascadingValue Value="currentCount">
    <h1>Count parent</h1>

    <p>Current count is : @currentCount.Count</p>

    <button class="btn btn-primary" onclick="@currentCount.Increment">+1 from parent</button>

    <CountChild></CountChild>
</CascadingValue>

@functions {
    private CountModel currentCount = new CountModel();
}
Run Code Online (Sandbox Code Playgroud)

子组件:

<h1>Count child</h1>

<p>Current count is : @currentCount.Count</p>

<button class="btn btn-primary" onclick="@currentCount.Increment">+1 from child</button>


@functions {
    [CascadingParameter]
    private CountModel currentCount { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

它是用于父级和子级的模型的相同实例。当模型从父模型更新时,两者都显示正确的增量值。当它从孩子更新时,只有孩子显示正确的值。

从子组件更新时,如何强制刷新父组件?

请注意,这里我有一个更新模型的函数,但我希望该解决方案在数据绑定到输入时起作用。

Lau*_*e73 34

创建共享服务。RefreshRequested在父级订阅服务事件,从子级订阅Invoke()。在父方法中调用 StateHasChanged();

public interface IMyService
{
    event Action RefreshRequested;
    void CallRequestRefresh();
 }

public class MyService: IMyService
{
    public event Action RefreshRequested;
    public void CallRequestRefresh()
    {
         RefreshRequested?.Invoke();
    }
}


//child component
MyService.CallRequestRefresh();


//parent component
MyService.RefreshRequested += RefreshMe;

private void RefreshMe()
{
    StateHasChanged();
}
Run Code Online (Sandbox Code Playgroud)

  • 这对我也有用,但界面完全没有必要。 (7认同)
  • 我最终做了类似的事情,但不是共享服务,而是父组件订阅了 PropertyChanged 事件 (6认同)
  • 如果其他人遇到同样的问题,请确保您的服务未注册为“瞬态”,因为父级和子级将拥有自己的服务实例,并且组件之间不会触发事件。 (5认同)
  • 该接口对于像这样注册服务很有用;services.AddScoped&lt;IMyService, MyService&gt;(); (3认同)
  • @Shuvra 像这样: async () =&gt; wait RefreshMethod(); (3认同)

Isa*_*aac 7

级联参数的流动是向下的。为了刷新您的父组件,您希望提供一个子组件可以调用的回调,并向其传递一些值。我已经在 Blazor 部分展示了如何在父组件上创建回调,以及如何触发回调,向它传递一个值。

  • 感谢Issac,经过一些测试,我更喜欢Laurence73的解决方案,因为当我使用服务时,父子之间没有直接依赖,并且增加了更多的灵活性(例如,更容易处理兄弟组件) (4认同)

Isa*_*aac 7

以下代码片段是在从其子组件更新模型时刷新父组件的最合适方法。但它增加了更多的讨价还价:父母和孩子之间没有依赖。它不是专门为通知状态更改而创建的。它通知属性、任何属性何时发生更改,并且可以向订阅者提供其值已更改的属性的名称、新值等。

 using System.ComponentModel;
 using System.Runtime.CompilerServices;
 using System.ComponentModel.DataAnnotations;
Run Code Online (Sandbox Code Playgroud)

这里要注意的要点是我们的模型类实现了 INotifyPropertyChanged 接口......

CountModel.cs

public class CountModel : INotifyPropertyChanged
{
    private int count;
    public int Count
    {
        get => count;
        set => SetProperty(ref count, value);
    }

    public event PropertyChangedEventHandler PropertyChanged;
    void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new 
                                   PropertyChangedEventArgs(propertyName));
    }

    bool SetProperty<T>(ref T storage, T value, [CallerMemberName] string 
                                                     propertyName = null)
    {
        if (Equals(storage, value))
        {
            return false;
        }

        storage = value;
        OnPropertyChanged(propertyName);
        return true;
    }

    public void Increment()
    {
        Count++;
    }
}
Run Code Online (Sandbox Code Playgroud)

计数剃刀

@page "/count"
@implements IDisposable

<CascadingValue Value="currentCount">
    <h1>Count parent</h1>

    <p>Current count is : @currentCount.Count</p>

    <button class="btn btn-primary" @onclick="@currentCount.Increment">+1 
                                                     from parent</button>

    <CountChild></CountChild>
</CascadingValue>

@code {
    private CountModel currentCount = new CountModel();

    protected override void OnInitialized()
    {
       currentCount.PropertyChanged += (sender, args) => StateHasChanged();
    }

    public void Dispose()
    {
        currentCount.PropertyChanged -= (sender, args) => StateHasChanged();
    }
}
Run Code Online (Sandbox Code Playgroud)

CountChild.razor

<h1>Count child</h1>

<p>Current count is : @currentCount.Count</p>

<button class="btn btn-primary" @onclick="@currentCount.Increment">+1 from 
                                                            child</button>


@code {
     [CascadingParameter]
     private CountModel currentCount { get; set; }


}
Run Code Online (Sandbox Code Playgroud)

希望这可以帮助...


Dan*_*iel 5

通过调用它的 StateHasChanged 方法更新父状态

创建一个方法来更新父级的状态:

public void RefreshState(){
     this.StateHasChanged();
}
Run Code Online (Sandbox Code Playgroud)

通过级联值或参数将父级传递给子级示例:

<CascadingValue Value="this">
  <ChildComponent /> 
</CascadingValue>
Run Code Online (Sandbox Code Playgroud)

现在在 Child 的组件上声明级联参数:

[CascadingParameter]
public ParentPageType _Parent { get; set; }
Run Code Online (Sandbox Code Playgroud)

现在当你想刷新父级时,只需调用:

_Parent.RefreshState();
Run Code Online (Sandbox Code Playgroud)


Abd*_*kim 5

如果子组件调用父组件提供的 EventCallback,则父组件将重新呈现。所以从技术上来说,你可以这样做:

  • 在子组件中,添加以下内容:
[Parameter]
public EventCallback OnIncrement { get; set; }
Run Code Online (Sandbox Code Playgroud)
  • 然后每当你增加时调用它(伪代码如下):
<button @onClick=@(args => HandleClick()) ... >
Task HandleClick()
{
    currentCount.Increment();

    return OnIncrement.InvokeAsync();
}
Run Code Online (Sandbox Code Playgroud)
  • 在父组件中,提供 OnIncrement 回调:
<CountChild OnIncrement=@( () => {} )/>
Run Code Online (Sandbox Code Playgroud)

即使提供的回调不执行任何操作,它的调用也会触发重新渲染。

请注意,具有“不执行任何操作”的方法/函数通常被认为是代码异味。