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

Два основных способа заполнения содержимым несвязанных столбцов

b первый из обработчиков хорошо

Есть два основных способа заполнения содержимым несвязанных столбцов: либо обрабатывая событие RowsAdded, Либо обрабатывая событие CellFormatting. Первый из обработчиков хорошо подходит для установки значения ячейки, когда требуется сделать значение доступным впоследствии для программного извлечения. Второй обработчик подходит для передачи значения, которое будет использоваться только в целях отображения и не будет сохраняться вместе с данными, содержащимися в коллекции ячеек сетки. Событие CellFormatting Может также использоваться для преобразования значений в ходе их отображения в ячейках, когда отображаться должно что-то отличное от действительных значений, сохраняемых в скрытых за сеткой данных. Сначала этот код извлекает данные таблицы Customers при помощи метода GetData Адаптера таблицы. Как обсуждалось ранее, адаптер таблицы был создан вместе с типизированным набором данных, когда вы добавили к своему проекту источник данных. Возвращаемая методом таблица устанавливается в качестве источника данных для источника привязки. Свойство AutoGenerateColumns Устанавливается равным False, Так как код заполняет коллекцию столбцов программным путем. Затем при помощи перегруженного метода Add Коллекции Columns, Который принимает имя столбца и текст заголовка, к сетке добавляются четыре столбца текстовых полей. Первые три столбца настраиваются для привязки к данным столбцов CompanyName, ContactName и Phone таблицы Customers, для чего после создания каждого столбца устанавливается его свойство DataPropertyName. Четвертый столбец является несвязанным и здесь только создается вызовом метода Add. Он будет заполняться позднее при обработке событий. Наконец, интересующие нас события связываются, посредством неявных делегатов, с методами, которые будут их обрабатывать.

Генерация тестовых данных для привязки

b обратите внимание на то

Это простой метод генерации тестовых данных, который создает коллекцию List<Customer> И затем заполняет ее двумя объектами Customer, С каждым из которых ассоциируются объекты Order. Обратите внимание на то, как код клиента использует коллекцию Orders Класса Customer, Вызывая методы класса List<T>, Например, Add, Просто путем обращения к самому свойству Orders И вызова его методов. Заметьте также, что код устанавливает обратную ссылку от объекта Order На его родительский объект Customer, Просто устанавливая свойство Customer Объекта Order На создаваемый в данный момент экземпляр Customer. Как только список конструирован, он возвращается вызывающей форме и может быть использован для привязки данных. Если вы закодируете все это или загрузите образец CustomBusiness — Objects с сайта этой книги, а потом запустите его, то должны увидеть данные, заполняющие обе сетки. Выбор текущего заказчика в верхней сетке должен определять то, какие заказы будут показаны в нижней, что можно видеть Вы сразу же должны заметить, что если свойство класса с единственным значением является ссылочным типом, как свойство Customer Класса Order, Оно по умолчанию появится в сетке, поскольку пример автоматически генерирует столбцы. К сожалению, появляющиеся при этом значения имеют мало смысла, так как сетка, чтобы получить строковые значения для отображения в ячейке, в процессе форматирования вызывает метод ToString Объектов. То же самое произойдет, если привязать это свойство для отображения в элементе управления ComboBox, ListBox Или TextBox. Метод ToString По умолчанию, наследуемый от базового класса System.Object, Возвращает в качестве строки полностью квалифицированное имя типа, которое, скорее всего, не то, что вы хотели бы показать.

Можно было бы справиться с этим, не генерируя столбцы автоматически и не отображая в сетке свойство Customer. Но В Зависимости от ситуации вам могло бы потребоваться использовать это свойство в сценариях привязки данных, и в этом случае, возможно, вы хотели бы отображать нечто осмысленное, когда оно привязывается к текстовому элементу управления. Это можно сделать просто путем переопределения в своем специальном рабочем объекте метода ToString. В данном случае это означает добавление в класс Customer Переопределения ToString, Которое просто возвращает имя заказчика:

Создание набора ячеек строки по умолчанию методом 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 Ищет этот интерфейс у элементов данных в любой коллекции, к которой он привязан. Если сетка видит, что представляемые ею элементы данных реализуют этот интерфейс, она будет использовать его свойства, чтобы определить, имеются ли в столбцах какие-то ошибки, которые следует отобразить, или для самого объекта имеет место общая ошибка, подлежащая отображению.