= new Dictionary<string, List<string>>();
Свойство HasErrors должно возвращать true, если в словаре присутствуют любые ошибки, что легко достигается следующим образом:
public bool HasErrors => _errors.Any();
Создайте вспомогательный метод для инициирования события ErrorsChanged (подобно инициированию события PropertyChanged):
private void OnErrorsChanged(string propertyName)
{
ErrorsChanged?.Invoke(this,
new DataErrorsChangedEventArgs(propertyName));
}
Как упоминалось ранее, метод 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<string> { error });
}
private void AddErrors(
string propertyName, IList<string> errors)
{
if (errors == null || !errors.Any())
{
return;
}
var changed = false;
if (!_errors.ContainsKey(propertyName))
{
_errors.Add(propertyName, new List<string>());
changed = true;
}
foreach (var err in errors)
(window.adrunTag = window.adrunTag || []).push({v: 1, el: 'adrun-4-390', c: 4, b: 390})
{
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 для свойств, что делает код труднее в чтении и сопровождении.