Blazor 通过反射获取嵌套组件

Jul*_*lot 2 asp.net razor asp.net-core blazor

我实际上正在 Blazor 项目 (0.8.0) 中进行表单验证。

我创建了一个名为 InputValidation 的组件。该组件接收许多参数以根据我们可以设置的条件测试属性值是否正确。

@using System.Linq.Expressions;

@typeparam TItem

@if (!Valid)
{
    <span id="@(Id)_validation" class="form-text text-danger">@Message</span>
}

@functions {

    [Parameter]
    string Id { get; set; }

    [Parameter]
    TItem Property { get; set; }

    [Parameter]
    Expression<Func<TItem, bool>> On { get; set; }

    [Parameter]
    string Message { get; set; }

    [Parameter]
    bool ActiveOnLoad { get; set; } = true;

    internal bool Valid { get; set; }
    bool Activated;

    protected async override Task OnInitAsync()
    {
        Activated = ActiveOnLoad;
    }

    protected async override Task OnAfterRenderAsync()
    {
        Activated = true;
    }

    protected async override Task OnParametersSetAsync()
    {
        Valid = !On.Compile().Invoke(Property);
    }
}
Run Code Online (Sandbox Code Playgroud)

您可以像这样在父组件上实现它:

<InputValidation Id="@nameof(ViewModel.UrlInput)" Property="@ViewModel.UrlInput" On="@(x => string.IsNullOrEmpty(x))" Message="Url is empty" ActiveOnLoad="@false"/>
Run Code Online (Sandbox Code Playgroud)

我编写了一个类来验证所有 InputValidation 组件都具有 Valid at true属性。

@if (ViewModel.IsValid(this))
Run Code Online (Sandbox Code Playgroud)

代表父组件。

问题是……它不起作用!

这是验证器的代码:

public static class ModelValidator
{
    public static bool IsValid<T, V>(this T viewmodel, V component) where T : IViewModel where V : ComponentBase
        => component.GetType().GetFields().OfType<InputValidation<T>>().All(x => x.Valid);
}
Run Code Online (Sandbox Code Playgroud)

我知道它不起作用,但即使我们使用反射(GetProperties、GetFields、GetMembers),它也不会返回父组件的任何 InputValidation 成员。

我的问题是:有没有办法通过使用反射来获取所有子组件?如果是,怎么做?

我知道 Blazor 仍处于早期阶段,我希望它很快就会发布,因为它是一项非常令人愉快的技术!

谢谢您的反馈 !

Mis*_*goo 6

此处不需要反射(InputValidation 组件不是父级中的字段,它是将由 RenderTree 呈现的组件)。

您可以使用 ref 属性捕获对每个 InputValidation 组件的引用。

<InputValidation ref="@InputValidationRef" Id="@nameof(ViewModel.UrlInput)" Property="@ViewModel.UrlInput" On="@(x => string.IsNullOrEmpty(x))" Message="Url is empty" ActiveOnLoad="@false"/>
Run Code Online (Sandbox Code Playgroud)

通常这个引用“InputValidationRef”将是一个字段,但您可以使用带有自定义设置器的属性来构建列表(或您喜欢的任何集合)

List<InputValidation> InputValidations = new List<InputValidation>();
InputValidation InputValidationRef { set => InputValidations.Add(value); }
Run Code Online (Sandbox Code Playgroud)

因此,现在每个 InputValidation 都将被捕获为一个引用,并且将为每个 InputValidationRef 设置属性,这将依次将所有引用存储在“InputValidations”集合中。

现在,你有一个集合,你可以测试

InputValidations.All(iv => iv.Valid)
Run Code Online (Sandbox Code Playgroud)

注意:集合仅在组件/页面呈现后填充,因此在初始页面加载期间,引用集合为空,直到调用 OnAfterRender/OnAfterRenderAsync 方法。