如何在依赖属性值变更时触发Fluent Validation验证?
问题:依赖属性的Fluent Validation实时验证不触发
我有一个依赖于A、B、C、D、E五个布尔属性的计算属性AnyLetter,Fluent Validation在表单提交时能正常验证,但希望它像Location属性一样,在值变更时实时触发验证——目前修改复选框时,AnyLetter的错误消息不会自动消失,而修改Location时错误会即时消失。
视图模型
public record AlphabetViewModel { public bool AddDate { get; set; } public bool A { get; set; } public bool B { get; set; } public bool C { get; set; } public bool D { get; set; } public bool E { get; set; } public bool AnyLetter => A || B || C || D || E; public string Location { get; set; } }
Fluent验证器
public class AlphabetViewModelValidator : AbstractValidator<AlphabetViewModel> { public AlphabetViewModelValidator() { When(x => x.AddDate, () => { RuleFor(x => x.Location).NotEmpty().WithMessage("Location是必填字段。"); RuleFor(x => x.AnyLetter).NotEqual(false).WithMessage("至少需要选择一个字母。"); }); } }
UI代码
<div class="row"> <div class="col-md-6 col-sm-6"> <label for="Location">Location*</label> <SfTextBox Enabled="true" ID="Location" Placeholder="输入内容" maxlength="100" TabIndex="10" @bind-Value="AlphabetViewModel.Location"/> <ValidationMessage For="@(()=> AlphabetViewModel.Location)" /> </div> </div> <div class="row"> <div class="col-md-3 col-sm-3"> <label for="AnyLetter">Any Letter*</label> <ValidationMessage For="@(()=> AlphabetViewModel.AnyLetter)" /> </div> </div> <div class="row"> <div class="col-md-2 col-sm-2"> <label for="A">A</label> <SfCheckBox id="A" TChecked="bool" TabIndex="12" @bind-Checked="AlphabetViewModel.A"/> </div> <div class="col-md-2 col-sm-2"> <label for="B">B</label> <SfCheckBox id="B" TChecked="bool" TabIndex="13" @bind-Checked="AlphabetViewModel.B"/> </div> <div class="col-md-2 col-sm-2"> <label for="C">C</label> <SfCheckBox id="C" TChecked="bool" TabIndex="14" @bind-Checked="AlphabetViewModel.C"/> </div> <div class="col-md-2 col-sm-2"> <label for="D">D</label> <SfCheckBox id="D" TChecked="bool" TabIndex="15" @bind-Checked="AlphabetViewModel.D"/> </div> <div class="col-md-2 col-sm-2"> <label for="E">E</label> <SfCheckBox id="E" TChecked="bool" TabIndex="16" @bind-Checked="AlphabetViewModel.E"/> </div> </div>
已尝试的无效方案
// 方案1:直接判断字母状态 When(x => (x.A || x.B || x.C || x.D || x.E) == false, () => { RuleFor(x => x.AnyLetter).NotEqual(false).WithMessage("至少需要选择一个字母。"); }); // 方案2:使用DependentRules RuleFor(x => x.AnyLetter).NotEqual(false).DependentRules(() => { RuleFor(x => x.A).NotEqual(false); RuleFor(x => x.B).NotEqual(false); RuleFor(x => x.C).NotEqual(false); RuleFor(x => x.D).NotEqual(false); RuleFor(x => x.E).NotEqual(false); }).WithMessage("至少需要选择一个字母。");
解决方法
问题核心是:Blazor的ValidationMessage组件默认只监听绑定属性的变更,而AnyLetter是计算属性,当A-E变更时,Blazor不会自动触发AnyLetter的验证重新执行。以下是两种可行的解决思路:
1. 调整验证规则,直接验证依赖属性
把针对AnyLetter的验证改成针对整个模型的条件验证,同时指定错误关联到AnyLetter,这样任一复选框变更时都会触发验证:
public class AlphabetViewModelValidator : AbstractValidator<AlphabetViewModel> { public AlphabetViewModelValidator() { When(x => x.AddDate, () => { RuleFor(x => x.Location).NotEmpty().WithMessage("Location是必填字段。"); // 直接验证至少一个字母被选中,关联到AnyLetter的验证消息 RuleFor(x => x) .Must(x => x.A || x.B || x.C || x.D || x.E) .WithMessage("至少需要选择一个字母。") .WithName("AnyLetter"); }); } }
2. 复选框变更时手动触发验证
在Blazor组件中注入EditContext,给每个复选框添加ValueChanged事件,触发全局验证:
<!-- 以A复选框为例,其他复选框同理 --> <SfCheckBox id="A" TChecked="bool" TabIndex="12" @bind-Checked="AlphabetViewModel.A" ValueChanged="@(() => EditContext.Validate())"/>
推荐组合
优先使用调整验证规则+手动触发验证的方案,无需修改视图模型的结构,就能实现和Location一致的实时验证效果。
内容的提问来源于stack exchange,提问作者Sivakrishnan
相关产品推荐
相关产品推荐

