在我看来,DataGrid
仅应用ValidationRule
定义为行验证规则
<DataGrid.RowValidationRules>
...
</DataGrid.RowValidationRules>
如果用户输入。我的视图模型实现了INotifyDataErrorInfo
,并且由于某些asynchrounus后台操作,单元格的值可能无效。单元级别的验证与ValidatesOnNotifyDataErrors = true
和我的自定义验证样式完美匹配。但是,如果我手动进行任意输入(即,我开始编辑单元格并按Enter键),则检查单元格中是否存在可能无效数据的行验证规则将仅更新(然后将行标记为无效)。是否有可能手动触发单个/特定行的行验证?这种行为是预期的行为吗?在单元格无效的情况下,数据网格是否应该重新验证?
这真的让我感到很震惊。我使用IDataErrorInfo
尝试了相同的方法来验证DataGrid
没有错误。下面是一个非常简单的WPF应用程序。可以验证行验证仅在用户更改突出显示的单元格时触发。有没有办法自己触发行验证?唯一的解决方案&#34;会减少细胞水平的验证。为此,我创建了一个虚拟/只读对象属性,它聚合了该行的所有错误。我使用INotifyDataErrorInfo
并在使用虚拟属性名称调用GetErrors
时返回所有错误。但是,这不是解决方案!整个WPF围绕验证构建。 VisualStateManager
依赖于内部验证,......
Person.cs
class Person : IDataErrorInfo, INotifyPropertyChanged
{
private string _name;
public string this[string columnName]
{
get
{
string error = null;
switch(columnName)
{
case nameof(Name):
if (string.IsNullOrWhiteSpace(Name))
{
error = "Name is empty";
}
break;
}
return error;
}
}
public string Name
{
get { return _name; }
set { _name = value; OnPropertyChanged(); }
}
public string Error
{
get { return null; }
}
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
if(propertyName != null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
} else
{
throw new ArgumentNullException();
}
}
}
PersonsViewModel.cs
class PersonsViewModel
{
private ObservableCollection<Person> _personsList;
public ObservableCollection<Person> PersonsList
{
get { return _personsList ?? (_personsList = new ObservableCollection<Person>()); }
}
public PersonsViewModel()
{
PersonsList.Add(new Person()
{
Name = "Bob"
});
PersonsList.Add(new Person()
{
Name = "Alice"
});
PersonsList.Add(new Person()
{
Name = "Max"
});
}
}
MainWindow.xaml
<Window x:Class="DataGridTesting.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:DataGridTesting"
mc:Ignorable="d"
Title="MainWindow" Height="200" Width="300">
<Grid>
<StackPanel Orientation="Vertical">
<DataGrid ItemsSource="{Binding PersonsList, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}" AutoGenerateColumns="False">
<DataGrid.RowValidationRules>
<DataErrorValidationRule ValidatesOnTargetUpdated="True" ValidationStep="CommittedValue"/>
</DataGrid.RowValidationRules>
<DataGrid.Columns>
<DataGridTextColumn Header="Person" Binding="{Binding Path=Name, UpdateSourceTrigger=LostFocus, ValidatesOnDataErrors=True}"/>
</DataGrid.Columns>
</DataGrid>
<Button x:Name="MakeInvalidButton" Click="MakeInvalidButton_Click" Content="Make me invalid"/>
</StackPanel>
</Grid>
</Window>
MainWindow.xaml.cs
/// <summary>
/// Interaktionslogik für MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private PersonsViewModel viewModel;
public MainWindow()
{
InitializeComponent();
viewModel = new PersonsViewModel();
this.DataContext = viewModel;
}
private void MakeInvalidButton_Click(object sender, RoutedEventArgs e)
{
var alice = viewModel.PersonsList.Where(p => p.Name.StartsWith("Alice")).First();
if (alice != null)
{
alice.Name = string.Empty;
}
}
}