В веб-сборке Blazor 8 (возможно, в других моделях размещения) ValidationMessage не отображается при использовании универсальной модели в компоненте. Вот пример. Похоже, мне нужно что-то сделать с выражением Для, но что?
@typeparam TModel where TModel : class, new()
<EditForm Context = "editFormComponent" OnValidSubmit = "@HandleValidSubmit" Model = "@model">
<DataAnnotationsValidator />
<h4>Validation Summary</h4>
<ValidationSummary />
@foreach (var property in model.GetType().GetProperties())
{
var propertyValue = property.GetValue(model)?.ToString();
<div class = "row mb-3">
<div class = "col">
<div class = "form-group">
<input @onchange='((e) => HandleValueChanged(e, property.Name))'
type = "text"
value=@propertyValue
class = "form-control" />
</div>
</div>
</div>
<h5>Validation Message</h5>
<ValidationMessage For=@(() => property.Name) />
Я хочу выглядеть так:





Вам необходимо создать собственный компонент ValidationMessage, который будет обрабатывать способ указания имени поля. Построить выражение For в общем виде непросто, но вы можете указать Model и FieldName, которые компонент извлекает из выражения.
Вот BlazorValidationMessage на основе базы кода ValidationMessage.
@implements IDisposable
@foreach (var message in _validationMessages)
{
<div class = "validation-message" @attributes = "this.AdditionalAttributes">
@message
</div>
}
@code {
private EditContext? _previousEditContext;
private FieldIdentifier _fieldIdentifier;
private IEnumerable<string> _validationMessages => CurrentEditContext.GetValidationMessages(_fieldIdentifier);
[CascadingParameter] EditContext CurrentEditContext { get; set; } = default!;
[Parameter] public object? Model { get; set; }
[Parameter, EditorRequired] public string? FieldName { get; set; }
[Parameter(CaptureUnmatchedValues = true)] public IReadOnlyDictionary<string, object>? AdditionalAttributes { get; set; }
protected override void OnParametersSet()
{
if (CurrentEditContext is null|| this.FieldName is null)
throw new InvalidOperationException($"The Edit Context and/or FieldName are missing!");
_fieldIdentifier = new(this.Model ?? this.CurrentEditContext.Model, this.FieldName);
if (CurrentEditContext != _previousEditContext)
{
DetachValidationStateChangedListener();
CurrentEditContext.OnValidationStateChanged += this.OnValidationStateChanged;
_previousEditContext = CurrentEditContext;
}
}
private void OnValidationStateChanged(object? sender, ValidationStateChangedEventArgs e)
=> StateHasChanged();
private void DetachValidationStateChangedListener()
{
if (_previousEditContext != null)
_previousEditContext.OnValidationStateChanged -= OnValidationStateChanged;
}
void IDisposable.Dispose()
{
DetachValidationStateChangedListener();
}
}
Который вы затем используете вот так в GenericComponent
@foreach (var property in model.GetType().GetProperties())
{
var propertyValue = property.GetValue(model)?.ToString();
<div class = "row mb-3">
<div class = "col">
<div class = "form-group">
<input @onchange='((e) => HandleValueChanged(e, property.Name))'
type = "text"
value=@propertyValue
class = "form-control" />
</div>
</div>
</div>
<h5>Validation Message</h5>
<BlazorValidationMessage FieldName = "@property.Name"/>
}
Код ValidationMessage — https://github.com/dotnet/aspnetcore/blob/main/src/Components/Web/src/Forms/ValidationMessage.cs