更新源/绑定后重新验证DataGrid的行

时间:2017-09-03 18:48:27

标签: c# wpf wpfdatagrid

在我看来,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;
        }
    }
}

0 个答案:

没有答案