inotifydataerrorinfo get all validation errors

2019-09-08 16:56发布

问题:

Currently I'm developing .net 4.5 wpf MVVM application with validation system handled by INotifyDataErrorInfo. At some point in application I have to check if there are any validation errors, currently it's done like this:

public class RootViewModel : BindableBase
{
     //class code

            if (designInformation.Technology == Technology.CVT)
            {
                if (designInformation.HasErrors) return;
                if (InfoInputViewModel.TrafoProperties.HasErrors) return;
                if (InfoInputViewModel.CapacitorVoltageTransformerViewModel.CapacitorVoltageDivider.HasErrors) return;
                if (InfoInputViewModel.CapacitorVoltageTransformerViewModel.IntermediateVoltageTransformer.HasErrors) return;
                if (SpecialDesignViewModel.SpecialDesignInformation.HasErrors) return;
                foreach (var item in InfoInputViewModel.SecondaryWindings.WindingsCollection)
                {
                    if (item.HasErrors) return;
                }

                performCalculationsCVT();
            }
}

And I'm looking for a way to simplify this code by getting all errors from model at once, but don't know where to start with this problem.

Bellow is implementation of INotifyDataErrorInfo interface i use.

public class ValidableBase : BindableBase, INotifyDataErrorInfo
{
    protected readonly Dictionary<string, ICollection<string>>
    _validationErrors = new Dictionary<string, ICollection<string>>();

    #region INotifyDataErrorInfo Implementation

    public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;

    protected void RaiseErrorsChanged(string propertyName)
    {
        if (ErrorsChanged != null)
            ErrorsChanged(this, new DataErrorsChangedEventArgs(propertyName));
    }

    public IEnumerable GetErrors(string propertyName)
    {
        if (string.IsNullOrEmpty(propertyName) || !_validationErrors.ContainsKey(propertyName))
            return null;

        return _validationErrors[propertyName];
    }

    public bool HasErrors
    {
        get { return _validationErrors.Count > 0; }
    }

    public void AddError(string propertyName, string message)
    {
        if (_validationErrors.ContainsKey(propertyName))
        {
            string value = _validationErrors[propertyName].First();
            value += Environment.NewLine;
            value += message;
            _validationErrors[propertyName] = new List<string> { value };
        }
        else
            _validationErrors[propertyName] = new List<string> { message };

        RaiseErrorsChanged(propertyName);
    }

    public void RemoveError(string propertyName)
    {
        _validationErrors.Remove(propertyName);

        RaiseErrorsChanged(propertyName);
    }

    [XmlIgnore]
    public Dictionary<string, ICollection<string>> ValidationErrors 
    {
        get { return this._validationErrors; }
    }

    #endregion 
}

}

回答1:

Obviously, the base class has no idea what properties a particular child class has, let alone if they implement INDEI. You'll have to write the logic to do this. There are many ways you can accomplish this.

For me, I'd add an abstract method to the base class thusly

abstract class ValidableBase 
{
    // snip
    protected abstract IEnumerable<ValidableBase> GetValidableProperties();
    // snip

Then change HasErrors to call HasErrors recursively on the results of the above call

public bool HasErrors
{
    get { return _validationErrors.Count > 0 ||
          GetValidableProperties().Any(x => x.HasErrors); }
}

An example implementation of GetValidableProperties might be

protected override IEnumerable<ValidableBase> GetValidableProperties()
{
    yield return SomeProperty; // a Validable property
    yield return SomeOtherProperty; // this too
    foreach(var prop in SomeCollectionProperty) // collection of Validable
        yield return prop;
}

Lastly, I'd rename Validable to Validatable, which is the correct (english) spelling. If I were Spanish or French, I'd probably skip that last step.



标签: c# wpf mvvm