Blazor通过反射获取嵌套组件 [英] Blazor get nested components by Reflection

查看:253
本文介绍了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);
    }
}

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

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

我已经编写了一个类,用于验证所有InputValidation组件均具有 true 属性Valid.

@if (ViewModel.IsValid(this))

代表父组件.

问题是...它不起作用!

这是验证器的代码:

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);
}

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

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

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

感谢您的回复!

解决方案

这里不需要反射(InputValidation组件不是父级中的字段,它是将由RenderTree呈现的组件)./p>

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

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

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

List<InputValidation> InputValidations = new List<InputValidation>();
InputValidation InputValidationRef { set => InputValidations.Add(value); }

因此,现在将每个InputValidation捕获为一个引用,并为每个InputValidationRef设置属性,该属性将依次将所有引用存储在"InputValidations"集合中.

现在,您有一个收藏夹,可以对其进行测试

InputValidations.All(iv => iv.Valid)

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

I'm actually working on form validation in Blazor project (0.8.0).

I have created a component called InputValidation. This component receive many parameters to test if a property value is correct according a condition we can set up.

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

You can implement it on your parent component like this :

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

I have coded a class that verifies that all InputValidation components have the property Valid at true.

@if (ViewModel.IsValid(this))

this represents the parent component.

The problem is... it's not working !

Here is the code of the validator :

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);
}

It's not working, I know, but even if we use Reflection (GetProperties, GetFields, GetMembers), it won't return any of the InputValidation members of the parent component.

My question is : is there a way to get all child components by using Reflection ? If yes, how to do it ?

I know that Blazor is still on early stage and I hope it will be released soon because it's a very pleasant technology !

Thank you for your responses !

解决方案

You don't need reflection here (the InputValidation component is not a field in the parent, it is a component that will be rendered by the RenderTree).

You can capture a reference to each InputValidation component using the ref attribute.

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

Normally this ref "InputValidationRef" would be a field, but you can, instead use a property with a custom setter to build a list (or whatever collection you like)

List<InputValidation> InputValidations = new List<InputValidation>();
InputValidation InputValidationRef { set => InputValidations.Add(value); }

So, each InputValidation will now be captured as a reference and the Property InputValidationRef will be set for each one, which will, in turn, store all the references in the collection "InputValidations".

Now, you have a collection, you can test against

InputValidations.All(iv => iv.Valid)

Note: the collection is only populated after the component/page is rendered, so during the initial page load the collection of references is empty until the OnAfterRender/OnAfterRenderAsync method is called.

这篇关于Blazor通过反射获取嵌套组件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆