调用通用Blazor子控件中的方法

时间:2019-06-28 13:28:03

标签: blazor

在通用子控件中调用方法

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

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

外观如下:

<InfoPanel>
    <Budget />
</InfoPanel>

这里的预算是从InfoPanelControl派生的。

InfoPanel具有ChildControl属性:

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

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

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

InfoPanelControl childControl = ChildContent.Target as InfoPanelControl;

但是,ChildContent.Target返回的内容不是投放到InfoPanelControl的预算。实际上,它是InfoPanel容器的上级控件的实例。

如何从InfoPanel访问预算(广播到InfoPanelControl)控件的方法?

2 个答案:

答案 0 :(得分:1)

ChildContent.Target属性返回一个生成类的实例,当前RenderFragment委托在该实例上调用呈现内容的实例方法。在这种情况下,由于infoPanel定义了ChildContent属性,因此ChildContent.Target返回infoPanel的容器组件,而不是Budget。 ChildContent.Target由编译器设置,您无法对其进行任何操作。实际上,就RenderFragment委托而言,它不能做很多事情,它提供的发现机制很少。

对于Blazor,您的计划至少在目前而言过于复杂。 我建议使用以下实现:公开在infoPanel组件中引发的Save事件,并将其传播(通知)给订阅者(子组件)。这是一个不太复杂的解决方案,但是我发现您的问题很引人入胜,并希望看到它解决了您最初想要的方式。也许您应该在github上试试运气……很多时候,史蒂夫·安德森(Steve Anderson)都会解决此类问题。

希望这对您有帮助...

答案 1 :(得分:1)

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

我希望将来会有更好的解决方案,但是在撰写本文时,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();
    }

ChildControl

@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
    }

}