Для
написания статьи использована русская версия Visual Basic.NET.
1. Вступление.
DataGrid является мощным средством отображения данных и в своем,
наиболее общем применении, позволяет отобразить какую-либо таблицу из
базы данных, например:
Это таблица Employee из учебной базы данных Pubs, входящая в MS SQL
Server. Как видим, DataGrid отобразил все поля, в том числе, поля
являющиеся ключами для связи с другими таблицами. В частности, поле
job_id, указанное стрелкой, содержит идентификаторы должностей
работников. Сами же названия должностей находятся в таблице jobs,
являющейся родительской по отношению к искомой таблице.
А как сделать так, чтобы в DataGrid (1) отображать только нужные
поля, а поле job_id (2) отображало вместо цифр наименования должностей.
Да чтобы в режиме редактирования (3) выбирать эти должности из списка
прямо в DataGrid.
Решая эту задачу, я нашел удивительно мало примеров по выводу в
DataGrid информации из родительской таблицы. Хотя, в то же время,
довольно много сведений по отображению записей из подчиненной (дочерней)
таблицы.
Как бы то ни было, задачу нашу можно решить несколькими путями. Я
попробую показать вариант, который требует минимум кода и несколько
движений мышки. Благо, Visual Studio.NET позволяет это сделать. В
процессе решения задачи будут выполнены шаги по созданию проекта, что
окажется полезным для начинающих разработчиков ASP.NET
2. Создание проекта
Итак, открываем студию и на начальной странице выбираем "Новый
проект".
В диалоговом окне выбираем язык программирования (я выбрал удобный
мне Visual Basic), далее - тип приложения. У нас это "Веб-приложение
ASP.NET". Изменим имя по умолчанию на осмысленное HierarchyDataGrid.
Жмем кнопку ОК и смотрим, как создается проект на локальном
Веб-сервере.
После создания проекта, в обозреватель решений выводится список
файлов, входящих в наш проект. И видим, что в названии проекта я
допустил ошибку. Надеюсь, с Вами этого никогда не случится :).
Сразу поменяем название нашей страницы с WebForm1.aspx на
default.aspx. Это важно, особенно в случае, если это начальная страница
сайта. Дважды щелкаем по названию нашей страницы. Откроется чистая
форма. Все, проект создан!
3. Создание соединения с базой данных и настройка DataAdapter
Следующий наш шаг - соединение с базой данных Pubs. Разумеется, для
этого должен быть установлен и запущен MS SQL Server2000.
Откроем Обозреватель серверов и найдем наш SQL Server с базой данных
Pubs. Развернув дерево объектов базы, находим таблицы employee и jobs.
Захватив мышкой название таблицы employee, перетянем ее на форму.
VS.NET автоматически создаст в невидимой части формы соединение с базой
Pubs под именем SqlConnection1 и DataAdapter с именем SqlDataAdapter1
для работы с таблицей employee.
Те же действия проделаем с таблицей jobs.
Переименуем вновь созданные объекты:
- SqlConnection1 в conPubs
- SqlDataAdapter1 в daEmployee
- SqlDataAdapter2 в daJobs
Затем выделим conPubs и перейдем в окно свойств. В секции
Конфигурации раскроем DynamicProperties и в свойстве ConnectionString
нажмем кнопку. В открывшемся диалоговом окне поставим флажок и закроем
его.
В результате этой операции строка соединения у нас добавилась в файл
Web.config, что дает нам прекрасную возможность конфигурировать наше
соединение без необходимости лезть в код. Этим мы сразу и воспользуемся.
Вперед!
Открываем файл Web.config, находим секцию appSettings, а в ней запись
с нашей строкой соединения под именем ключа "conPubs.ConnectionString".
Созданную редактором строку соединения заменим на показанную на
изображении, и немного отформатируем ее для удобства чтения.
Почему я это сделал? Так мы избежим проблем с правами доступа и
настройками SQL Server. В итоге, мы создали соединение и готовы делать
дальнейшие шаги.
4. Создание Dataset и DataRelation
Теперь мы должны создать так называемый типизированный Dataset.
Щелкнув правой кнопкой мышки по изображению любого DataAdapter, в данном
случае с названием daJobs, в контекстном меню выберем пункт "Создание
Dataset...".
В появившемся диалоговом окне в дополнение к таблице jobs, будет
предложено добавить в Dataset и таблицу employee. Отлично! Ставим флажок
и нажимаем ОК.
Наш Dataset создан. В обозревателе решений это файл Dataset1.xsd, а в
невидимой части формы - объект Dataset11.
Щелкнем дважды по файлу Dataset1.xsd. Откроется схема с двумя нашими
таблицами. Свяжем их по полям job_id.
Для этого откроем Область элементов и перетянем объект Relation на
одну из таблиц. Откроется диалоговое окно. Родительским элементом ставим
таблицу jobs, ну а дочерним, соответственно, таблицу employee. Поле
ключа подставится автоматически, а поле внешнего ключа -
после выбора дочерней таблицы. Имя Relation и наименование ключа
редактор определит автоматически.
Нажимаем ОК и видим, что между таблицами появилась связь
один-ко-многим. Нам осталось еще чуть поработать ручками: добавим в
таблицу employee поле job_desc.
Все! Подготовительная часть закончена. Более-менее приближенно, мы
сделали то, что необходимо делать каждый раз при создании приложения,
работающего с базами данных. Создали новый проект, соединение с БД,
настроили DataAdapter'ы, создали Dataset и отношения между таблицами.
5. Настройка DataGrid
В редакторе перейдем на страницу default.aspx. Перетащим на форму
DataGrid из Области элементов. Щелчком правой кнопки мышки по нему
вызовем контекстное меню и выберем пункт "Автоформат". В нем выберем
формат "Профессиональный1" и закроем диалоговое окно. Впрочем, это на
ваш вкус. Я еще изменил шрифт по умолчанию на Verdana и на один пункт
уменьшил его размер.
В конечном итоге, после всех, в т.ч. и будущих настроек, наш DataGrid
будет иметь вот такой вид.
Ну, а теперь будем его настраивать. Свяжем наш DataGrid с Dataset.
Это очень просто. В свойствах для поля DataSource выбираем Dataset11.
Затем полю DataMember назначаем имя таблицы employee, а полю
DataKeyField - название столбца emp_id из таблицы employee
Следующим действием будет открытие Построителя свойств. Щелчком мыши
на DataGrid вызываем контекстное меню и выбираем пункт "Построитель
свойств…"
В открывшейся форме начинаем формировать наш DataGrid. Слева выберем
пункт "Столбцы" и сразу же снимем флажок с параметра "Создавать столбцы
автоматически".
В списке "Доступные столбцы" перечислены (как Поля данных) столбцы из
таблицы employee, которая входит в наш DataSet11, а также дополнительные
столбцы для управления данными в DataGrid. Наша задача состоит в том,
чтобы выбрать нужные для отображения столбцы. Начнем!
Переместим в список "Выбранные столбцы" следующие столбцы:
- emp_id - и снимем флажок с параметра "Выводить на экран"
- fname - изменим текст верхнего колонтитула на "First Name", и
поставим флажок у параметра "Только для чтения"
- lname - изменим текст верхнего колонтитула на "Last Name", и
поставим флажок у параметра "Только для чтения"
- job_desc - изменим текст верхнего колонтитула на "Job
Position" и в нижней части формы нажмем на ссылку "Преобразовать
этот столбец в столбец шаблона"
Важно следовать данному порядку добавления столбцов!
Далее, добавим еще один дополнительный столбец. Он находится в группе
"Столбец кнопки" под названием "Правка, Обновить, Отмена".
На этом, наш DataGrid почти готов. Подведя итог последних действий,
мы создали DataGrid в 5 столбцов, один из которых невидим, два только
для чтения, 1 предназначен для управления редактированием и 1
представляет собой шаблон. Вот его, последнего, мы и начнем сейчас
настраивать.
6. Создание шаблонного поля с DropDownList
Снова вызываем контекстное меню DataGrid и видим, что в нем появился
пункт "Изменить шаблон". В нем только одно подменю: тот самый столбец,
который мы определили шаблоном.
Выбираем его - открылся редактор шаблонного столбца. Нас в нем
интересуют ItemTemplate - область, которая находится в строке DataGrid в
режиме отображения данных. И EditItemTemplate - соответственно в режиме
редактирования. Левая часть изображения показывает шаблон до нашего
вмешательства. Как видим, ItemTemplate содержит внутри label, а
EditItemTemplate - textbox. Изменим ширину Label1, и удалим textbox.
Вместо него из Области элементов перетащим DropDownList и тоже настроим
по ширине, принимая во внимание длину отображаемого в нем текста.
Оставим его выделенным, и в окне свойств выберем DataSource,
DataMember, DataTextField и DataValueField, как показано на рисунке.
Таким образом, мы привязали DropDownList к данным, которыми он будет
заполняться из родительской таблицы jobs.
Ту же процедуру мы должны сделать с Label1, но немного иначе. Выделим
его, в окне свойств найдем DataBindings, и вызовем диалоговое окно
привязки данных нажатием на кнопочку. Слева выберем свойство Text.
Справа же, нажмем нижний RadioButton и впишем выражение, которое мы
видим в окне "Особого выражения привязки". Оно представляет собой
функцию, которая будет у нас в коде.
Закроем окно, нажимая на ОК. Правой кнопкой мышки кликнем по шаблону
и в контекстном меню выберем пункт "Завершить изменение шаблона".
Все, конструирование закончилось. Осталось написать немного кода,
чтобы наш пример заработал.
7. Заключение
Public Class WebForm1
Inherits System.Web.UI.Page
#Region " Код, автоматически созданный конструктором веб-форм"
Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
' загрузка страницы, соединение с БД, заполнение DataSet
If Not IsPostBack Then
daJobs.Fill(DataSet11, "jobs")
daEmployee.Fill(DataSet11, "employee")
DataGrid1.DataBind()
Session("DS") = DataSet11
Else
DataSet11 = Session("DS")
End If
End Sub
Private Sub DataGrid1_EditCommand(ByVal source As Object,
ByVal e As System.Web.UI.WebControls.DataGridCommandEventArgs) Handles DataGrid1.EditCommand
' редактирование данных в DataGrid
DataGrid1.EditItemIndex = e.Item.ItemIndex
DataBind()
End Sub
Private Sub DataGrid1_CancelCommand(ByVal source As Object,
ByVal e As System.Web.UI.WebControls.DataGridCommandEventArgs) Handles DataGrid1.CancelCommand
' отмена редактирования
DataGrid1.EditItemIndex = -1
DataBind()
End Sub
Private Sub DataGrid1_UpdateCommand(ByVal source As Object,
ByVal e As System.Web.UI.WebControls.DataGridCommandEventArgs) Handles DataGrid1.UpdateCommand
' обновление отредактированных данных в базе
Dim id As String
DataGrid1.EditItemIndex = -1
' определяем ID выбранной строки
id = CType(e.Item.Cells(0).Text, String)
' записываем новые данные в Dataset
With DataSet11.employee.FindByemp_id(id)
.job_id = CType(e.Item.Cells(3).Controls(1), DropDownList).SelectedValue
End With
' обновляем данные в БД
daEmployee.Update(DataSet11)
DataBind()
Page.DataBind()
End Sub
'Public Function BindJob(ByVal o As Object) As String
' Dim drv As DataRowView = o
' Dim dr As DataSet1.employeeRow = drv.Row
' Dim dp As DataSet1.jobsRow = dr.GetParentRow("jobsemployee")
' Return dp.job_desc
'End Function
Public Function BindJob(ByVal o As Object) As String
' Alternatively, since this is strongly typed:
Dim drv As DataRowView = o
Dim dr As DataSet1.employeeRow = drv.Row
Return dr.jobsRow.job_desc
End Function
End Class
Здесь написаны четыре процедуры, которые выполняют инициацию DataSet
при открытии формы, редактирование данных в DataGrid, обновление либо
отмену обновления. А также вышеупомянутая функция BindJob (в двух
вариантах), которая вместо job_id выводит наименование должности.
Вставим этот код (заключенный в красную рамку, с заменой процедуры
Page_Load) внутрь класса WebForm1 на странице default.aspx.vb и
попробуем запустить проект.
Если все успешно, то мы должны получить вот такую картинку.
Выберем другую должность и нажмем "Обновить". Новые данные сохранятся
в базе данных.
Хочу предупредить: это всего лишь пример, и я использовал только
два поля - job_id и job_desc. Но в самой базе они находятся во
взаимосвязи с другими полями, поэтому возможны случаи возникновения
исключений при смене должностей!!!
Поводя итог, снова оговорюсь, данный вариант не претендует на
исключительность. Я также не пытался объяснять код, надеюсь, читатель
сам сможет в нем разобраться и творчески применить в своих собственных
приложениях.
Эта статья не была бы написана без тестового задания, которое мне дал
Андрей Филев (Murano Software), а также без помощи Владислава
Бородина (учебный центр Support, Санкт-Петербург), который помог мне
сделать первые шаги в ASP.NET.
При написании статьи частично были использованы материалы
статьи , в частности функция BindJob.