问题
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 !
回答1:
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.
来源:https://stackoverflow.com/questions/54859217/blazor-get-nested-components-by-reflection