Базовый класс для общих процедур проверки
Вы можете использовать DataAnnotations , если вы выполните некоторые операции в реализации IDataErrorInfo
.Например, вот модель базового представления, которую я часто использую (из Windows Forms, но вы можете экстраполировать):
public class ViewModelBase : IDataErrorInfo, INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public SynchronizationContext Context
{
get;
set;
}
public bool HasErrors
{
get
{
return !string.IsNullOrWhiteSpace(this.Error);
}
}
public string Error
{
get
{
var type = this.GetType();
var modelClassProperties = TypeDescriptor
.GetProperties(type)
.Cast();
return
(from modelProp in modelClassProperties
let error = this[modelProp.Name]
where !string.IsNullOrWhiteSpace(error)
select error)
.Aggregate(new StringBuilder(), (acc, next) => acc.Append(" ").Append(next))
.ToString();
}
}
public virtual string this[string columnName]
{
get
{
var type = this.GetType();
var modelClassProperties = TypeDescriptor
.GetProperties(type)
.Cast();
var errorText =
(from modelProp in modelClassProperties
where modelProp.Name == columnName
from attribute in modelProp.Attributes.OfType()
from displayNameAttribute in modelProp.Attributes.OfType()
where !attribute.IsValid(modelProp.GetValue(this))
select attribute.FormatErrorMessage(displayNameAttribute == null ? modelProp.Name : displayNameAttribute.DisplayName))
.FirstOrDefault();
return errorText;
}
}
protected void NotifyPropertyChanged(string propertyName)
{
if (string.IsNullOrWhiteSpace(propertyName))
{
throw new ArgumentNullException("propertyName");
}
if (!this.GetType().GetProperties().Any(x => x.Name == propertyName))
{
throw new ArgumentException(
"The property name does not exist in this type.",
"propertyName");
}
var handler = this.PropertyChanged;
if (handler != null)
{
if (this.Context != null)
{
this.Context.Post(obj => handler(this, new PropertyChangedEventArgs(propertyName)), null);
}
else
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
}
Пример использования:
public class LogOnViewModel : ViewModelBase
{
[DisplayName("User Name")]
[Required]
[MailAddress] // This is a custom DataAnnotation I wrote
public string UserName
{
get
{
return this.userName;
}
set
{
this.userName = value;
this.NotifyPropertyChanged("UserName");
}
}
[DisplayName("Password")]
[Required]
public string Password
{
get; // etc
set; // etc
}
}
Использование IDataErrorInfoдля одноразовых процедур проверки
Если честно, в итоге я использую как аннотации, так и переключатель.Я использую аннотации для простых проверок, и если у меня есть более сложные проверки (такие как «проверять только это свойство, если установлено это другое свойство»), я прибегну к переключателю в переопределении индекса this[]
.Этот шаблон часто выглядит следующим образом (просто вымышленный пример, он не имеет смысла:
public override string this[string columnName]
{
get
{
// Let the base implementation run the DataAnnotations validators
var error = base[columnName];
// If no error reported, run my custom one-off validations for this
// view model here
if (string.IsNullOrWhiteSpace(error))
{
switch (columnName)
{
case "Password":
if (this.Password == "password")
{
error = "See an administrator before you can log in.";
}
break;
}
}
return error;
}
Некоторые мнения
Что касается указания имен свойств в виде строк: вы могли бы сделатьс лямбдами, но мой честный совет: просто преодолеть это . Вы можете заметить, что в моем ViewModelBase
мой маленький помощник NotifyPropertyChanged
выполняет магию отражения, чтобы убедиться, что у меня нет жира-предоставил имя свойства - это помогает мне быстрее обнаружить ошибку привязки данных, а не бегать в течение 20 минут, чтобы выяснить, что я пропустил.
Ваше приложение получит спектр проверки от piddlyтакие вещи, как «требуется» или «максимальная длина» на уровне свойств пользовательского интерфейса, до «требуется», только если что-то еще проверено »на другом уровне пользовательского интерфейса и вплоть до« имени пользователя не существует »на уровне домена / персистентности.Вы обнаружите, что вам придется искать компромисс между повторением небольшой логики проверки в пользовательском интерфейсе и добавлением большого количества метаданных в домене к дес.напишите сам пользовательский интерфейс, и вам придется найти компромисс в отношении того, как эти различные классы ошибок проверки отображаются для пользователя.
Надеюсь, что это поможет.Удачи!