5. Общее представление об интерфейсах привязки данных

Обобщенные классы коллекций. NET Framework

net вы реализовывали специальные классы

В. NET 1.1 вы реализовывали специальные классы коллекций, используя класс CollectionBase И лежащий под ним ArrayList. Тут имелись некоторые проблемы, поскольку за кулисами все сохранялось и извлекалось через сырую ссылку Object, Что порождало проблемы с эффективностью, обусловленные упаковкой и распаковкой для типов-значений и приведениями для любых типов. Одним из важнейших нововведений в. NET 2.0 на уровне Framework явились обобщения. Вы уже познакомились с применением обобщений в ряде примеров этой книги, но полное обсуждение обобщений выходит за рамки ее тематики. Тем не менее использование обобщенных классов коллекций является центральным моментом привязки данных в приложениях Windows Forms со специальными рабочими объектами, поскольку обобщенные коллекции решают все проблемы, о которых уже говорилось в этой главе. Когда вы используете обобщенные классы коллекций, вы фактически объявляете сильно типизированный класс коллекции, просто объявляя экземпляр обобщенного класса с параметризованным типом. Рассмотрим, например, следующую строчку кода: Эта строка объявляет элемент-переменную типа List<Customer> И создает экземпляр этого типа. Параметром обобщенного типа является Customer, Который указывает, что должен быть создан новый обобщенный тип List, Содержащий объекты Customer. По синтаксису и семантике обобщения аналогичны шаблонам C++, но реализация их сильно отличается и более эффективна. Это простое объявление эквивалентно по своей функции определению целого класса, подобного показанному в листинге 9.1, но гораздо эффективнее в плане памяти и исполнения. Оно дает вам класс безопасной по типу коллекции для объектов любого рода, просто объявляя новый экземпляр обобщенного типа List<T> С соответствующим параметром типа , Специфицирующим тип объектов, для хранения которых предназначается коллекция.

Элемент управления DetailsView

форматирование элемента управления b detailsview

DetailsView — это новый удобный элемент управления, который устанавливает таблицу, отображающую детали отдельной единицы данных для более естественного просмотра. Форматирование элемента управления DetailsView Можно представить себе так, как будто он поворачивает одиночную строку табличной сетки набок, представляя заголовки столбцов как заголовки строк, а значения полей из желаемой строки как примыкающие к ним ячейки в каждой из этих строк. Пример показан на рис. А. З. Для использования DetailsView Вы устанавливаете управляющий элемент источника данных, как описывалось выше, и помещаете его ID В свойство DataSourcelD Элемента управления DetailsView. Задать, какую следует выбрать строку в источнике данных, вы можете либо ограничив запрос к источнику, чтобы он возвращал только одну единицу данных , Либо установив свойство FilterExpression Значением, которое отфильтрует желаемую строку. Код для страницы, показанной на рис. А. З приведен в листинге А.8.Av

Обратите внимание, что здесь два элемента управления SqlDataSource. Первый установлен как источник данных сетки и получает из базы данных все записи заказчиков. Второй установлен в качестве источника данных для элемента управления DetailsView И посредством ограничения Select . . . Where Определяет, какая строка выбирается. Параметр выбора определяется динамически через ControlParameter, Указывающий на элемент управления сетки, а его свойство SelectedValue Принимает значение ключевого поля выбранной строки, которое содержит CustomeriD. Элемент управления DetailsView Поддерживает также пагинацию, редактирование и многие из других возможностей самого GridView. Он предназначен для операций над единственной строкой за раз, поэтому источник данных должен быть установлен соответствующим образом.

Интерфейс IRaiseltemChangedEvents: осуществление уведомлений об изменении элемента

это может потребоваться если вы

Интерфейс IRaiseltemChangedEvents Позволяет коллекции указать, что она будет отслеживать изменения свойств содержащихся в ней объектов, производимые посредством метода SetValue Их дескрипторов свойств. Это может потребоваться, если вы ожидаете, что ваш тип коллекции может содержать объекты, которые не будут поддерживать интерфейс INotifyPropertyChanged, Но Хотите предусмотреть какую-то возможность уведомлять привязанные элементы управления о том, что свойства нижележащего элемента данных изменились. Этот интерфейс ничего не гарантирует относительно уведомления об изменениях, производимых какими-то средствами, отличными от метода SetValue Их дескрипторов свойств. Этот интерфейс используется в качестве сигнала потребляющему коду, что ваша коллекция будет возбуждать события ListChanged При изменении значений свойств ваших объектов, обусловленном действиями, произведенными через дескрипторы свойств — именно так производятся все обновления свойств через привязанные элементы управления, поддерживающие редактирование. Интерфейс имеет единственный элемент — булево свойство RaiseltemChangedEvents. Если коллекция возвращает в этом свойстве True, Потребляющий код вправе ожидать, что он будет получать уведомления в случае, когда какой-то объект в коллекции изменяется через привязанный элемент управления. Это используется во внутреннем устройстве компонента BindingSource Для лучшей синхронизации данных, отображаемых в привязанных элементах управления, даже если нижележащие объекты сами по себе не поддерживают уведомления об изменении свойств. Чтобы реализовать поддержку возбуждения событий ListChanged В ответ на изменения значений свойств в коллекции объектов, вам потребуется передать дескриптору свойства возвратно вызываемый делегат для каждого свойства каждого объекта в коллекции, так что коллекция будет получать уведомления об изменении этих свойств через дескриптор свойства. Это делается при помощи метода AddValueChanged Класса PropertyDescrriptor. Пример и более подробное обсуждение смотрите в главе 9, где реализуется класс Binding — ListView.

Свойство islnitialized

событие b initialized b типа

Свойство Islnitialized Возвращает булево значение, показывающее, завершил ли компонент, реализующий интерфейс, свою инициализацию. Событие Initialized Типа EventHandler Запускается компонентом при завершении инициализации. Таким образом, если некоторый компонент зависит от инициализации другого компонента, первый компонент может проверить у другого компонента наличие реализации этого интерфейса. Если он находит интерфейс, он может проверить, завершил ли уже второй компонент свою инициализацию, и если нет, подписаться на событие Initialized, Чтобы получить уведомление, когда это произойдет. Код листинга 7.3 показывает пример того, как ISupportlnitializeNotification Используется в методе Endlnit Компонента BindingSource. Комментарии, которые я добавил к листингу 7.3, описывают, что происходит. Когда вызывается Endlnit Компонента BindingSource, Последний проверяет объект, установленный в качестве его DataSouce, На наличие реализации интерфейса ISupportlnitializeNotification . Если интерфейс присутствует, через его свойство Islnitialized Проверяется, завершил ли объект свою инициализацию. Если нет, компонент подписывается на событие Initialized Объекта и больше ничего в методе Endlnit Не делает. Если объект источника данных уже завершил свою инициализацию или не реализует интерфейс, то метод завершает процесс инициализации, вызывая EndlnitCore, В котором производится вся действительная работа по завершению инициализации. Если объект поддерживает интерфейс и показывает, что еще не завершил свою инициализацию, то BindingSource Ждет, пока объект не запустит событие Initialized, И тогда заканчивает свою собственную инициализацию вызовом EndlnitCore. Кроме того, обработчик события Initialized Отписывается от этого события, поскольку в данном сценарии инициализации оно не должно запускаться более одного раза. Итак, если вы реализуете класс, который может использоваться в качестве источника данных, и этому классу необходима реализация ISupportlnitialize Для контроля взаимосвязанных свойств, то вы должны также реализовать интерфейс ISupportlnitializeNotification, Возвращая False В свойстве Isinitialized, Пока вы находитесь в процессе инициализации , И запуская событие Initialized Для любых подписчиков, когда вы закончите инициализацию

Действительные сохраняемые значения ячеек несвязанных столбцов

b как можно догадаться из

Если вы хотите устанавливать в сетке действительные сохраняемые значения ячеек несвязанных столбцов, то это лучше всего делать, обрабатывая событие RowsAdded. Как можно догадаться из имени, это событие запускается при добавлении строк к сетке. Обрабатывая событие, вы можете заполнить значения сразу всех несвязанных ячеек в строке, что будет эффективнее обработки события CellFormatting Для каждой ячейки. События CellFormatting Могут запускаться по одному для каждой строки по мере того, как вы программно добавляете строки в цикле, либо может быть запущено единственный раз для целой группы добавляемых строк, что происходит, когда вы привязываете данные или вызываете метод AddCo — Pies Коллекции строк. Аргумент события для RowsAdded Содержит свойства Rowindex И RowCount; Эти свойства позволяют вам перебрать добавленные строки в цикле и обновить значения несвязанного столбца. Следующий метод показывает альтернативный способ заполнения столбца Contact сетки из предыдущего примера с использованием события RowsAdded Вместо Этот код получает в цикле текущую строку, индексируя коллекцию Rows Свойством Rowindex Со смещением, равным счетчику цикла, пока не переберет все строки, вовлеченные в операцию в момент запуска события. Для определения содержимого несвязанного столбца текущей строки код использует данные из других ее столбцов. В реальном приложении вы могли бы получать или рассчитывать значения для несвязанных столбцов строки в цикле. Используйте для управления отображаемым содержимым ячейки событие CellFormatting, а для управления сохраняемым содержимым — событие RowsAdded