Silverlight 4: Обработка ошибок при связывании
Silverlight 3 поддерживал специальный механизм проверки данных при связывании с элементами управления – ValidatesOnException и NotifyOnValidationError. Первое свойство объекта типа Binding обеспечивало возможность визуального отображения ошибки (например, красный прямоугольник вокруг текстового поля), а второе – обеспечивало механизм перехвата и обработки ошибки в коде. Сама ошибка связывания должна была инициироваться исключением внутри класса, описывающего данные. То есть, если Вы выполняли связывание свойства FirstName класса Employee с текстовым полем, то обработку значения должно было выполнять само свойство и выбрасывать исключения всякий раз, когда устанавливаемое значение выглядело не корректно.
В Silverlight 4 механизм обработки ошибок при связывании был расширен следующими свойствами: ValidatesOnDataErrors и ValidatesOnNotifyDataErrors
ValidatesOnDataErrors
В отличие от ValidatesOnException, тут можно не вмешиваться в свойства класса, а вынести всю логику проверки и выдачи сообщений в отдельный метод, определяемый интерфейсом IDataErrorInfo. Это развязывает руки разработчику, позволяя создавать расширения существующих классов, просто определив производный класс, реализующий дополнительный интерфейс.
Рассмотрим простой класс Employee, реализующий интерфейс IDataErrorInfo. Приведем весь код этого класса:
1: public class Employee: 2: INotifyPropertyChanged, IDataErrorInfo 3: { 4: public event PropertyChangedEventHandler PropertyChanged; 5: 6: public void OnPropertyChanged(PropertyChangedEventArgs e) 7: { 8: if (PropertyChanged != null) 9: PropertyChanged(this, e); 10: } 11: 12: private string firstName; 13: private string lastName; 14: private int age; 15: private string email; 16: private double salary; 17: 18: public double Salary 19: { 20: get 21: { 22: return salary; 23: } 24: set 25: { 26: salary = value; 27: OnPropertyChanged(new PropertyChangedEventArgs("Salary")); 28: } 29: } 30: 31: public string FirstName 32: { 33: get { return firstName; } 34: set 35: { 36: firstName = value; 37: OnPropertyChanged(new PropertyChangedEventArgs("FirstName")); 38: } 39: } 40: 41: public string LastName 42: { 43: get { return lastName; } 44: set 45: { 46: lastName = value; 47: OnPropertyChanged(new PropertyChangedEventArgs("LastName")); 48: } 49: } 50: 51: public string EMail 52: { 53: get { return email; } 54: set 55: { 56: email = value; 57: OnPropertyChanged(new PropertyChangedEventArgs("EMail")); 58: } 59: } 60: 61: public int Age 62: { 63: get { return age; } 64: set 65: { 66: age = value; 67: OnPropertyChanged(new PropertyChangedEventArgs("Age")); 68: } 69: } 70: 71: public override string ToString() 72: { 73: return String.Format("{0} {1}", firstName, lastName); 74: } 75: 76: string errors = null; 77: 78: public string Error 79: { 80: get { return errors; } 81: } 82: 83: public string this[string columnName] 84: { 85: get 86: { 87: string result = null; 88: if (columnName == "Age") 89: { 90: if (Age <= 0) 91: { 92: result = "Age should be positive!"; 93: } 94: else if (Age <= 16) 95: { 96: result = "You are too young!"; 97: } 98: } 99: return result; 100: } 101: } 102: }
Как видите, проверка свойств выносится в реализацию индексатора, описываемого интерфейсом IDataErrorInfo. При этом, реализация проверки базируется на проверке свойства, которое уже установлено (пусть даже в неправильное значение).
Следовательно, данных подход правильно применять скорее для отображения предупреждений, а не для проверки критических ошибок. Так, в примере выше, мы могли бы вынести проверку свойства Age на негативное значение в исключение, а проверку на совершеннолетие оставить в индексаторе.
Чтобы инициировать выдачу сообщений об ошибках, описанных в индексаторе, нужно воспользоваться свойством класса Binding – ValidatesOnDataErrors:
<TextBlock Text="Age:" Grid.Row="3" Grid.Column="0"></TextBlock> <TextBox Text= "{Binding Path=Age, Mode=TwoWay, ValidatesOnDataErrors=True, NotifyOnValidationError=True}" BindingValidationError="TextBox_BindingValidationError" Grid.Row="3" Grid.Column="1"> </TextBox>
Естественно, что ValidatesOnDataErrors и ValidatesOnExceptions не могут отрабатывать одновременно. Иными словами, если у Вас есть готовый класс, описывающий некоторый объект, при этом его свойства выполняют проверку данных и выбрасывают исключения, то ValidatesOnDataErrors использовать нельзя, так как он полностью игнорируется при появлении исключения (даже если ValidatesOnExceptions установлен в false).
ValidatesOnNotifyDataErrors
К сожалению, не всегда данные можно проверить сразу же на клиенте. Очень часто необходимо обратиться к источнику данных, который расположен на удаленном сервере. Лишь после этого можно сделать вывод о корректности данных. Естественно, что описанные выше механизмы не подходят для удаленной проверки данных, так как заблокируют интерфейс на время соединения с источником данных. Поэтому Silverlight 4 представляет новый механизм, позволяющий вести асинхронную проверку данных.
Чтобы обеспечить асинхронную проверку данных, класс, описывающий данные, должен реализовывать интерфейс INotifyDataErrorInfo. Тут описаны свойство HasErrors, определяющее наличие ошибок при асинхронной проверке данных, метод GetErrors, возвращающий объект перечислимого типа, содержащий ошибки, а также событие ErrorsChanged, которое инициируется при любом изменении коллекции ошибок.
Чтобы активировать работу интерфейса INotifyDataErrorInfo, необходимо воспользоваться свойством класса Binding – ValidatesOnNotifyDataErrors, установив его значение в true.
Особенностью этого подхода является возможность его комбинации с описанными выше подходами.
Добавить комментарий