2. Работа с наборами типизированных данных

Интерфейс IBindingListView: поддержка расширенной сортировки и фильтрации

i как было описано в

Интерфейс IBindingListView Дополняет возможности привязки данных интерфейса IBindingList, Вводя поддержку сортировки по набору свойств и фильтрации списка. Как было описано в предыдущем разделе, интерфейс IBindingList Обеспечивает простые функции сортировки и поиска. Однако иногда вам требуются дополнительные функциональные возможности. Вам может потребоваться сортировать коллекцию одновременно по нескольким свойствам или столбцам, или фильтровать представляемые коллекцией элементы по некоторому критерию, не отыскивая соответствующие ему элементы по одному. Интерфейс IBindingListView Предназначен как раз для таких случаев. IBindingListView Является производным от IBindingList, Так что все сказанное об IBindingList И его базовых интерфейсах остается в силе и здесь. Свойства и методы IBindingListView Описываются в Для поддержки расширенной сортировки коллекция должна быть способна устанавливать порядок исходя одновременно из нескольких свойств своих объектов данных. Перед попыткой применения расширенной сортировки код клиента должен проверить, истинно ли свойство SupportsAdvan — CedSorting. Если это так, то критерии сортировки специфицируются путем конструирования коллекции объектов ListSortDescription, Которая передается методу ApplySort Интерфейса IBindingListView. Тип ListSortDescription Весьма прост: это просто контейнер для пары, состоящей из свойства PropertyDescriptor И свойства SortDirection. Как правило, порядок этих элементов в ListSortDescriptionCoilection Определяет порядок, в котором применяются критерии сортировки. Чтобы удалить применявшуюся ранее сортировку, просто вызовите метод RemoveSort, Унаследованный от базового класса IBindingList. Чтобы получить доступ к текущим описаниям сортировки, применяемым к коллекции, можно проверить свойство IsSorted Базового интерфейса, после чего обратиться к свойству SortDescriptions, Чтобы получить коллекцию элементов ListSortDesc — Ription, Используемых в данный момент Если коллекция поддерживает фильтрацию, она должна возвращать True В свойстве SupportsFiltering. Тогда при помощи свойства Filter Вы можете установить строку фильтра, что немедленно изменит объекты данных, экспонируемые коллекцией при ее итерации. Формат строки фильтра будет относиться к разряду деталей реализации, отдельно специфицируемых для коллекции каждого типа.

Отслеживание данных при помощи событий

в таблице показаны события имеющиеся

Еще одна важная возможность сценариев привязки данных, особенно когда имеет место развязка уровней, состоит в оповещении об изменениях в нижележащем источнике данных при помощи событий. В таблице показаны события, имеющиеся в BindingSource. Такие события, как PositionChanged, ListChanged И CurrentChanged, Вы можете использовать для управления привязкой данных или синхронизации других элементов управления на форме, которые не обязательно находятся в строгих родительско-дочерних отношениях, которые допускали бы управление посредством каскадирования источников привязки, как было описано ранее. Например, представьте, что на форме имеется привязанный к данным комбинированный список, и при выборе в нем нового значения требуется переключить на новый источник данных — другой источник привязки, который управляет привязкой другой группы элементов управления на форме. Допустим, комбинированный список содержит строки соединения или имена баз данных. Вы можете решить эту проблему при помощи события SelectedlndexChanged Комбинированного списка. Но что, если на форме имеется несколько элементов управления, которые могут изменить текущий источник данных? Благодаря событию CurrentChanged Источника привязки вы можете очень просто решить проблему на уровне источника привязки, вместо того чтобы решать ее на уровне элементов управления.

Вы можете также использовать эти события для синхронизации между коллекциями данных, которые не связаны отношением «ведущий-детализация». Это иллюстрируется листингом 4.7 , где событие CurrentChanged Обновляет отображение родительского элемента при выборе в коллекции дочерних объектов. Событие CurrentChanged Можно еще использовать для организации своего рода связи «ведущий-детализация» между коллекциями объектов, связанных отношением «многие-ко-многим», как будет показано далее в разделе «Синхронизация коллекций, связанных отношением многие-ко-многим» .

Несколько более сложное приложение

допустим вы строите приложение winfx

Приложение «Hello World» не особенно продвинет вас вперед в понимании объектной модели WinFx и того, как образуется приложение, поэтому давайте взглянем на чуть более сложный пример. Допустим, вы строите приложение WinFx, которое будет производить идентификацию и авторизацию для определения того, что разрешено пользователю, исходя из сведений о нем в специальной базе данных и известных ролей. Итак, вам нужно идентифицировать пользователя, так что потребуется окно для входа в приложение. Давайте закодируем окно WinFx, которое будет выглядеть, как показанный на рис. Б.1 примитивный диалог авторизации. Сначала код создает объект Window Для главного окна и устанавливает его свойства width, Height И Text. Ничего загадочного здесь не происходит; код напоминает тот, что записывает в свой файл кода конструктор Windows Forms для каждой создаваемой вами формы.

Затем создаются следующие элементы управления: Grid, Два Text — Block, Один TextBox, Один PasswordBox И Button. Каждый экземпляр создается с помощью конструктора по умолчанию, после чего устанавливаются некоторые свойства. Для элементов TextBlock В свойстве Text — Content Устанавливаются строки подсказки, ради которых они здесь и присутствуют — здесь они используются аналогично элементам управления Label В Windows Forms. Для свойств HorizontalAlignment И Vertical Alignment Устанавливается значение Center, чтобы элементы были правильно выровнены на форме. Для TextBox, PasswordBox И Button Устанавливается свойство Height; Для Button В свойстве Content Устанавливается строка, которая будет отображаться на поверхности кнопки, аналогично тому, как это было со свойством Text Элемента управления Button В Windows Forms.

Обработка событий верификации

b когда запускаются и запускаются

Каждый элемент управления Windows Forms экспонирует два события, Validating И Validated, Которые наследуются от базового класса Control. Когда запускаются и запускаются ли вообще эти события, зависит от назначения производного элемента управления, некоторых свойств контейнерного элемента управления, которому он принадлежит, и от того, какой программный код активируется в отношении верификации. Предполагается, что событие Validating Запускается немедленно по завершении ввода, но до того, как ввод будет принят как действительный. Событие Validated Запускается, когда ввод принимается как действительный. Скажем, вы хотите написать в форме авторизации некоторый код, который проверяет поле имени пользователя. Простой пример, который можно было бы написать для подтверждения того, что в поле было введено некоторое значение, подписывал бы на событие Validating Элемента управления TextBox, Принимающего имя пользователя, следующий обработчик: Этот код входит в форму, которая содержит элемент управления M UsernameTextBox, И вызывается ею, когда фокус переключается на какой-то другой элемент управления формы. Код вызывает метод IsNullOrEmpty Класса String Для проверки того, пусто ли текстовое поле. Если это так, он устанавливает свойство Cancel Аргумента CancelEventArgs Равным True. Установка этого аргумента является сигналом инфраструктуре верификации Windows Forms о неудачной верификации данного элемента управления, что умолчанию завершит процесс верификации. Значением Cancel По умолчанию является False, Которое позволяет процессу верификации продолжаться. Затем отображается панель сообщения, чтобы предоставить пользователю некоторую обратную связь, информирующую о проблеме.

Откатывайте транзакции явным образом

однако я рекомендую вам всегда

Если вы закрываете соединение, на котором начали транзакцию, и еще не вызвали для нее Commit, Произойдет автоматический откат транзакции. Однако я рекомендую вам всегда делать это явным образом, самостоятельно вызывая Rollback , Чтобы было ясно, где и когда происходит откат Поскольку соединение открывается в листинге Г.9 явным образом, в дополнение к Try-Cach, Как вы можете видеть, я обеспечил его закрытие в блоке Finally, Поэтому, что бы ни происходило, соединение будет закрыто перед тем, как я выйду из метода. Вы видите здесь еще пару моментов, которые еще не обсуждались — это методы ExecuteScalar И ExecuteNon — Query Объектов SqlCommand. Метод ExecuteScalar Удобен для запросов, которые возвращают в качестве результирующего набора единственную строку с единственным столбцом. Метод извлекает значение этого столбца и передает его в качестве своего возвращаемого значения. Оно возвращается как объектная ссылка, поэтому необходимо приведение к ожидаемому типу, как показано в листинге Г.9. Метод ExecuteNonQuery Предназначен для исполнения команд, от которых вы не ожидаете каких-либо возвращаемых строк, таких, как запросы обновления, удаления и вставки. Когда транзакция создана, вам нужно ассоциировать ее с любыми командами, которые вы собираетесь применять внутри области действия транзакции. После этого вы можете исполнять команды. Если все получится так, как вы ожидаете, вы должны вызвать Commit Для объекта транзакции, чтобы сделать постоянными все изменения, произведенные внутри транзакции. Если что-то происходит не так, вы должны вызвать Rollback Транзакции, чтобы предотвратить запись любых изменений, сделанных командами внутри нее. Наилучшим способом обеспечить такую модель поведения является блок Try-Catch, Как показано в листинге Г.9. Если вы в своем коде явно открываете соединение, всегда заключайте код, который открывает соединение и исполняет запросы, в Try-блок. За ним расположите блок Finally И в нем закройте соединение. Тогда, завершается ли метод нормально или в результате неперехваченного исключения, соединение все равно будет закрыто и освобождено для использования другими клиентами.