在 Blazor 8 Web Assembly(可能是其他托管模型)中,在组件中使用通用模型时不会显示 ValidationMessage。这是一个示例。看起来我必须用 For 表达式 做点什么,但是什么?
@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