Введение.
Понятие Binding данных в новой технологии .Net имеет весьма и весьма
важное значение. Несколько моих друзей, разработчиков, часто присылают
мне свой код для каких либо замечаний. И я уже в который раз ловлю себя
на мысли о том, что, казалось бы, элементарные вещи связанные с
синхронизацией коллекций, например тех же дорогих нам таблиц в dataset
мои товарищи делают почему-то очень по-разному и излишне сложными.
Я решил восполнить этот пробел небольшой статьей.
Практика.
Итак, давайте посмотрим на, казалось бы, элементарную проблему: как
сделать так, чтобы в двух DataGrid на одной форме выводилась информация
из двух таблиц. Но с тем условием, чтобы в гриде с «зависимой» таблицей
выводился отфильтрованный набор данных согласно ключевому полю.
Давайте снова возьмем уже избитую в боях базу NorthWind и проведем
небольшой эксперимент над двумя ее табличками: Regions и Territories.
Создаем проект. После появления Form1 открываем ToolBox Window и
перетаскиваем парочку гридов разделенных сплитером.
Получаем картинку подобную этой:
Далее наши действия по созданию адаптеров для двух таблиц и генерации
на основе них dataset, довольно просты. Быстренько перетягиваем из
Server Explorer таблички под названием Region и Territories (с целью
экономии времени можно сделать одновременное выделение с помощью клавиши
Ctrl) на нашу форму и генерируем на основе них типизированный dataset.
(правой клавишей мышки на поле не визуальных компонентов, т.е. там же
где находятся sqlDataAdapter1 и sqlDataAdapter2).
И теперь у нас получается следующая картина: мы имеем типизированный
dataset, объект sqlConnection и два адаптера для наших таблиц.
После приведения в порядок названий для наших объектов, я предлагаю
перейти в дизайнер dataset, т.е. нажав правую клавишу мышки над
предварительно выбранным dataSetMain экземпляром объекта нашего
"типизированного" dataset.
Что же мы видим? А видим мы две наши таблички без связей между ними.
Пожалуй исправим это «безобразие» и повторим схему связей из нашей
базы данных. Кстати, связи нашей БД, мы можем посмотреть тут же в окне
Server Explorer и даже в случае отсутствия диаграммы связей легко ее
создать.
После некоторых манипуляций мы должны получить с вами следующую
картинку:
Скажем честно – не было большого смысла делать связь в дизайнере
схемы dataset-а но для чистоты эксперимента мы это сделали.
Теперь перейдем в нашу основную форму. И в дизайнере присвоим
свойства datamember для наших гридов.
После запуска нашего приложения мы видим что наложение Relations в
нашем dataset ничего нам не дало. Да собственно и не должно было дать
потому как, мы просто добавили условие на ввод данных, но никак не на их
отображение.
Но в конце концов мы же должны получить «отфильтрованные» данные?
Точно, так оно и задумывалось и поможет нам в этом класс
BindingManagerBase.
Давайте-ка, добавим пару-тройку строк кода в наше приложение:
Для начала объявим экземпляры:
...
///
/// Private collection
///
private BindingManagerBase bmRegion;
private BindingManagerBase bmTerritory;
private DataRelations.DataSet1 dataSetMain;
public FormMain()
{
...
Далее мы должны провести инициализацию экземплярам , для этого мы
должны сделать следующее:
...
public FormMain()
{
//
// Required for Windows Form Designer support
//
InitializeComponent();
bmRegion = this.BindingContext[dataSetMain.Region];
bmTerritory = this.BindingContext[dataSetMain.Territories];
...
Я думаю с BindingContext вы уже наверняка знакомы. А если же нет, то
коротко и в двух словах - это метод, возвращающий экземпляр
BindingManagerBase для текущего Control и содержащий в себе информацию о
имеющихся связанных элементах для данного контекста. Не знаю, удачно ли
это объяснение, но в дальнейшем при работе я думаю, вы достаточно легко
поймете, что такое binding.
Итак движемся далее. У BindingManagerBase имеется несколько событий
которые нам будут весьма интересны: а именно PositionChanged. Как вы
догадались, это событие возникнет при движении, грубо говоря курсора по
гриду для данного datamember. Это событие нас как раз очень и
заинтересует. Давайте ка определим его. Для этого добавляем следующий
код:
...
... public FormMain() { // // Required for Windows Form Designer support
// InitializeComponent(); bmRegion =
this.BindingContext[dataSetMain.Region]; bmTerritory =
this.BindingContext[dataSetMain.Territories];
bmRegion.PositionChanged += new EventHandler(bmRegionPocition_Changed);
...
А также опишем собственно сам метод события:
...
[STAThread]
static void Main()
{
Application.Run(new FormMain());
}
private void bmRegionPocition_Changed(object sender, EventArgs e)
{
dataSetMain.Territories.DefaultView.RowFilter = "RegionID = " +
((DataSet1.RegionRow)((DataRowView)bmRegion.Current).Row).RegionID.ToString();
}
...
Компилируем и запускаем наше приложение.
Все! Пробуем и наслаждаемся
На самом деле этот пример не претендует на оригинальность, но
почему-то разработчики очень часто создают себе массу проблем «из
ничего» и почему-то очень часто игнорируют binding для создания
элементарных вещей и ломают себе голову над этим часами. |