当其中任何属性发生变化时,如何验证多个属性?

Rac*_*hel 21 validation wpf idataerrorinfo

我有两个日期字段:StartDate和EndDate.StartDate必须早于EndDate.

如果用户将StartDate更改为大于EndDate的值,则DatePicker周围会出现红色边框,反之亦然.如果用户更改第二个框以使日期范围现在正确,则第一个框仍然具有验证错误.

如果其中任何一个更改,我如何验证这两个日期字段?

在此输入图像描述

我正在使用 IDataErrorInfo

public string GetValidationError(string propertyName)
{
    switch (propertyName)
    {
        case "StartDate":
            if (StartDate > EndDate)
                s = "Start Date cannot be later than End Date";
            break;

        case "EndDate":
            if (StartDate > EndDate)
                s = "End Date cannot be earlier than Start Date";
            break;
    }

    return s;
}
Run Code Online (Sandbox Code Playgroud)

我不能简单地引发一个PropertyChange事件,因为当它们中的任何一个发生变化时我需要验证这两个字段,因此让它们两个为另一个引发一个PropertyChange事件将陷入无限循环.

如果另一个日期返回验证错误,我也不喜欢清除Date字段的想法.

Rac*_*hel 15

最简单的方法是PropertyChanged在setter中为两个需要验证的属性(如bathineni建议)提出通知

private DateTime StartDate
{
    get { return _startDate; }
    set
    {
        if (_startDate != value)
        {
            _startDate = value;
            RaisePropertyChanged("StartDate");
            RaisePropertyChanged("EndDate");
        }
    }
}

private DateTime EndDate
{
    get { return _endDate; }
    set
    {
        if (_endDate!= value)
        {
            _endDate= value;
            RaisePropertyChanged("StartDate");
            RaisePropertyChanged("EndDate");
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

但是,如果这对你不起作用,我想出了一种方法来一起验证一组属性,虽然你的类必须实现INotifyPropertyChanging除了INotifyPropertyChanged(我正在使用EntityFramework,默认情况下它们的类实现两个接口)

扩展方法

public static class ValidationGroup
{
    public delegate string ValidationDelegate(string propertyName);
    public delegate void PropertyChangedDelegate(string propertyName);

    public static void AddValidationGroup<T>(this T obj, 
        List<string> validationGroup, bool validationFlag,
        ValidationDelegate validationDelegate, 
        PropertyChangedDelegate propertyChangedDelegate)
        where T : INotifyPropertyChanged, INotifyPropertyChanging
    {

        // This delegate runs before a PropertyChanged event. If the property
        // being changed exists within the Validation Group, check for validation
        // errors on the other fields in the group. If there is an error with one
        // of them, set a flag to true.
        obj.PropertyChanging += delegate(object sender, PropertyChangingEventArgs e)
        {
            if (validationGroup.Contains(e.PropertyName))
            {
                foreach(var property in validationGroup)
                {
                    if (validationDelegate(property) != null)
                    {
                        validationFlag = true;
                        break;
                    }
                }
            }
        };

        // After the Property gets changed, if another field in this group was
        // invalid prior to the change, then raise the PropertyChanged event for 
        // all other fields in the Validation Group to update them.
        // Also turn flag off so it doesn't get stuck in an infinite loop
        obj.PropertyChanged += delegate(object sender, PropertyChangedEventArgs e)
        {
            if (validationGroup.Contains(e.PropertyName))
            {
                if (validationFlag && validationDelegate(e.PropertyName) == null)
                {
                    validationFlag = false;
                    foreach(var property in validationGroup)
                    {
                        propertyChangedDelegate(property);
                    }
                }
            }
        };
    }
}
Run Code Online (Sandbox Code Playgroud)

要使用它,请将以下调用添加到应该一起验证一组属性的任何类的构造函数中.

this.AddValidationGroup(
    new List<string> { "StartDate", "EndDate" },
    GetValidationError, OnPropertyChanged);
Run Code Online (Sandbox Code Playgroud)

我在Validation Group中测试了最多3个属性,它似乎工作正常.