MVVM - Валидация
Мы пытаемся выяснить валидацию в mvvm, делая валидацию в бизнес-логике или модели. Я реализовал валидацию по типу исключения в нашей бизнес-логике - здесь можно найти упрощенную диаграмму:
Если у нас есть много входных данных, которые не зависят друг от друга, проблем нет, выдается исключение, текстовое поле ловит его, помечая его границы красными для каждого неправильного ввода. Однако, когда у нас есть зависимые ценности, у нас проблемы. например
Value1 и Value2 в модели не должны быть одинаковыми, поэтому у нас есть функция проверки в каждом из тех, кто ищет значение equals, и выдает исключение, если это происходит
Теперь, если мы установим Value1 в 0 и Value2 в 1, все в порядке
Значение 1 устанавливается в графическом интерфейсе на 1 -> это помечается красным, потому что проверка других значений не запускается, поэтому значение 2 в графическом интерфейсе не помечается как неисправное
Значение 2 установлено в 2 в графическом интерфейсе, теперь мы достигли допустимого состояния, но только значение 2 проверяется, поэтому значение 1 по-прежнему помечается как неисправное.
Существует ли общая схема решения этой проблемы? мы не хотим вводить зависимость в GUI между двумя текстовыми полями, потому что эта логика должна присутствовать только на уровне бизнес-логики.
Вместо реализации валидации по исключению можно также реализовать интерфейс IDataErrorInfo, но проблема все еще существует, нет способа заставить зависимые значения снова проверить свои значения, по крайней мере, тот, который я могу видеть:)
Любая помощь приветствуется
ура, Манни
[очистка, удален ненужный шаг]
15.11.2010 - Часть 2
хорошо, большое переосмысление здесь, мы идем с бизнес-уровня. вот наша текущая запланированная конфигурация:(изображение немного уменьшено, пожалуйста, откройте его в отдельном окне, чтобы показать его в полном размере) все более или менее понятно, кроме как уведомить все клоны моделей моделей / моделей различных редакторов, если модель данных под бизнес логика меняется. Один из способов сделать это - отслеживать клонированные модели в бизнес-логике, которая их создает. Когда модель данных изменяется с помощью commit логики бизнес-логики, все другие зарегистрированные клоны модели могут быть уведомлены об изменениях и распространять их дальше. в качестве альтернативы бизнес-логика может опубликовать событие, на которое подписываются все модели представления, чтобы они также получили изменения - может кто-нибудь подсказать мне, что лучше?
Еще раз спасибо за помощь, извините, я так заблокирован;)
2 ответа
Вы можете рассмотреть возможность использования интерфейса System.ComponentModel.IDataErrorInfo. Этот очень удобный интерфейс дает вам возможность:
- выполнить проверку в соответствии с MVVM
- выполнить пользовательскую проверку для любого конкретного поля (проверка может проверить несколько значений, если вы этого хотите)
- привязать ваш пользовательский интерфейс к ошибкам проверки
Вы реализуете IDataErrorInfo в своей модели представления (или даже фактически в базе моделей представления и переопределяете ее в своих производных моделях представления). Из-за характера привязки данных все значения, которые мне нужно проверить, находятся в модели представления, и я могу протестировать любую их комбинацию. Конечно, у вас все еще есть подтверждение на вашем бизнес-уровне, но вам больше не нужно совершать поездку на свой бизнес-уровень (или модель) только для того, чтобы выполнить некоторую проверку.
Вот быстрый пример с экрана (WPF), который собирает некоторые пользовательские данные и выполняет базовую проверку на них:
Код C#:
#region IDataErrorInfo Members
/// <summary>
/// Gets an error message indicating what is wrong with this object.
/// </summary>
/// <value></value>
/// <returns>An error message indicating what is wrong with this object. The default is an empty string ("").</returns>
public override string Error
{
get
{
return this["UserCode"] + this["UserName"] + this["Password"] + this["ConfirmedPassword"] + this["EmailAddress"];
}
}
/// <summary>
/// Gets the <see cref="System.String"/> with the specified column name.
/// </summary>
/// <value></value>
public override string this[string columnName]
{
get
{
switch (columnName)
{
case "UserCode":
if (!string.IsNullOrEmpty(UserCode) && UserCode.Length > 20)
return "User Code must be less than or equal to 20 characters";
break;
case "UserName":
if (!string.IsNullOrEmpty(UserCode) && UserCode.Length > 60)
return "User Name must be less than or equal to 60 characters";
break;
case "Password":
if (!string.IsNullOrEmpty(Password) && Password.Length > 60)
return "Password must be less than or equal to 60 characters";
break;
case "ConfirmedPassword":
if (Password != ConfirmedPassword)
return Properties.Resources.ErrorMessage_Password_ConfirmedPasswordDoesntMatch;
break;
case "EmailAddress":
if (!string.IsNullOrEmpty(EmailAddress))
{
var r = new Regex(_emailRegex);
if (!r.IsMatch(EmailAddress))
return Properties.Resources.ErrorMessage_Email_InvalidEmailFormat;
}
break;
}
return string.Empty;
}
}
#endregion
и вот разметка XAML для двух текстовых полей на странице (обратите внимание, в частности, ValidatesOnDataErrors
а также ValidatesOnExceptions
свойства в Text
связывание):
<TextBox Name="UserCodeTextBox"
Text="{Binding UserCode,
Mode=TwoWay,
UpdateSourceTrigger=PropertyChanged,
ValidatesOnDataErrors=True,
ValidatesOnExceptions=True,
NotifyOnSourceUpdated=True,
NotifyOnTargetUpdated=True}"
GotFocus="Input_GotFocus"
VerticalAlignment="Top"
Margin="165,0,150,0"
CharacterCasing="Upper"
/>
<TextBox Name="UserNameTextBox"
Text="{Binding UserName,
Mode=TwoWay,
UpdateSourceTrigger=PropertyChanged,
ValidatesOnDataErrors=True,
ValidatesOnExceptions=True,
NotifyOnSourceUpdated=True,
NotifyOnTargetUpdated=True}"
GotFocus="Input_GotFocus"
VerticalAlignment="Top"
Margin="165,30,0,0"
/>
Существует ли общая схема решения этой проблемы? мы не хотим вводить зависимость в GUI между двумя текстовыми полями, потому что эта логика должна присутствовать только на уровне бизнес-логики.
Value1
а такжеValue2
являются взаимозависимыми из-за условия "Значение1 и Значение2 в модели не должны быть одинаковыми".Это означает, что когда
Value2
изменения,Value1
тоже меняется, и наоборот! На самом деле, когдаValue2
изменения,Value1
результат проверки изменяется, но это близко к предыдущему утверждению.Value1
а такжеValue2
сеттеры должны уведомить об обоихValue1
а такжеValue2
изменение собственности.Представление должно перечитать и повторно проверить оба значения и очистить ошибочную метку.
Не уверен если
WPF
сделает это, если обнаружит, что событие уведомления было инициировано, но значение фактически не изменилось.