如何实现INotifyDataErrorInfo仅在点击保存时触发验证
解决方案:按需触发INotifyDataErrorInfo验证(仅保存时执行)
你的问题核心在于当前实现中属性变更时自动触发了验证(RaisePropertyChanged里调用了ValidateAsync),且初始化时模型的空值就被验证了。要实现“仅保存时验证”的需求,我们需要调整验证触发时机、绑定配置和模型逻辑,具体步骤如下:
1. 移除自动验证触发,仅保留手动验证
首先修改ValidateModelBase的RaisePropertyChanged方法,删掉自动调用的ValidateAsync()——这是导致初始化和输入过程中触发验证的根本原因:
public void RaisePropertyChanged([CallerMemberName]string propertyName = null) { var handler = PropertyChanged; handler?.Invoke(this, new PropertyChangedEventArgs(propertyName)); // 移除自动验证调用:ValidateAsync(); }
同时,在Validate()方法末尾添加HasErrors的属性变更通知,确保ViewModel能实时获取最新的错误状态:
public void Validate() { lock (_lock) { // 原有验证逻辑保持不变... // 新增:通知HasErrors属性变更 RaisePropertyChanged(nameof(HasErrors)); } }
2. 调整XAML绑定配置
把ValidatesOnNotifyDataErrors设为True(否则UI不会显示错误标记),同时保留UpdateSourceTrigger=Explicit确保输入过程中不自动更新模型:
<TextBox x:Name="ModelTextBox" Text="{Binding Car.Model, ValidatesOnNotifyDataErrors=True, UpdateSourceTrigger=Explicit}"/>
3. 更新SaveCommand逻辑:先同步输入到模型,再触发验证
因为UpdateSourceTrigger=Explicit,TextBox的输入不会自动同步到Model属性,所以在调用验证前,需要手动触发绑定源更新,再执行验证:
public ICommand SaveCommand => new RelayCommand(() => { // 步骤1:手动同步TextBox输入到Model var window = Application.Current.Windows.OfType<YourWindow>().FirstOrDefault(); if (window != null) { var modelTextBox = window.FindName("ModelTextBox") as TextBox; modelTextBox?.GetBindingExpression(TextBox.TextProperty)?.UpdateSource(); } // 步骤2:触发模型验证 Car.Validate(); // 步骤3:检查错误,有错误则终止保存 if (Car.HasErrors) { return; } // 执行保存逻辑... });
优化提示(可选,更贴合MVVM)
如果不想在ViewModel中直接操作UI元素,可以:
- 将
UpdateSourceTrigger改为LostFocus,这样输入时离开TextBox会自动更新模型,但依然不会触发验证(因为我们已经移除了自动验证逻辑) - 或者在ViewModel中为Model属性添加对应的命令参数,通过命令传递输入值,但手动更新绑定源是最直接的适配方案。
4. 确保初始化时不触发验证
现在因为移除了RaisePropertyChanged中的自动验证调用,初始化Car时(即使Model属性为空)也不会触发验证,只有点击保存按钮时才会执行验证并显示错误标记,完全符合你的需求。
内容的提问来源于stack exchange,提问作者user1702369
相关产品推荐
相关产品推荐

