在通用子控件中调用方法
我有一个名为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)控件的方法?
答案 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
}
}