Как принудительно обновить ошибки проверки в представлении ViewModel с помощью IDataErrorInfo?
У меня есть окно на основе MVVM со многими элементами управления, а моя модель реализует IDataErrorInfo
.
Существует также кнопка SaveCommand
, которая выполняет проверку путем анализа свойства Model.Error
.
В представлении отображается красная рамка по умолчанию вокруг элементов управления с ошибками только при изменении значения конкретного элемента управления или когда я уведомляю об изменении этого свойства с помощью PropertyChanged.
Как я могу заставить View отображать все ошибки проверки, даже когда я не касался элементов управления?
Все мои привязки проверки включают ValidatesOnDataErrors=True, NotifyOnValidationError=True
.
Я знаю, что одно решение состоит в том, чтобы иметь агрегатный ящик со всеми ошибками, но я бы предпочел отображать ошибки на основе управления.
Я не хочу запускать Model.NotifyPropertyChanged
для каждого свойства привязки из ViewModel.
Я использую WPF 4.0, а не Silverlight, поэтому INotifyDataErrorInfo
не будет работать.
Ответы
Ответ 1
Вы упомянули, что не хотите поднять свойство, измененное для свойств, к которым вы привязываетесь, но это действительно самый простой способ выполнить это. Вызов свойстваChanged без параметра будет повышаться для всех свойств в вашей модели просмотра.
В качестве альтернативы вы можете обновить привязки (и принудительно повторить проверку) на любом элементе управления следующим образом:
myControl.GetBindingExpression(ControlType.ControlProperty).UpdateSource();
Ответ 2
Лучшее решение, которое я нашел до сих пор, заключается в том, чтобы изменить DataContext на null и вернуться к экземпляру ViewModel.
Это приводит к обновлению элементов управления в представлении с DataContext
, привязанным к InnerViewModel
:
public void ForceUpdateErrors() {
var tmpInnerVM = _mainViewModel.InnerViewModel;
_mainViewModel.InnerViewModel = null;
_mainViewModel.InnerViewModel = tmpInnerVM;
}
Рекомендуется проверить, не потеряны ли данные после этого трюка. У меня был случай, когда этот код вызвал обновление исходного кода для ComboBox.SelectedItem с нулевым значением, но мне удалось его решить. Это было вызвано использованием BindingProxy на основе ресурсов и порядком распространения DataContext=null
по иерархии управления.
Ответ 3
Этот "Hack" временно работал у меня, чтобы принудительно активировать событие InotifyChanged, просто назначьте этот элемент управления своим собственным контентом. Сделайте это перед оценкой функции HasError привязок. Например, текстовое поле будет:
((TextBox)child).Text = ((TextBox)child).Text;
И затем полный пример (прежде чем я узнаю, что это не правда, MVVM, я просто получил ручку на сетке, чтобы упростить отображение этого snipet кода)
public bool Validate()
{
bool hasErr = false;
for (int i = 0; i != VisualTreeHelper.GetChildrenCount(grd); ++i)
{
DependencyObject child = VisualTreeHelper.GetChild(grd, i);
if (child is TextBox)
{
bool pp = BindingOperations.IsDataBound(child, TextBox.TextProperty);
if (pp)
{
((TextBox)child).Text = ((TextBox)child).Text;
hasErr = BindingOperations.GetBindingExpression(child, TextBox.TextProperty).HasError;
System.Collections.ObjectModel.ReadOnlyCollection<ValidationError> errors = BindingOperations.GetBindingExpression(child, TextBox.TextProperty).ValidationErrors;
if (hasErr)
{
main.BottomText.Foreground = Brushes.Red;
main.BottomText.Text = BindingOperations.GetBinding(child, TextBox.TextProperty).Path.Path.Replace('.', ' ') + ": " + errors[0].ErrorContent.ToString();
return false;
}
}
}
if (child is DatePicker)
{
...
}
}
return true;
}