Студопедия

КАТЕГОРИИ:

АстрономияБиологияГеографияДругие языкиДругоеИнформатикаИсторияКультураЛитератураЛогикаМатематикаМедицинаМеханикаОбразованиеОхрана трудаПедагогикаПолитикаПравоПсихологияРиторикаСоциологияСпортСтроительствоТехнологияФизикаФилософияФинансыХимияЧерчениеЭкологияЭкономикаЭлектроника


Привязка данных




Как известно, прежде чем начать усиленно и красиво отображать данные, эти самые данные надо получить. DataGridView поддерживает три режима работы с данными:

  1. Первый, основной – отображение данных из внешних коллекций (например, ListView, DataTable).
  2. Специальный режим отображения свободных (unbound) данных, то есть данные хранятся в самом control-е.
  3. Еще один особый режим работы – виртуальный (Virtual mode). В нем control посылает событие, при поступлении которого прикладной код возвращает некоторые данные. Так как данные при этом не обязаны где-то храниться, виртуальный режим может оперировать миллионами строк без каких-либо проблем с производительностью или нехваткой памяти.

80% времени control будет работать в основном режиме, так как в большинстве случаев данные будут поступать из СУБД, при этом копируясь в промежуточные коллекции, например, DataTable.

Привязывать элементы пользовательского интерфейса можно отнюдь не исключительно к таблично представленным данным. Практически любая структура данных может выступить в роли их источника – обычные объекты, массивы, коллекции и т.д. Хотя вопрос привязки данных в мире WinForms (Windows Forms Data Binding) совершенно выходит за рамки данной статьи ввиду его масштабности, не упомянуть ключевые моменты этой технологии было бы несомненным упущением. Сжато исследуем вопрос – как рекомендуется привязывать DataGridView к данным, и чем Framework 2.0 может нас порадовать при сравнении с версиями 1.x.

В Framework 2.0 процедура привязки данных упростилась. Чтобы продемонстрировать это, разберем, как осуществлялась привязка данных во Framework 1.x (см рисунок 2).


Рисунок 2.

А что сегодня? Сегодня у нас новый герой – BindingSource (см. рисунок 3).


Рисунок 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 вполне возможны подобные привязки:

public partial class Form1 : Form{ public Form1() { InitializeComponent(); //_biSour - объект типа BindingSource _biSour.DataSource = new PersonCollection(); //_grid - обычный, без настроек, DataGridView _grid.DataSource = _biSour; }} public class PersonCollection : System.Collections.IEnumerable{ public System.Collections.IEnumerator GetEnumerator() { for(uint i = 0; i <= 5; i++) { yield return new Person("Name_" + i.ToString(), 20 + i, 'M'); } }} public class Person{ private string _name; private uint _age; private char _gender;....// свойства, инкапсулирующие эти три поля public Person(string name, uint age, char gender) { ... }}

Отображает grid с шестью записями. Заманчиво? :)

А каков общий подход при привязке любого WinForms-control-а к BindingSource? В общем случае – довольно несложный. Допустим, у нас есть DataSet NorthwindDataSet с единственной таблицей Products. Тогда первым шагом будет привязка BindingSource к этому источнику данных:

// _biSour - объект типа BindingSource_biSour.DataSource = this.NorthwindDataSet;// сразу привязываемся к конкретной таблице_biSour.DataMember = "Products";

Теперь BindingSource сам становится полноценным источником данных. Единственное, что отличает его от "нормального" источника вроде того же DataTable, – отсутствие "собственных" данных, т.к. данные BindingSource – это данные нижележащего источника данных. Таким образом, при необходимости привязки свойства Text к колонке ProductName таблицы Products мы можем смело писать:

this.label1.DataBindings.Add( new Binding("Text", _biSour, "ProductName", true));

Так же обстоит дело со сложной привязкой той же колонки к control-у, поддерживающему подобную привязку:

this.comboBox1.DataSource = _biSour;this.comboBox1.DisplayMember = "ProductName";

И совсем уже нехитрой представляется привязка DataGridView ко всей таблице Products:

//_grid - обычный, без настроек, DataGridView_grid.DataSource = _biSour;

Обратите внимание, что свойство DataMember в последнем случае остается незадействованным. BindingSource уже привязан к интересующей нас таблице, и уточнять путь к ней внутри DataSet-а необходимости нет.

СОВЕТ В среде Framework 2.0 любую привязку визуального элемента формы к источнику данных настоятельно рекомендуется проводить только через класс-посредник BindingSource. Действуя так, вы просто не можете проиграть. В самом крайнем случае вы получите просто избыточную функциональность новообразованной связи, что, понятно, много лучше ее дефицита. Поэтому отныне вашим девизом должен стать: "Говорим Data Binding – подразумеваем BindingSource".

И, чтобы перекинуть мостик от "привязки любого WinForms-control-а" к "привязка конкретно DataGridView", отметим, что формальное требование к источнику данных у нового control-а осталось практически неизменным по сравнению с его предшественником, DataGrid. Единственное исключение выражается в требовании того, что свойства DataSource и DataMember теперь должны в сочетании определять некоторый список, то есть коллекцию, реализующую IEnumerable или интерфейсы, унаследованные от него, также возможно использовать в качестве источника данных компонент, реализующий IListSourse. Два свойства нужны, например, для того, чтобы указать некоторый DataTable, входящий в состав DataSet.

Отличие же от предшественника заключается в том, что DataGrid мог привязываться к коллекции коллекций, наподобие DataSet с несколькими таблицами внутри, после чего начиналась упомянутая иерархическая навигация по элементам всех коллекций. На рисунке 4 приведена блок-схема привязки.


Рисунок 4.

С практической точки зрения все эти хитросплетения означают, что DataGridView следует привязывать исключительно к BindingSource, который сам реализует один из требуемых интерфейсов (именно – IBindingListView) и позволяет привязываться к широкому диапазону источников данных. Вариант с источником, реализующим IEnumerable был рассмотрен выше. Кстати, если в процессе исполнения приложения нужно отслеживать изменения значений свойств DataSource и DataMember, можно воспользоваться событиями DataSourceChanged и DataMemberChanged.

Рассмотрим также событие DataGridView.DataBindingComplete. Оно будет сгенерировано как при изменении значения любого из двух упомянутых свойств, так и при наполнении control-а новыми данными (например, методом Fill адаптера данных). Нужно помнить только, что это все – события DataGridView, к самому источнику данных они никакого отношения не имеют. На практике же, чаще всего, интересны изменения данных именно в источнике, а не в control-е, эти данные отображающем. Для такого сценария (в который уже раз!) пригодится объект BindingSource с его замечательными событиями AddingNew, BindingComplete, CurrentChanged, CurrentItemChanged, ListChanged и целым рядом других. Остается в очередной раз досадовать, что подробное изучение этих событий увело бы нас в сторону от основной темы изложения.


Поделиться:

Дата добавления: 2015-09-15; просмотров: 111; Мы поможем в написании вашей работы!; Нарушение авторских прав





lektsii.com - Лекции.Ком - 2014-2024 год. (0.008 сек.) Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав
Главная страница Случайная страница Контакты