Как упоминалось ранее, метод GetErrors() должен возвращать любые ошибки в словаре, когда в параметре передается пустая строка или null. Если передается допустимое значение propertyName, то возвращаются ошибки, обнаруженные для указанного свойства. Если параметр не соответствует какому-либо свойству (или ошибки для свойства отсутствуют), тогда метод возвратит null.
public IEnumerable GetErrors(string propertyName)
{
if (string.IsNullOrEmpty(propertyName))
{
return _errors.Values;
}
return _errors.ContainsKey(propertyName)
? _errors[propertyName]
: null;
}
Финальный набор вспомогательных методов будет добавлять одну или большее число ошибок для свойства либо очищать все ошибки для свойства (или всех свойств). Не следует забывать о вызове вспомогательного метода OnErrorsChanged() каждый раз, когда словарь изменяется.
private void AddError(string propertyName, string error)
{
AddErrors(propertyName, new List
}
private void AddErrors(
string propertyName, IList
{
if (errors == null || !errors.Any())
{
return;
}
var changed = false;
if (!_errors.ContainsKey(propertyName))
{
_errors.Add(propertyName, new List
changed = true;
}
foreach (var err in errors)
{
if (_errors[propertyName].Contains(err)) continue;
_errors[propertyName].Add(err);
changed = true;
}
if (changed)
{
OnErrorsChanged(propertyName);
}
}
protected void ClearErrors(string propertyName = "")
{
if (string.IsNullOrEmpty(propertyName))
{
_errors.Clear();
}
else
{
_errors.Remove(propertyName);
}
OnErrorsChanged(propertyName);
}
Возникает вопрос: когда приведенный выше код активизируется? Механизм привязки прослушивает событие ErrorsChanged и обновляет пользовательский интерфейс, если в коллекции ошибок для выражения привязки возникает изменение. Но код проверки по-прежнему нуждается в триггере для запуска. Доступны два механизма, которые обсуждаются далее.
Использование интерфейса INotifyDataErrorInfo для проверки достоверности
Одним из мест выполнения проверки на предмет ошибок являются блоки set для свойств, как демонстрируется в показанном ниже примере, упрощенном до единственной проверки на равенство свойства Make значению ModelT:
public string Make
{
get { return _make; }
set
{
if (value == _make) return;
_make = value;
if (Make == "ModelT")
{
AddError(nameof(Make), "Too Old");
}
else
{
ClearErrors(nameof(Make));
}
OnPropertyChanged(nameof(Make));
OnPropertyChanged(nameof(Color));
}
}
Основная проблема такого подхода состоит в том, что вам приходится сочетать логику проверки достоверности с блоками set для свойств, что делает код труднее в чтении и сопровождении.
Комбинирование IDataErrorInfo С INotifyDataErrorInfo для проверки достоверности
В предыдущем разделе было показано, что реализацию интерфейса IDataErrorInfo можно добавить к частичному классу, т.е. обновлять блоки set не понадобится. Кроме того, индексатор автоматически вызывается при возникновении события PropertyChanged в свойстве. Комбинирование IDataErrorInfo и INotifyDataErrorInfo предоставляет дополнительные возможности для проверки достоверности из INotifyDataErrorInfo, а также отделение от блоков set, обеспечиваемое IDataErrorInfo.
Цель применения IDataErrorInfo не в том, чтобы запускать проверку достоверности, а в том, чтобы гарантировать вызов кода проверки, который задействует INotifyDataErrorInfo, каждый раз, когда для объекта генерируется событие PropertyChanged. Поскольку интерфейс IDataErrorInfo не используется для проверки достоверности, необходимо всегда возвращать string.Empty из индексатора. Модифицируйте индексатор и вспомогательный метод CheckMakeAndColor() следующим образом: