КАТЕГОРИИ:
АстрономияБиологияГеографияДругие языкиДругоеИнформатикаИсторияКультураЛитератураЛогикаМатематикаМедицинаМеханикаОбразованиеОхрана трудаПедагогикаПолитикаПравоПсихологияРиторикаСоциологияСпортСтроительствоТехнологияФизикаФилософияФинансыХимияЧерчениеЭкологияЭкономикаЭлектроника
|
Привязка данныхСтр 1 из 10Следующая ⇒ Как известно, прежде чем начать усиленно и красиво отображать данные, эти самые данные надо получить. DataGridView поддерживает три режима работы с данными:
80% времени control будет работать в основном режиме, так как в большинстве случаев данные будут поступать из СУБД, при этом копируясь в промежуточные коллекции, например, DataTable. Привязывать элементы пользовательского интерфейса можно отнюдь не исключительно к таблично представленным данным. Практически любая структура данных может выступить в роли их источника – обычные объекты, массивы, коллекции и т.д. Хотя вопрос привязки данных в мире WinForms (Windows Forms Data Binding) совершенно выходит за рамки данной статьи ввиду его масштабности, не упомянуть ключевые моменты этой технологии было бы несомненным упущением. Сжато исследуем вопрос – как рекомендуется привязывать DataGridView к данным, и чем Framework 2.0 может нас порадовать при сравнении с версиями 1.x. В Framework 2.0 процедура привязки данных упростилась. Чтобы продемонстрировать это, разберем, как осуществлялась привязка данных во Framework 1.x (см рисунок 2). А что сегодня? Сегодня у нас новый герой – BindingSource (см. рисунок 3). Не правда ли – разница видна невооруженным глазом. Что же это за новый класс – BindingSource? Про него, на самом деле, тоже можно написать свою статью. Ну, уж заметку как минимум. :) Поэтому, стараясь оставаться в рамках поставленной цели, сжато опишу причины его возникновения и принципы работы. Приведенные выше иллюстрации показывают, что BindingSource представляет собой промежуточный слой между источником данных и control-ом, к нему привязанным. Также можно предположить (и совершенно обоснованно!), что, должно быть, этот класс взял на себя функциональность, ранее предоставлявшуюся CurrencyManager и PropertyManager. Второй из этих двух классов применялся очень редко, зато первый – весьма часто. Ведь надо же было как-то узнавать текущую позицию в коллекции, к которой привязан control, узнавать общее количество записей в ней, получать оповещения об изменениях этих записей и решать прочие подобные задачи. Но проблема была в том, что в .NET 1.x CurrencyManager создавался неявно. И значительная группа разработчиков, не давшая себе труда или не нашедшая времени детально разобраться в механизмах такого и вправду совсем не банального механизма, как Windows Forms Data Binding, попросту совершенно не представляла, как вообще подступиться к подобным вопросам? Да и те, кто вопрос изучил, были обречены продираться к CurrencyManager через дебри еще одного вспомогательного класса – BindingContext. Это была одна из причин возникновения нового класса – построить удобный и внятный интерфейс к функциональности CurrencyManager. BindingSource является, помимо всего, компонентом, и может быть помещен на форму. После этого он попадает на панель компонентов, и с ним можно работать через окно свойств. Удобно? Разумеется, главная задача – предоставить всю функциональность CurrencyManager – была с блеском выполнена. Знакомые и полюбившиеся свойства Count, Current, List, Position представлены непосредственно самим классом BindingSource. Видимо, предвидя, что переход с CurrencyManager на BindingSource может вызвать у особо впечатлительных натур приступы жестокой ностальгии по “старым и добрым временам”, авторы компонента даже снабдили его свойством CurrencyManager, возвращающим тот самый старый менеджер из 1.x. Иных побудительных мотивов возникновения этого свойства я не вижу, ибо новый класс включает в себя абсолютно все свойства/методы/события старого, да еще добавляет свои собственные, делая применение CurrencyManager сомнительным занятием. (думаем, все это было сделано из куда более прозаических соображений совместимости – прим.ред.) Итак, первый побудительный мотив – упростить работу с CurrencyManager. Вторая причина такова. Допустим, у нас есть Label, TextBox и ComboBox, привязанные к таблице (DataTable). Предположим, что для обновления информации был создан и заполнен данными из БД новый DataTable. Встает несложная, в общем-то, задача – сменить у всех трех control-ов источник данных. В 1.x задача решалась очень просто – ручками. Все три (тридцать три, как вариант) control-а перепривязывались к новой таблице, и дело с концом. Теперь можно изменить свойства DataSource/DataMember единственного BindingSource. Всё. Все три (или тридцать три) control-а привязаны к новому источнику. Вообще, BindingSource привнес массу улучшений в вопрос привязки данных. Чтобы заинтересовать читателя и подтолкнуть его к глубокому изучению данного класса, приведем пример. Как известно, в 1.x для привязки control-а к коллекции “чего-нибудь”, эта коллекция обязана была реализовывать как минимум интерфейс IList. А это три свойства и семь методов. BindingSource умерил свои аппетиты до скромного интерфейса IEnumerable. Поэтому в мире Framework 2.0 вполне возможны подобные привязки:
Отображает grid с шестью записями. Заманчиво? :) А каков общий подход при привязке любого WinForms-control-а к BindingSource? В общем случае – довольно несложный. Допустим, у нас есть DataSet NorthwindDataSet с единственной таблицей Products. Тогда первым шагом будет привязка BindingSource к этому источнику данных:
Теперь BindingSource сам становится полноценным источником данных. Единственное, что отличает его от "нормального" источника вроде того же DataTable, – отсутствие "собственных" данных, т.к. данные BindingSource – это данные нижележащего источника данных. Таким образом, при необходимости привязки свойства Text к колонке ProductName таблицы Products мы можем смело писать:
Так же обстоит дело со сложной привязкой той же колонки к control-у, поддерживающему подобную привязку:
И совсем уже нехитрой представляется привязка DataGridView ко всей таблице Products:
Обратите внимание, что свойство DataMember в последнем случае остается незадействованным. BindingSource уже привязан к интересующей нас таблице, и уточнять путь к ней внутри DataSet-а необходимости нет.
И, чтобы перекинуть мостик от "привязки любого WinForms-control-а" к "привязка конкретно DataGridView", отметим, что формальное требование к источнику данных у нового control-а осталось практически неизменным по сравнению с его предшественником, DataGrid. Единственное исключение выражается в требовании того, что свойства DataSource и DataMember теперь должны в сочетании определять некоторый список, то есть коллекцию, реализующую IEnumerable или интерфейсы, унаследованные от него, также возможно использовать в качестве источника данных компонент, реализующий IListSourse. Два свойства нужны, например, для того, чтобы указать некоторый DataTable, входящий в состав DataSet. Отличие же от предшественника заключается в том, что DataGrid мог привязываться к коллекции коллекций, наподобие DataSet с несколькими таблицами внутри, после чего начиналась упомянутая иерархическая навигация по элементам всех коллекций. На рисунке 4 приведена блок-схема привязки. С практической точки зрения все эти хитросплетения означают, что DataGridView следует привязывать исключительно к BindingSource, который сам реализует один из требуемых интерфейсов (именно – IBindingListView) и позволяет привязываться к широкому диапазону источников данных. Вариант с источником, реализующим IEnumerable был рассмотрен выше. Кстати, если в процессе исполнения приложения нужно отслеживать изменения значений свойств DataSource и DataMember, можно воспользоваться событиями DataSourceChanged и DataMemberChanged. Рассмотрим также событие DataGridView.DataBindingComplete. Оно будет сгенерировано как при изменении значения любого из двух упомянутых свойств, так и при наполнении control-а новыми данными (например, методом Fill адаптера данных). Нужно помнить только, что это все – события DataGridView, к самому источнику данных они никакого отношения не имеют. На практике же, чаще всего, интересны изменения данных именно в источнике, а не в control-е, эти данные отображающем. Для такого сценария (в который уже раз!) пригодится объект BindingSource с его замечательными событиями AddingNew, BindingComplete, CurrentChanged, CurrentItemChanged, ListChanged и целым рядом других. Остается в очередной раз досадовать, что подробное изучение этих событий увело бы нас в сторону от основной темы изложения.
|