2011-02-11 3 views
1

В настоящее время я использую интерфейс IDataErrorInfo для реализации проверки в приложении WPF. Индексатор, который является частью этого интерфейса позволяет проверить одно свойство, например, так:Проверка перекрестных свойств в WPF

public string this[string columnName] 
{ 
    get 
    { 
     switch (columnName) 
     { 
      case "LastName": 
       if (string.IsNullOrEmpty(this.LastName)) 
        return "LastName must not be empty."; 
       break; 
      // case, case, case, etc., etc. 
     } 
     return null; 
    } 
} 

Если ошибка проверки происходит отобразить звездочку с подсказкой рядом с TextBox.

Что делать, если у меня есть правила проверки, которые не имеют строгого отношения к одному свойству? Например, если объект домена, представляющий заказ, имеет дату отправки и дату счета, и я хочу проверить правильность того, что дата счета должна быть позже или равна дате отправки?

Конечно, я мог бы принудительно ввести это правило в индекс, проверив соотношение дважды, один раз для columnName «ShippingDate» и один раз для columnName «InvoiceDate», а затем пометить ошибку звездочкой на обоих полях ввода в пользовательском интерфейсе , например, так:

public string this[string columnName] 
{ 
    get 
    { 
     switch (columnName) 
     { 
      case "ShippingDate": 
      case "InvoiceDate": 
       if (this.ShippingDate > this.InvoiceDate) 
        return "Invoice date must not be before shipping date."; 
       break; 
     } 
     return null; 
    } 
} 

Но я предпочел бы иметь «уровень объекта» или «крест свойство» проверку независимо от индексатора (индексатор должен сообщать только недопустимое «одно свойства состояния») и отображать эти объекты уровня или взаимосвязи в отдельном интерфейсе.

Я надеялся, что свойство Error интерфейса IDataErrorInfo может иметь эту цель проверки уровня объекта. WPF вызывает индексатор для проверки свойств, когда я указываю ValidatesOnDataErrors=True в выражении Binding TextBox, например. Но я не мог найти способ сказать WPF вызвать свойство Error всякий раз, когда я изменяю некоторые данные в своих полях ввода. Может быть, мое предположение о цели этого свойства неверно?

Как я могу реализовать проверку перекрестных свойств в WPF?

Благодарим вас за предложения!

ответ

2

Что касается моего вопроса, если я могу настроить привязку, так что WPF автоматически проверяет Error свойство интерфейса IDataErrorInfo я нашел следующий отрицательный ответ here:

Вопрос от кого-то:

В принципе, я 'd хотел бы знать о свойстве связывания , которое вызовет тестирование IDataErrorInfo.Error способом, который ValidatesOnDataErrors вызывает тестирование IDataErrorInfo.Item.

Ответ от службы поддержки Microsoft Online Community:

Установка свойства Binding класса ValidatesOnDataErrors только испытания IDataErrorInfo.Item и не из IDataErrorInfo.Error.

связующая класс не обеспечивает свойство, чтобы проверить IDataErrorInfo.Error как свойство ValidatesOnDataErrors к чеке IDataErrorInfo.Item до сих пор.

Чтобы получить то, что лет хотят, мы должны установить привязки данных к IDataError.Error ...

Таким образом, Error свойство не имеет больше значения, чем мое собственное определение (например, CrossPropertyErrors) в доменах. WPF не поддерживает тестирование свойства Error простым способом.

Редактировать: Кавычки выше с марта 2008 года, поэтому очень вероятно, что это связано с .NET 3.5. Но я не мог найти никаких признаков того, что это изменилось в .NET 4.0.

Редактировать: Наконец, мне пришлось создать свою собственную рукописную привязку к свойству Error и заполнить ее соответствующими сообщениями об ошибках перекрестных свойств. Каждое изменение любого другого свойства класса повышает значение PropertyChanged Событие как измененного свойства, так и свойства Error, чтобы обновить сообщение об ошибке в пользовательском интерфейсе.

Edit 2

Это выглядит примерно так:

Model (или ViewModel) классов:

public class SomeModel : NotificationObject, IDataErrorInfo 
{ 
    private string _someProperty; 
    public string SomeProperty 
    { 
     get { return _someProperty; } 
     set 
     { 
      if (_someProperty != value) 
      { 
       _someProperty = value; 
       RaisePropertyChanged("SomeProperty", "Error"); 
       // That's the key: For every changed property a change 
       // notification also for the Error property is raised 
      } 
     } 
    } 
    // The above repeats for every property of the model 

    #region IDataErrorInfo Member 
    public string Error 
    { 
     get 
     { 
      var sb = new StringBuilder(); 
      // for example... 
      if (InvoiceDate < ShippingDate) 
       sb.AppendLine("InvoiceDate must not be before ShippingDate."); 

      // more cross-property validations... We have only one Error 
      // string, therefore we append the messages with 
      // sb.AppendLine("Another message...") ... etc. 
      // could all be moved into a separate validation class 
      // to keep the model class cleaner 

      return sb.ToString(); 
     } 
    } 

    public string this[string columnName] 
    { 
     get 
     { 
      switch (columnName) 
      { 
       case "ShippingDate": 
        // property-level validations 
       case "InvoiceDate": 
        // property-level validations 
       // etc. 
      } 
      return null; 
     } 
    } 
    #endregion 
} 

NotificationObject реализует RaisePropertyChanged:

public abstract class NotificationObject : INotifyPropertyChanged 
{ 
    #region INotifyPropertyChanged Member 
    public event PropertyChangedEventHandler PropertyChanged; 
    #endregion 

    protected virtual void RaisePropertyChanged(string propertyName) 
    { 
     PropertyChangedEventHandler handler = PropertyChanged; 
     if (handler != null) 
      handler(this, new PropertyChangedEventArgs(propertyName)); 
    } 

    protected void RaisePropertyChanged(params string[] propertyNames) 
    { 
     if (propertyNames == null) 
      throw new ArgumentNullException("propertyNames"); 

     foreach (var name in propertyNames) 
      RaisePropertyChanged(name); 
    } 

    // ... 
} 

Тогда в состязаться ж свойство Error обязан - например - в TextBlock, который отображает ошибки перекрестной собственности проверки:

<TextBlock Text="{Binding SomeModel.Error}" TextWrapping="Wrap" ... /> 

Итак: все изменённые свойства на модели будет оповещать WPF привязки двигателя о (потенциал) изменения свойство Error, вызывающее, следовательно, обновление текста проверки перекрестной собственности.

+0

не могли бы вы предоставить некоторый исходный код для этого? У меня такая же проблема ... – Rob

+0

@Rob: Я добавил краткий очерк о том, как выглядит материал, см. Мой вариант Edit 2 выше. – Slauma

Смежные вопросы