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

Интерфейс 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

Встроенные типы столбцов

работа с некоторыми другими типами

Использовать столбец текстовых полей достаточно просто: вы привязываетесь к данным, которые могут быть представлены в виде текста, или устанавливаете свойство Value Равным чему-то, что допускает преобразование в строку, и дело сделано. Работа с некоторыми другими типами ячеек может оказаться не столь очевидной, поэтому в этом разделе мы рассмотрим каждый из встроенных типов столбцов, отмечая его возможности и то, как им пользоваться. Прежде всего следует понимать, что хотя большая часть функциональных возможностей DataGridView Лежит на уровне ячейки и может поддерживать поведение, подобное поведению «электронных таблиц» , в основе своей сетка остается табличным элементом управления. Столбцы сетки обычно отражают информацию, которую можно определить на этапе разработки, — а именно, схему представляемых данных. Строки обычно определяются динамически во время исполнения и отображаются на структуру, описываемую столбцами. Изредка вам приходится программно создавать столбцы в зависимости от динамических схем данных во время выполнения, но даже тогда вы сначала определяете форму данных, а затем предоставляете собственно данные. Как следствие, для каждого из встроенных типов ячеек, которые может отображать сетка, имеется соответствующий тип столбца, предназначенный для ячеек именно такого типа. Каждый тип ячейки производится от класса DataGridViewCell, А каждый из соответствующих типов столбцов — от DataGridViewColumn. Каждый из типов столбцов экспонирует свойства, предназначенные для привязки его данных, и каждый тип столбца соответствует ожидаемому содержимому того типа ячеек, что объединены в столбец. Аналогичным образом каждый производный тип ячейки может экспонировать дополнительные свойства в зависимости от типа содержимого, для которого предназначена ячейка.

Так как каждый встроенный тип столбца имеет свои тонкие особенности, лучше всего рассматривать их по одному. Однако поскольку все типы ячеек, содержащихся в различных типах столбцов, являются производными от одного и того же базового класса, они наследуют от него ряд свойств, которые вы будете использовать для управления и доступа к содержимому ячейки. Эти свойства базового класса DataGridViewCell Описываются в таблице 6.1.

Обновление при помощи наборов данных и сохраняемых процедур

если вы запустите для базы

Не удивительно, что для разговора об обновлениях при помощи сохраняемых процедур нам потребуются какие-то сохраняемые процедуры, производящие обновления. Если вы запустите для базы данных Northwind скрипт из листинга Г. 7, то получите простые сохраняемые процедуры SELECT, UPDATE, INSERT и DELETE, работающие с таблицей Region, которые подойдут для работы с любым набором данных, содержащим данные из таблицы Region. Чтобы ничего здесь не усложнять и сосредоточить внимание на вызове сохраняемых процедур для обновления, эти процедуры не имеют никакой конкурентной защиты. Как уже упоминалось при обсуждении построителей команд, запросы, требуемые для проверки оптимистической конкуренции по каждому из столбцов в строке, становятся запутанными и очень неэффективны. Лучшим способом будет использование столбца для отметки времени или версии строки, либо столбца, который обновляется значениями даты и времени всякий раз, когда строка изменяется. Вы можете затем использовать его для обнаружения нарушений конкуренции, и тогда вам потребуется проверять единственный столбец и переносить единственный дополнительный параметр, чтобы узнать, не обновил ли кто-нибудь строку с тех пор, как она была извлечена.

Заметьте, что в данном случае столбец RegionID не является автоматически нумеруемым идентификационным столбцом, поэтому вы должны передавать ID как параметр даже для вставок. Если у вас есть столбец идентификации, который будет генерироваться при выполнении вставки на стороне сервера, то вам нужно будет сделать этот столбец выходным параметром сохраняемой процедуры, а затем устанавливать этот параметр в сохраняемой процедуре значением @@IDENTITY. Тогда новое идентификационное значение будет передаваться из сохраняемой процедуры обратно и помещаться в строку, инициировавшую вставку, в таблице на стороне клиента. Имея сохраняемые процедуры, которые можно вызывать, вам нужно написать немного кода, чтобы подготовить все команды, необходимые для извлечения и обновления набора данных при помощи этих сохраняемых процедур. Следующий код показывает простой метод, который вызывает сохраняемую процедуру GetRegions Для заполнения набора данных, являющегося элементом охватывающего класса.