当ItemsControl存在验证错误时禁用Button的实现方案
解决方案:通过INotifyDataErrorInfo实现验证错误联动按钮禁用
你当前使用的ValidationRules属于视图层验证,默认情况下只有验证通过时才会更新绑定源,导致ViewModel无法感知错误状态。改用INotifyDataErrorInfo将验证逻辑移至ViewModel层,既能保留错误提示,又能统一管理所有Order的错误状态,进而实现按钮的禁用控制。
步骤1:让Order类实现INotifyDataErrorInfo
修改Order类,继承BindableBase的同时实现INotifyDataErrorInfo接口,将ID的验证逻辑内嵌到属性变更中,并维护错误状态:
public class Order : BindableBase, INotifyDataErrorInfo { private int? _id; private readonly Dictionary<string, List<string>> _errors = new Dictionary<string, List<string>>(); public int? ID { get => _id; set { if (SetProperty(ref _id, value)) { ValidateID(value); } } } // 替换为你的实际验证规则 private void ValidateID(int? value) { var propertyName = nameof(ID); _errors.Remove(propertyName); if (!value.HasValue) { AddError(propertyName, "ID不能为空"); } else if (value < 1 || value > 100) { AddError(propertyName, "ID必须在1-100范围内"); } OnErrorsChanged(propertyName); } private void AddError(string propertyName, string errorMessage) { if (!_errors.ContainsKey(propertyName)) { _errors[propertyName] = new List<string>(); } _errors[propertyName].Add(errorMessage); } public bool HasErrors => _errors.Any(kv => kv.Value.Any()); public event EventHandler<DataErrorsChangedEventArgs>? ErrorsChanged; public IEnumerable GetErrors(string? propertyName) { if (string.IsNullOrEmpty(propertyName) || !_errors.ContainsKey(propertyName)) { return Enumerable.Empty<string>(); } return _errors[propertyName]; } protected virtual void OnErrorsChanged(string propertyName) { ErrorsChanged?.Invoke(this, new DataErrorsChangedEventArgs(propertyName)); } }
步骤2:在ViewModel中跟踪错误状态并控制按钮
修改ViewModel,监听OrderCollection的集合变化以及每个Order的错误变更事件,实时更新按钮的启用状态:
public class YourViewModel : BindableBase { private bool _isButtonEnabled = true; public ObservableCollection<Order> OrderCollection { get; } = new ObservableCollection<Order>(); public bool IsButtonEnabled { get => _isButtonEnabled; set => SetProperty(ref _isButtonEnabled, value); } public YourViewModel() { OrderCollection.CollectionChanged += OrderCollection_CollectionChanged; } private void OrderCollection_CollectionChanged(object? sender, NotifyCollectionChangedEventArgs e) { if (e.NewItems != null) { foreach (Order order in e.NewItems) { order.ErrorsChanged += Order_ErrorsChanged; } } if (e.OldItems != null) { foreach (Order order in e.OldItems) { order.ErrorsChanged -= Order_ErrorsChanged; } } UpdateButtonEnabledState(); } private void Order_ErrorsChanged(object? sender, DataErrorsChangedEventArgs e) { UpdateButtonEnabledState(); } private void UpdateButtonEnabledState() { // 检查所有Order是否无错误 IsButtonEnabled = OrderCollection.All(order => !order.HasErrors); } }
步骤3:调整XAML绑定
移除原视图层的ValidationRules,开启ValidatesOnNotifyDataErrors(默认已开启,显式声明更清晰),并将按钮的IsEnabled绑定到ViewModel的对应属性:
<Grid> <ItemsControl x:Name="MyItemsControl" ItemsSource="{Binding Path=OrderCollection}"> <ItemsControl.ItemTemplate> <DataTemplate> <TextBox x:Name="MyTextBox" Text="{Binding Path=ID, Mode=TwoWay, ValidatesOnNotifyDataErrors=True, UpdateSourceTrigger=PropertyChanged}"> </TextBox> </DataTemplate> </ItemsControl.ItemTemplate> </ItemsControl> <Button x:Name="MyButton" IsEnabled="{Binding IsButtonEnabled}"> 提交 </Button> </Grid>
关键说明
UpdateSourceTrigger=PropertyChanged:设置为实时验证,输入内容变化时立即触发验证,若需要失去焦点时验证可改为LostFocus。- 错误提示:WPF会自动识别
INotifyDataErrorInfo的错误状态,为TextBox显示默认的红色错误边框,无需额外配置。 - 状态联动:ViewModel通过监听所有Order的错误变更,实时更新按钮启用状态,确保任意Order存在错误时按钮禁用。
内容的提问来源于stack exchange,提问作者Alexey Titov
相关产品推荐
相关产品推荐

