Blazor получает вложенные компоненты с помощью Reflection

На самом деле я работаю над проверкой формы в проекте 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 имеют свойство Valid на true.

@if (ViewModel.IsValid(this))

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

Я знаю, что это не работает, но даже если мы используем Reflection (GetProperties, GetFields, GetMembers), он не вернет ни один из элементов InputValidation родительского компонента.

Мой вопрос: есть ли способ получить все дочерние компоненты с помощью Reflection? Если да, то как это сделать?

Я знаю, что Blazor все еще находится на ранней стадии, и я надеюсь, что он скоро будет выпущен, потому что это очень приятная технология!

Спасибо за ваши ответы !


person Julien Guillot    schedule 25.02.2019    source источник


Ответы (1)


Здесь отражение не требуется (компонент InputValidation не является полем в родительском элементе, это компонент, который будет отображаться RenderTree).

Вы можете записать ссылку на каждый компонент InputValidation с помощью атрибута ref.

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

Обычно этот ref "InputValidationRef" будет полем, но вместо этого вы можете использовать свойство с настраиваемым сеттером для создания списка (или любой другой коллекции, которая вам нравится).

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

Таким образом, каждое InputValidation теперь будет захвачено как ссылка, и свойство InputValidationRef будет установлено для каждого из них, что, в свою очередь, будет хранить все ссылки в коллекции «InputValidations».

Теперь у вас есть коллекция, вы можете протестировать ее против

InputValidations.All(iv => iv.Valid)

Примечание. Коллекция заполняется только после рендеринга компонента / страницы, поэтому во время начальной загрузки страницы коллекция ссылок пуста, пока не будет вызван метод OnAfterRender / OnAfterRenderAsync.

person Mister Magoo    schedule 25.02.2019
comment
Благодарю за ваш ответ ! Для меня было непонятно использовать атрибут ref, поэтому я не думал об этом! Хорошая идея. В вашем примере вы имели в виду, что каждый раз, когда вы захватываете ссылку в атрибут ref, вызывается установщик InputValidationRef? - person Julien Guillot; 25.02.2019
comment
Да, верно, и это создает коллекцию, на которую вы можете ссылаться - person Mister Magoo; 25.02.2019
comment
Хорошая идея (обходной путь) для захвата ссылок на список :) - person Dresel; 17.04.2019