При загрузке данных из БД возникает исключение InvalidOperationException с сообщением: Элемент коллекции должен быть пустым перед использованием ItemsSource. Знаю, что для заполнения DataGrid можно использовать коллекции Items или ItemsSource, но одновременно их использовать нельзя: если задано значение для свойства ItemsSource и в коде C# добавляется элемент в Items, возникает исключение. |
Базовые инструменты WPF
Преобразование и проверка данных
При выполнении привязки данных достаточно часто тип или представление объекта-источника и целевого объекта не совпадают, и встает задача преобразования данных. Преобразование данных может проводится неявно, когда целевой тип может представлять любое допустимое значение типа источника, но это не всегда может удовлетворять пользователя.
В технологии WPF преобразование данных используется для:
- форматирования данных к строковому представлению;
- создания специфических типов WPF;
- условного изменения свойств элемента на основе привязанных данных.
Для проектирования преобразователя значений необходимо выполнить следующее:
- Создать класс, реализующий интерфейс IValueConverter.
- Добавить атрибут ValueConversion в объявление класса и специфицировать исходный и отображаемый формат.
- Реализовать метод Convert(), преобразующий данные из исходного формата в отображаемый формат.
- Реализовать метод ConvertBack(), выполняющий обратное преобразование значения данные из отображаемого форма в исходный формат.
В случае преобразования вещественного значения в строковое можно использовать метод ToString(), а для обратного преобразования - Single.Parse().
Спроектируем класс конвертора StringToFloatConvert для преобразования строковых данных в вещественное число.
[ValueConversion(typeof(float),typeof(string))] public class StringToFloatConvert : IValueConverter { public object Convert(object value, Type typeTarget, object param, CultureInfo culture) { if (value != null) return value.ToString(); else return string.Empty; } public object ConvertBack(object value, Type typeTarget, object param, CultureInfo culture) { if ((value != null) && (value.ToString() != "")) return Single.Parse(value.ToString(), NumberStyles.Float); else return 0; } }
Обратите внимание на то, что для преобразования строки данных в вещественное число используется метод Single.Parse(value.ToString(), NumberStyles.Float). Данный метод преобразует строковое представление числа в указанном стиле в эквивалентное ему число одиночной точности с плавающей запятой, то есть для ввода используется не точка, а запятая.
Для подключения преобразователя необходимо к дескриптору окна добавить атрибут с отображением пространства имен проекта на префикс пространства имен XML:
xmlns:s="clr-namespace:Wpf_Primer1"
Далее необходимо создать экземпляр класса StringToFloatConvert и присвоить его свойству Convert в привязке элемента TextBox:
<TextBox Grid.Column="1" Margin="5,5,28,15" Name="textBox1"> <TextBox.Text> <Binding Path="Factor" Mode="TwoWay" UpdateSourceTrigger="PropertyChanged"> <Binding.Converter> <s:StringToFloatConvert /> </Binding.Converter> </Binding> </TextBox.Text> </TextBox>
Тестирование приложения показывает, что при вводе цифровой строки с запятой, то есть вещественного числа с плавающей запятой, например "0,3", выводится также строка "0,3" ( рис. 3.8). При вводе цифровой строки с точкой формируется программное прерывание методом Single.Parse(value.ToString(), NumberStyles.Float).
Теперь вернемся к вопросу проверки достоверности вводимых данных. Логика проверки достоверности вводимых данных должна перехватывать некорректные значения и отвергать их.
Технология WPF предполагает два варианта проверки достоверности данных для перехвата неверных значений:
- инициирование ошибки в объекте данных путем генерации исключения при установке свойства;
- определение проверки достоверности на уровне привязки.
Спроектируем правило проверки достоверности ввода данных путем создания класса ValidationFactor, который должен быть наследником класса правил ValidationRule из пространства имен System.Windows.Control:
public class ValidationFactor: ValidationRule { public float Min { get; set;} public float Max { get; set;} public override ValidationResult Validate(object value, System.Globalization.CultureInfo cultureInfo) { try { if (((string)value).Length > 0) Window1.Factor.Factor = Single.Parse((string)value, NumberStyles.Float); if((string)value == "") Window1.Factor.Factor = 0; } catch (Exception e) { return new ValidationResult(false, " Введен недопустимый символ! "); } if ((Window1.Factor.Factor < Min) || (Window1.Factor.Factor > Max)) return new ValidationResult(false, " Вводимое значение вне диапазона от " + Min + " до " + Max + ". "); else return new ValidationResult(true, null); } }
В классе ValidationFactor определены свойства Min и Max, описывающие минимальное и максимально возможное значения вводимого вещественного числа и переопределен метод Validate() для требуемой проверки достоверности. При проверке достоверности используют перегруженную версию метода Single.Parse(), принимающего значение из перечисления NumberStyles. Это связано с тем, что проверка достоверности всегда выполняется перед преобразованием данных. Если применяется средство проверки достоверности и преобразователь к одному полю, то нужно обеспечить успех проверки достоверности. Успех или неудача логики проверки достоверности определяется возвращаемым объектом ValidationResult. Свойство IsValid указывает на успех проверки достоверности, и если проверка не прошла, то свойство ErrorContent представляет объект, описывающий ошибку.
Создадим экземпляр класса ValidationFactor и присвоим его свойству ValidationRules в привязке элемента TextBox:
<TextBox Grid.Column="1" Margin="5,5,28,15" Name="textBox1"> <TextBox.Text> <Binding Path="Factor" Mode="TwoWay" UpdateSourceTrigger="PropertyChanged"> <Binding.Converter> <s:StringToFloatConvert /> </Binding.Converter> <Binding.ValidationRules> <s:ValidationFactor Min="0" Max="1"/> </Binding.ValidationRules> </Binding> </TextBox.Text> </TextBox>
Свойствам Min и Max класса ValidationFactor определим значения соответственно 0 и 1.
Тестирование приложения показывает, что при вводе корректного значения приложение работает правильно, а при вводе некорректного символа или числа вне интервала [0,1] происходит подсвет рамки элемента TextBox красным цветом ( рис. 3.9).
На рис. 3.9 показан ввод недопустимого нецифрового символа и недопустимого по значению числа.
Следует отметить, что коллекция Binding.ValidationRules может состоять из неограниченного числа правил. Когда значение фиксируется в источнике, WPF будет проверять каждое правило проверки достоверности по порядку. Если все проверки достоверности пройдут успешно, то WPF вызовет преобразователь данных и применит значения к источнику. Если проверка не пройдет, то текстовое поле будет очерчено красным цветом, будут установлены свойства HasError и Error и инициируется событие Error.