首页 > 解决方案 > 在泛型 Blazor 子控件中调用方法

问题描述

在通用子控件中调用方法

我有一个名为 InfoPanel 的容器控件,它应该包含各种类型的其他控件的实例,但都派生自一个名为 InfoPanelControl 的基类。InfoPanelControl 定义了一个虚拟方法 Save。

我想从 InfoPanel 中调用包含控件的 Save 方法,以便每个具体控件都进行自己的特定保存。

这是它的外观:

<InfoPanel>
    <Budget />
</InfoPanel>

这里的预算来自 InfoPanelControl。

InfoPanel 有一个 ChildControl 属性:

[Parameter] private RenderFragment ChildContent { get; set; }

其中填充了子控件的实例,在此示例中为预算。

现在,我需要从 InfoPanel 访问 Budget 控件(作为 InfoPanelControl,因为我不需要特定类型,只需要基本类型)。在 InfoPanel 中,我希望执行以下操作:

InfoPanelControl childControl = ChildContent.Target as InfoPanelControl;

但是,ChildContent.Target 返回的不是投射到 InfoPanelControl 的预算。它实际上是一个更高级别控件的实例,它是 InfoPanel 的容器。

如何从 InfoPanel 访问 Budget (casted to InfoPanelControl) 控件的方法?

标签: blazor

解决方案


奇怪的是,几天前我实际上做了类似的事情。我最终使用级联参数/值来解决我的特定问题。我在下面使用了一个简单的示例来展示一般逻辑。

我希望将来会有更好的解决方案,但在撰写本文时,blazor 仍处于预览阶段。

我还建议使用 ChildControlBase 来实现所有子控件继承的接口。

这个实现的另一个“好处”是它适用于可能在“ChildContent”中的多个子组件,并且它周围的标记无关紧要。

我目前在 OnParametersSet 的覆盖中将子级添加到父级。根据您的需要,您可能希望以不同的方式使用它或具有其他逻辑。

ParentControlBase.cs

    public class ParentControlBase : ComponentBase
{
    private List<IDoSomething> _childControls;

    public ParentControlBase()
    {
        _childControls = new List<IDoSomething>();
    }

    public void AddChildControl(IDoSomething control)
    {
        if (!_childControls.Contains(control))
        {
            _childControls.Add(control); 
        }
    }

    public void DoSomethingOnRelevantChildControls()
    {
        foreach (var control in _childControls)
        {
            control.DoSomething();
        }
    }
}

ParentControl.razor

@inherits ParentControlBase
<div class="parent-control-container">
<div>Parent Control</div>
    <CascadingValue Name="IDoSomethingParentControl" value="@this">
        @ChildContent
    </CascadingValue>
    <div class="btn btn-primary" @onclick="@DoSomethingOnRelevantChildControls">Do Something</div>
</div>
@code{
    [Parameter]
    private RenderFragment ChildContent { get; set; }
}

通用子控件实现

   public interface IDoSomething
    {
        void DoSomething();
    }

子控件

@implements IDoSomething
<div>ChildControl</div>

@code
{

    [CascadingParameter(Name = "IDoSomethingParentControl")]
    private ParentControlBase CurrentParentControl { get; set; }

    protected override void OnParametersSet()
    {
        if (CurrentParentControl != null)
        {
            CurrentParentControl.AddChildControl(this);
        }
    }

    public void DoSomething()
    {
        //Do Something implementation
    }

}

推荐阅读