4. Привязка объектов контроля к источникам данных

Создание набора ячеек строки по умолчанию методом CreateCells

если у вас есть ссылка

Можно написать код несколько экономнее, использовав существующие определения столбцов сетки для создания набора ячеек строки по умолчанию методом CreateCells, А затем заменить те ячейки, типы которых должны отличаться от подразумеваемых по умолчанию: программного доступа к содержимому ячеек вы индексируете коллекцию Rows, Получая таким образом ссылку на строку, после чего индексируете коллекцию Cells, Получая объект ячейки. Если у вас есть ссылка на ячейку, вы можете производить с ней любые действия, поддерживаемые действительным типом данной ячейки. Если вы хотите обращаться к конкретным свойствам или методам, предусмотренным типом ячейки, то следует сначала привести ссылку к действительному типу ячейки. Для изменения содержимого ячейки вы устанавливаете ее свойство Value Значением, соответствующим ее типу. Что будет в данном случае «соответствующим типу значением», определяется тем, какого рода это ячейка. Для типов текстового поля, ссылки, кнопки и ячейки заголовка этот процесс очень напоминает то, что описывалось в главе 4 для объекта Binding. В принципе значение, присваиваемое свойству Value Ячейки, должно допускать преобразование в строку, и в процессе вывода к нему будет применено соответствующее форматирование. Чтобы изменить форматирование выводимой строки, установите свойство Format Стиля, используемого для ячейки. Стиль является экземпляром объекта DataGridViewCellStyle И доступен в качестве одного из свойств ячейки и имеет, что неудивительно, имя Style. Стиль ячейки имеет и другие интересные свойства, описываемые далее в разделе «Форматирование при помощи стилей». Например, если вы хотите установить в качестве содержимого ячейки текущую дату в коротком формате, то могли бы написать следующий код: Тем самым в качестве значения третьей ячейки в первой строке будет установлен экземпляр объекта DateTime, Допускающий преобразование в строку, а в качестве строки формата — предопределенная строка "d" . Когда ячейка отображается, она использует свою строку формата для преобразования в строку записанного значения DateTime.

Интерфейс ICustomTypeDesctriptor: экспонирование специальной информации о типе

если вы не реализуете этот

Интерфейс ICustomTypeDesctriptor Позволяет объекту предоставить специальную информацию о типе в качестве информации, которую он хочет открыто экспонировать, чтобы потребляющий код мог попросить объект описать себя, а не использовать сырую рефлексию определения типа. Если вы не реализуете этот интерфейс, открытые свойства, определяемые вашим объектом, могут быть описаны для привязки данных и других целей классом TypeDescriptor Посредством рефлексии. Но если вы реализуете интерфейс, то сможете сами предоставлять классу TypeDescriptor Дескрипторы свойств. Благодаря этому вы можете экспонировать в целях привязки данных нечто даже не объявленное в качестве открытого свойства вашего класса, а также скрыть свойства, которые вы не хотите показывать коду, не имеющему явной информации о типе для вашего объекта. Так делается в DataView Для экспонирования коллекций дочерних строк в какой-то другой таблице, которые определяются через DataRelation В качестве свойства DataView Для дочерней коллекции. Интерфейс ICustomTypeDesctriptor Не принадлежит к числу тех, что вы должны были бы обычно реализовать. Но если вам нужен явный контроль над тем, какие свойства экспонируются посредством класса TypeDescriptor При рефлексии вашего объектного типа, то реализация этого интерфейса дает вам такую возможность. Когда класс TypeDescriptor Собирается получить свойства, реализуемые объектом, он прежде всего проверяет, реализует ли этот объект интерфейс ICustomTypeDesctriptor. Если да, то он попросит объект предоставить свои собственные дескрипторы свойств через метод GetProperties Этого интерфейса. На самом деле функции интерфейса ICustomTypeDesctriptor Далеко не ограничиваются тем, чтобы просто дать вам возможность описать свои свойства. Если вы реализуете ICustomTypeDesctriptor, То должны предусмотреть реализации для всех методов, показанных в таблице 7.16, большинство из которых не будет непосредственно участвовать в сценариях привязки данных.

Интерфейс IDataErrorlnfo: предоставление информации об ошибках

он экспонирует сообщение об ошибке

Интерфейс IDataErrorlnfo Позволяет объекту хранить и экспонировать информацию об ошибках, которая может использоваться привязанными элементами управления для извещения пользователя об ошибках, возникающих при работе с объектом. Он экспонирует сообщение об ошибке верхнего уровня для объекта в целом, а также индексатор, который может экспонировать сообщения об ошибках для отдельных свойств. Такие элементы управления, как DataGridView, Могут использовать эту информацию для индикации ошибок по месту и для сообщений пользователю. Когда элемент управления привязан к коллекции элементов данных, а элементы данных могут изменяться либо самим элементом управления, либо другим кодом в приложении, что-то может пойти неправильно. Кто-то попытается втиснуть значение недопустимого типа в слабо типизированное свойство рабочего объекта. Кто-то может передать значение вне допустимого диапазона верификации. Может произойти ошибка при попытке зафиксировать в базе данных содержащееся в объекте значение. В любой из этих ситуаций привязанному элементу управления может потребоваться узнать о произошедшей ошибке и, возможно, предоставить пользователю некоторую информацию о ней, если он умеет это делать. Хорошим примером является элемент управления DataGridView, Привязанный к DataView. Если в любом из столбцов строки нижележащей таблицы происходит ошибка, класс DataRow Может сохранить информацию о ней в своей коллекции Errors. При этом сохраняется не только какой была ошибка, но и к какому конкретному столбцу в строке она относилась. Когда в строке происходит ошибка, она отражается в сетке значком ошибки рядом с проблемной ячейкой. При задержке курсора мыши на значке в этом столбце данной строки появляется сообщение об ошибке, описывающее возникшую проблему. Все это происходит, если DataRowView Реализует интерфейс IDataErrorlnfo, И элемент управления DataGridView Ищет этот интерфейс у элементов данных в любой коллекции, к которой он привязан. Если сетка видит, что представляемые ею элементы данных реализуют этот интерфейс, она будет использовать его свойства, чтобы определить, имеются ли в столбцах какие-то ошибки, которые следует отобразить, или для самого объекта имеет место общая ошибка, подлежащая отображению.

Реализация специальных рабочих объектов и коллекций для привязки данных

одна из них та что

В большинстве всех примеров этой книги я в качестве источника данных, к которым подключаются, с точки зрения формы, источники привязки и элементы управления, использовал реляционные источники данных, а именно типизированные наборы данных. Для этого есть несколько причин. Одна из них та, что доминирующим способом хранения прикладных данных являются реляционные базы данных, поэтому при поступлении в приложение данных в виде реляционной коллекции разница между данными, с которыми приложение работает, и данными, которые оно загружает и сохраняет, оказывается небольшой. Другой причиной является то, что использование реляционных данных в уровне представления — самый распространенный способ представления коллекций данных, обеспечивающий взаимодействие пользователей с этими данными. И наконец, в прошлом, как правило, в сценариях привязки данных было проще работать с реляционными данными, чем со специальными рабочими объектами, отчасти из-за тех инструментов и затрат, которые требуются для правильного определения рабочих объектов и коллекций этих объектов, пригодных для привязки данных. Проблема при использовании реляционных данных в уровне представления состоит в том, что становится более вероятной тесная сопряженность в вашем приложении — от яруса данных вплоть до уровня представления. При такой сопряженности небольшие изменения в схеме данных на уровне базы данных потребуют изменений на всех уровнях — через уровень доступа к данным и рабочий уровень до уровня представления. Нужно будет найти все места вашего приложения, имеющие касательство к этой конкретной части базы данных, чтобы обновить соответствующий код доступа, работающий с этими данными. Но этого не потребуется, если вы обеспечите развязку рабочего уровня посредством сохраняемых процедур и определения типов наборов данных рабочего уровня, отличных от тех, что определены в уровне доступа к данным. Но иногда определение специальных рабочих объектов целесообразнее изоляции рабочего уровня, и дает вам более явный контроль над всем, что происходит в объектах, используемых для представления и манипуляции данными.

Уведомление потребителей об изменениях в коллекции

чтобы об этом сообщить коллекция

Если коллекция поддерживает изменения, она также должна поддерживать запуск события ListChanged При изменении коллекции. Чтобы об этом сообщить, коллекция должна возвращать True В свойстве Sup — PortsChangeNotification. Сама коллекция должна возбуждать события ListChanged, Когда элементы добавляются или удаляются из коллекции. В идеале она должна была бы посылать уведомления ListChanged При изменении существующих элементов в коллекции из-за модификации их свойств. Однако способность коллекции делать это будет диктоваться тем, как изменяются свойства и какую поддержку предусматривают для этого содержащиеся объектные типы. Как уже упоминалось, если изменения производятся посредством метода SetValue Дескриптора свойства, контейнер может вызвать метод AddVa — LueChanged Дескриптора и передать возвратно-вызываемый делегат, чтобы контейнер получал уведомления при изменении свойства. В ответ на уведомление от дескриптора об изменении свойства он может затем возбудить событие ListChanged. Это в точности то, что должна делать реализация интерфейса IRaiseltemChangedEvents, Обсуждаемого в одном из последующих разделов. Однако если свойство было изменено непосредственно его установщиком, вызванным через ссылку на объект, у коллекции нет способа узнать об изменении, если только сам объект не уведомит коллекцию. Последняя возможность обеспечивается интерфейсом INotifyProper — TyChanged. Другой формой изменения, которую может поддерживать коллекция, является динамическое изменение схемы, когда к элементам коллекции во время исполнения или проектирования добавляются новые свойства. Событие ListChanged Через свои аргументы события поддерживает уведомления и о таких изменениях. Событие ListChanged имеет тип ListChangedEventHandler, который сопровождается аргументом события типа ListChangedEventArgs. Его свойства, перечисленные в таблице 7.11, сообщают более подробную информацию об изменениях в списке. Запуск программы дает следующий результат: Из вывода программы вы можете видеть, что удаление элементов передает индекс удаленного элемента в свойстве Newlndex Аргументов события; для нового столбца возвращается дескриптор свойства, описывающий этот столбец; а когда изменяется элемент коллекции, наряду с его индексом возвращается дескриптор свойства, описывающий изменившееся свойство.