Blazor 组件:如何从孙子到子项到父项或孙子项到父项进行通信

Blazor components: How to communicate from grandchild to child to parent or grandchild to parent

提问人:LWC433 提问时间:7/9/2021 更新时间:7/12/2021 访问量:2191

问:

在我的 Blazor Server 应用中,我有一个名为“主页”的页面,它基本上是一个搜索页面。在主页(“父”)上,有一个窗体,其中包含用于筛选存储在后端数据库中的数据的控件。搜索结果的每一行都有一个“编辑”按钮,该按钮显示一个引导对话框,允许编辑数据。单击 UpdateDocumentNumber(孙子)组件上的“保存”按钮后,我想刷新主页(父)中的搜索结果

  • 父级:带有搜索结果网格的主页(页面);为每个项目嵌入一个 DisplayDocumentNumber 组件
  • 子组件:DisplayDocumentNumber 组件,该组件有自己的(子)UpdateDocumentNumber 组件
  • 孙子:UpdateDocumentNumber 组件 - 引导对话框

我的理解是,我可以使用事件回调来做到这一点;但是,虽然我可以从孙子到子孙提出/调用事件回调,但我似乎无法从孩子通知父项。

更多细节...

当“主页”(“父”页)循环访问返回的项列表时,它会插入一个组件(“子”),然后该组件具有一个组件来引用“编辑”对话框。下面是循环访问搜索结果的主页:<DisplayDocumentNumber><DisplayDocumentNumber>

<tbody>
    @foreach (var documentNumber in DocumentNumbers)
        {
            <DisplayDocumentNumber DocumentNumber="documentNumber" /> // DocumentNumber parameter in DisplayDocumentNumber receives the data from the documentNumber local var
        }
</tbody>

下面是 DisplayDocumentNumber 组件:

public partial class DisplayDocumentNumber : ComponentBase
{
    [Parameter]
    public DocumentNumberDto DocumentNumber { get; set; }
    [Parameter]
    public EventCallback<bool> OnDocumentNumberUpdatedEventCallback { get; set; }
}

请注意 .这在孙子和孩子之间都能正常工作。public EventCallback<bool> OnDocumentNumberUpdatedEventCallback { get; set; }

在 DisplayDocumentNumber.razor 组件中,是为搜索结果中的每个文档编号呈现的行,包括一个“编辑”按钮,该按钮具有用于显示启动对话框的 DOM 事件。最后,如上所述,还有组件,即<UpdateDocumentNumberDialog>

<tr>
    <td>@DocumentNumber.Column1Name</td>
    <td>@DocumentNumber.Column2Name</td>
    ...etc
    <td><button class="btn btn-primary table-btn" @onclick="@(() => ShowEditDocumentNumberDialog(DocumentNumber))">Edit</button></td>
    <UpdateDocumentNumberDialog @ref="UpdateDocNumDialog" DocumentNumberForUpdating="DocumentNumber" DocumentNumberUpdatedEventCallback="@UpdateDocumentNumberDialog_OnDialogClose"></UpdateDocumentNumberDialog>
</tr>

如果事件回调只适用于孙子到子项或子项到父项,我是否必须创建某种状态容器,如 Chris Sainty (https://chrissainty.com/3-ways-to-communicate-between-components-in-blazor/) 所描述的那样?或者,我是否遗漏了有关事件回调的内容?我试图消除子组件,但失败了,因为“编辑”按钮总是显示网格中迭代的最后一项。

事件 回调 组件 Blazor 通信

评论

0赞 Adam Vincent 7/9/2021
CascadingValues正是这样,级联。您可以在父组件上定义回调(例如; ),并将父组件向下级联到孙组件,其中孙组件可以在父组件上调用回调。OnDocumentNumberUpdatedEventCallback
0赞 LWC433 7/10/2021
到目前为止,我还没有让它工作,所以我错过了一些东西。不过,请继续努力。谢谢!
0赞 LWC433 7/12/2021
你的解释很好,但对我来说,要让它工作,我需要 ,特别是@Bennyboy1973提供的部分。关于使用“this”,我还有更多要学习的。再次感谢!<CascadingValue Value="this">Value="this"
0赞 Adam Vincent 7/13/2021
传球也包含在您自己发布的 Chris Sainty 的博客文章中。可能值得再读一遍。Value="this"

答:

5赞 Bennyboy1973 7/9/2021 #1

我能想到几个选择。一种是让孙子访问主页。这根本不需要事件:

家长.razor

<CascadingValue Value="this">
    Body of page, somewhere in there including <Grandchild/>
</CascadingValue>

@code{
    async Task DoSomething(){
    }
}

孙子剃须刀

@code {
    [CascadingParameter]
    public Parent MainPage {get; set;} // Or whatever your main page is called

    async Task StartSomething (){
        if (MainPage is not null) MainPage.DoSomething();
    }
}

评论

0赞 MrC aka Shaun Curtis 7/10/2021
如果您不想使用某项服务,这是迄今为止最简单的方法。
0赞 iKnowNothing 4/17/2022
我必须在MainPage.DoSomething()方法的末尾添加StateHasChanged(),以便在从孙子组件调用该方法后手动触发对UI的refrsh。当从主页本身触发时,这不是必需的。
1赞 Daniël J.M. Hoffman 7/9/2021 #2

我在 Child 和 Grandchild 组件中包含以下参数:

 [Parameter]
    public Action MyDataHasChanged {get;set;}

此外,在我的孙子组件中:

@code
{
  public void RefreshMySearchResultsInParent()
  {
      MyDataHasChanged?.Invoke();
  }
}

在我的子组件中:

<Grandchild @MyDataHasChanged="MyDataHasChanged"></Grandhild>

在我的父组件中:

<Child @MyDataHasChanged="RefreshMySearchResults"></Child>



 @code
    {
    
    public void RefreshMySearchResults()
    {
       //Do this...
    }

}

评论

2赞 daniel Snyder 7/9/2021
我几乎以这种方式做到这一点,只是我将事件放在一个类中,该类被注入到任何需要它的页面中。
0赞 Daniël J.M. Hoffman 7/10/2021
绝妙的创意@danielSnyder - 这也将使维护变得更加容易 👍
1赞 daniel Snyder 7/12/2021
谢谢。我将整体模式称为 SWIMMER I,用于注入存储库、事件、模型和模板。(模板内容来自数据库)它还允许对页面更改通知进行精细控制。用途是创建一个工具来开发 Blazor 单页应用程序。我总有一天会建造它
0赞 daniel Snyder 8/23/2021
而且我现在被禁止提问,所以如果我很聪明,我想我不会再了。