Введение.
Понятие 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 для создания элементарных вещей и ломают себе голову над этим часами.
|