WPF MVVM:DataGrid存在验证错误时禁用Save按钮问题
问题:DataGrid存在验证错误时禁用Save按钮,删除错误行后按钮无法恢复
开发了一个供用户编辑后保存至数据库的DataGrid,希望当DataGrid存在验证错误(如数字字段输入字符)时禁用Save按钮。尝试过两种方案:直接绑定Validation.HasError到DataGrid无效;另一种方案在删除存在错误的行后,按钮会一直处于禁用状态无法恢复。
现有DataGrid代码
<DataGrid x:Name="dataGrid" ItemsSource="{Binding DataList}" SelectedItem="{Binding SelectedData}" AutoGenerateColumns="False" CanUserAddRows="False" CanUserDeleteRows="False"> <DataGrid.Columns> <DataGridTemplateColumn Header="MustBeNumber"> <DataGridTemplateColumn.CellTemplate> <DataTemplate> <TextBox Text="{Binding Path=NUMBER_FIELD, UpdateSourceTrigger=PropertyChanged}" > </DataTemplate> </DataGridTemplateColumn.CellTemplate> </DataGridTemplateColumn> </DataGrid.Columns> </DataGrid>
模型类(ViewModel包含该模型的ObservableCollection)
public class Data : ObservableObject { private int? _number_field; public int? NUMBER_FIELD { get { return _number_field; } set { _number_field = value; OnPropertyChanged("NUMBER_FIELD"); } } }
尝试过的无效代码
<Button Content="Save" Name="btnSave" Command="{Binding SaveCommand}"> <Button.Style> <Style TargetType="Button"> <Setter Property="IsEnabled" Value="False"/> <Style.Triggers> <MultiDataTrigger> <MultiDataTrigger.Conditions> <Condition Binding="{Binding Path=(Validation.HasError), ElementName=dataGrid}" Value="False"/> </MultiDataTrigger.Conditions> <Setter Property="IsEnabled" Value="True"/> </MultiDataTrigger> </Style.Triggers> </Style> </Button.Style> </Button>
解决方案:通过ViewModel跟踪验证状态 + 命令启用控制
步骤1:给模型添加验证支持
实现IDataErrorInfo接口,让模型自身处理字段验证,并暴露错误状态属性:
public class Data : ObservableObject, IDataErrorInfo { private int? _number_field; public int? NUMBER_FIELD { get { return _number_field; } set { _number_field = value; OnPropertyChanged(nameof(NUMBER_FIELD)); OnPropertyChanged(nameof(HasError)); } } // IDataErrorInfo 实现 public string Error => null; public string this[string columnName] { get { if (columnName == nameof(NUMBER_FIELD)) { // 验证逻辑:若转换失败(输入非数字)或为空则返回错误信息 if (_number_field == null) { return "数字字段不能为空"; } } return null; } } // 标识当前模型是否有验证错误 public bool HasError => !string.IsNullOrEmpty(this[nameof(NUMBER_FIELD)]); }
步骤2:在ViewModel中跟踪全局验证状态
ViewModel监听集合变化和模型属性变化,实时更新整体错误状态:
public class YourViewModel : ObservableObject { private ObservableCollection<Data> _dataList; public ObservableCollection<Data> DataList { get => _dataList; set { if (_dataList != null) { _dataList.CollectionChanged -= DataList_CollectionChanged; foreach (var item in _dataList) { item.PropertyChanged -= Item_PropertyChanged; } } _dataList = value; OnPropertyChanged(nameof(DataList)); if (_dataList != null) { _dataList.CollectionChanged += DataList_CollectionChanged; foreach (var item in _dataList) { item.PropertyChanged += Item_PropertyChanged; } } UpdateHasValidationErrors(); } } private bool _hasValidationErrors; public bool HasValidationErrors { get => _hasValidationErrors; set { _hasValidationErrors = value; OnPropertyChanged(nameof(HasValidationErrors)); SaveCommand.RaiseCanExecuteChanged(); } } public ICommand SaveCommand { get; } public YourViewModel() { SaveCommand = new RelayCommand(Save, () => !HasValidationErrors); DataList = new ObservableCollection<Data>(); } private void Save() { // 数据库保存逻辑 } private void DataList_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) { if (e.NewItems != null) { foreach (Data item in e.NewItems) { item.PropertyChanged += Item_PropertyChanged; } } if (e.OldItems != null) { foreach (Data item in e.OldItems) { item.PropertyChanged -= Item_PropertyChanged; } } UpdateHasValidationErrors(); } private void Item_PropertyChanged(object sender, PropertyChangedEventArgs e) { if (e.PropertyName == nameof(Data.HasError)) { UpdateHasValidationErrors(); } } private void UpdateHasValidationErrors() { HasValidationErrors = DataList.Any(item => item.HasError); } }
步骤3:修改绑定,启用验证并通过命令控制按钮
更新TextBox绑定以启用数据验证,按钮直接通过命令的CanExecute控制启用状态:
<!-- 更新DataGrid列的TextBox绑定 --> <TextBox Text="{Binding Path=NUMBER_FIELD, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}" /> <!-- 简化按钮代码 --> <Button Content="Save" Command="{Binding SaveCommand}" />
内容的提问来源于stack exchange,提问作者ozturk.brk
相关产品推荐
相关产品推荐

