Использование разных шаблонов для разных браузеров

Любому Web-разработчику хорошо известно, что разные браузеры (например, Microsoft Internet Explorer, Netscape Navigator, Mozilla Firefox и др.) по разному обрабатывают HTML код и, что особенно важно, обладают несколько разными программируемыми моделями, что усложняет создание клиентских сценариев.

Для разрешения этой проблемы существует два основных метода, которые используются в классическом ASP и в ASP.NET 1.x. Первый заключается в том, что браузеру клиента отправляется клиентский код, который, основываясь на типе и версии браузера, выполняет некоторые действия. Второй состоит в перенаправлении браузера пользователя на те страницы, которые специально оптимизированы под конкретный браузер.

ASP.NET 2.0 упрощает создание подобных страниц, поскольку среда выполнения генерирует HTML код для стандартных серверных элементов управления, основываясь на информации о браузере клиента. При использовании шаблонов оформления, можно создать несколько шаблонов, для каждого браузера и в директиве Page страницы указать, какой шаблон использовать.

 

<%@ Page ie:MasterPageFile="ieMainTemplate.master" opera:MasterPageFile="operaMainTemplate.master " mozilla:MasterPageFile="mozillaMainTemplate.master " %>

 

Список браузеров и используемые средой ASP.NET свойства браузеров можно найти в директории:

%WINDIT%\Microsoft.NET\Framework\версия\CONFIG\Browsers

Порядок выполнения работы

В данном порядке выполнения лабораторной работы будет описано создание WEB-приложения, в функции которого входит отображение, добавление, удаление и редактирование групп, отображение, добавление, удаление и редактирование студентов в группе. В качестве источника данных, как и в предыдущей лабораторной работе, будет использоваться СУБД PostgreSQL и созданный в ппредыдущей лабораторной работе слой доступа к данным.

1. Создайте новый проект Веб-приложение ASP.NET (нажмите «Файл», «Создать», «Проект», в появившемся окне выберите «Web», «Веб-приложение ASP.NET», задайте каталог проекта и имя проекта, например lab5).

2. Добавьте в каталог с проектом библиотеки для работы с СУБД PostgreSQL, библиотеки NHibernate и библиотеки Fluent NHibernate. Данные библиотеки можно скачать по ссылкам:

Драйвер к postgreSQL http://www.postgresql.org/
Библиотеки NHibernate http://sourceforge.net/projects/nhibernate/
Библиотеки Fluent NHibernate http://fluentnhibernate.org/

В данном проекте были использованы архивы:

- Npgsql2.0.10-bin-ms.net.zip

- NHibernate-2.1.2.GA-bin.zip

- fluentnhibernate-1.1.zip

Список всех необходимых библиотек приведен ниже:

Npgsql.dll
Mono.Security.dll
NHibernate.dll
Antlr3.Runtime.dll
Iesi.Collections.dll
log4net.dll
Castle.DynamicProxy2.dll
Castle.Core.dll
NHibernate.ByteCode.Castle.dll
FluentNHibernate.dll

Подключите библиотеки Npgsql.dll, NHibernate.dll, FluentNHibernate.dll и NHibernate.ByteCode.Castle к проекту (нажмите правой кнопкой на «Ссылки» в дереве объектов потом на «Добавить ссылку…», перейдите на закладку «Обзор», выберите необходимые файлы).

3. Добавьте в проекте каталоги dao, domain, img, mapping. Каталоги dao, domain, mapping будут использоваться для хранения классов слоя доступа к данным DAO, реализованного в предыдущей лабораторной работе, а каталог img будет использоваться для хранения изображений приложения.

Каталоги dao, domain, img, mapping в обозревателе решений изображены на рисунке 5.1.

Рисунок 5.1 – Каталоги dao, domain, img, mapping в обозревателе решений

4. Скопируйте классы слоя доступа к данным, созданные в предыдущей лабораторной работке в соответствующие каталоги WEB-приложения. Это можно сделать, например, с использованием файлового менеджера Total Commander.

Откройте каталог dao с предыдущей лабораторной работы и скопируйте все классы в каталог dao проекта WEB-приложения. Результаты копирования представлены на рисунке 5.2.

Рисунок 5.2 – Результаты копирования классов с каталога dao предыдущего проекта в каталог dao WEB-приложения

Классы каталогов domain и mapping таким же образом необходимо скопировать в соответствующие каталоги WEB-приложения.

После копирования классов в проекте они не появятся, поэтому их следует добавить в проект (нажмите правой кнопкой мыши на каталог dao и в контекстном меню выберете пункт «Добавить», «Существующий элемент», в открывшемся диалоге выберете все классы каталога dao WEB-приложения и нажмите «Добавить»). Те же действия произведите с классами каталогов domain и mapping. В проекте должны появиться все классы слоя доступа к данным. Результат представлен на рисунке 5.3.

Рисунок 5.3 – Результат добавления классов слоя доступа к данным

Таким образом, все классы слоя доступа к данным были перенесены в WEB-приложение, и их можно использовать для отображения, добавления, удаления, замены данных.

5. Приступим к реализации интерфейса нашего WEB-приложения. Он у нас будет состоять из двух страниц. На одной странице будет отображаться список групп, а по нажатию на группу на второй будет отображаться список студентов группы. Эти страницы будут однотипными, у каждой из них будет шапка с названием страницы, футер (нижняя часть страницы) и меню. В данном случае страниц всего две, но в реальных проектах их может быть намного больше и те части, которые являются для группы страниц однотипными лучше выносить в шаблон страницы.

6. Создадим шаблон страницы для WEB-приложения. Нажмите правой кнопкой мыши на проект, нажмите «Добавить», затем «Создать элемент», в появившемся диалоге выберете «Web», затем «Главная страница», введите имя шаблона страницы, например University и нажмите «Добавить».

7. Откройте шаблон страницы University с помощью редактора главных страниц (нажмите правой кнопкой на шаблон страницы University, выберете «Открыть с помощью», в открывшемся диалоге выберете «Редактор главных страниц (По умолчанию)»). Откроется код шаблона главной страницы, который обычно состоит из html тегов и из тегов ASP.NET. Шаблон главной страницы можно редактировать как в текстовом, так и графическом режиме, перетаскивая необходимые элементы с палитры компонентов, html-теги чаще всего используются для разметки страницы. Неотъемлемым тегом шаблона страницы является тег:

 

<asp:ContentPlaceHolder ID="ContentPlaceHolder1" runat="server">

</asp:ContentPlaceHolder>

 

Вместо этого тега на страницах, которые наследуют шаблон страницы, подставляется необходимое содержимое.

Спроектируем шаблон страницы в графическом режиме.

8. Откройте шаблон страницы University с использованием графического редактора (нажмите два раза на шаблон страницы и из трех возможных вариантов «Конструктор», «Разделить», «Исходный код» выберите «Конструктор»). Для разметки страницы будем использовать таблицы.

9. Откройте палитру компонентов, разместите в верхней части шаблона страницы три компонент Table с раздела HTML. Один компонент будет использоваться для размещения header (верхней части страницы), второй компонент будет использоваться для размещения основной части страницы, а третий будет использоваться для размещения footer(нижней части страницы). Таблицы по умолчанию создаются с тремя рядками и тремя колонками и их необходимо настроить соответствующим образом.

10. Настроим header (верхнюю часть) шаблона. Для верхней таблицы из трех добавлены таблицы установите количество колонок равным 2, а количество строк равным 1. К сожалению, этого нельзя сделать с помощью диспетчера свойств, а только в текстовом режиме, поэтому шаблон страницы необходимо открыть в текстовом режиме и удалите лишние теги <tr> и <td>.

В результате получится код таблицы:

 

<table style="width:100%;">

<tr>

<td>

</td>

<td>

</td>

</tr>

</table>

 

В левую колонку верхней таблицы вставьте компонент Image с раздела «Стандартный», а в правую колонку вставьте компонент Label с того же самого раздела. Выберите для компонента Image изображение, поместите его в каталоге img. Установите с помощью диспетчера свойств URL изображения (свойство ImageUrl). Установите свойство Text у компонента Label – это будет текст заголовка WEB-приложения. Окончательный вариант верхней таблицы в текстовом виде представлен ниже:

 

<table style="width:100%;" cellpadding="0" cellspacing="0">

<tr>

<td width="200">

<asp:Image ID="Image1" runat="server" ImageUrl="~/img/1.png" />

</td>

<td align="center" bgcolor="#8B0000">

<asp:Label ID="Label1" runat="server" Font-Bold="True" Font-Size="20pt"

Text="Черниговский государственный технологический университет"

ForeColor="#EEC900">

</asp:Label>

</td>

</tr>

</table>

 

Как видно из текста таблицы, для первой колони, устанавливается ширина по размеру изображения, а для второй колонки устанавливается цвет заливки и выравнивание по центру.

11. Приступим к реализации центральной части страницы, представленной центральной таблицей. Центральная таблица также должна состоять из одной строчки и двух колонок. В левой колонке будет размещаться меню приложения, но оно в данном примере использоваться не будет, поскольку приложение состоит всего лишь с двух страниц, поэтому мы только расположим меню в левой колонке, заполним названия пунктов меню, а адреса страниц, на которые необходимо переходить при нажатии на пункты меню заполнять не будем. Как удалять лишние колонки и строки, показано в предыдущем пункте данного руководства. Разместите в левой колонке компонент Menu с раздела «Переходы». В правую колонку перетяните компонент ContentPlaceHolder, который на данный момент размещается под всеми таблицами. Текст центральной таблицы представлен ниже:

 

<table style="width:100%;">

<tr>

<td width="200" valign="top">

<table style="width:100%;">

<tr>

<td align="left">

<asp:Label ID="Label2" runat="server" Text="МЕНЮ"

Font-Size="16pt" ForeColor="Maroon">

</asp:Label>

</td>

</tr>

<tr>

<td>

<asp:Menu ID="Menu1" runat="server"

Font-Size="16pt" ForeColor="Maroon">

<Items>

<asp:MenuItem Text="Группы" Value="Группы">

</asp:MenuItem>

<asp:MenuItem Text="Студенты" Value="Студенты">

</asp:MenuItem>

</Items>

</asp:Menu>

</td>

</tr>

</table>

</td>

<td>

<asp:ContentPlaceHolder ID="ContentPlaceHolder1" runat="server">

</asp:ContentPlaceHolder>

</td>

</tr>

</table>

 

Как видно из текста таблицы, левая колонка для удобства разбита на две части еще одной таблицей, в верхней части располагается компонент Label со словом Menu, в нижній располагается самом меню.

12. Приступим к реализации нижней части страницы, представленной нижней таблицей. Она будет состоять с двух строк и одной колонки. В первой строке будет размещаться линия разделения футера от основной части страницы, а во второй строке будет размещаться футер страницы. Текст нижней таблицы приведен ниже:

 

<table style="width:100%;">

<tr>

<td>

<hr style="color: #800000" />

</td>

</tr>

<tr>

<td align="center">

<asp:Label ID="Label3" runat="server"

Text="OrIoN (c)" ForeColor="Maroon">

</asp:Label>

</td>

</tr>

</table>

 

Полный текст шаблона страницы приведен ниже, а внешний вид шаблона страницы приведен на рисунке 5.4.

<%@ Master Language="C#" AutoEventWireup="true" CodeBehind="University.master.cs" Inherits="lab5.University" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

 

<html xmlns="http://www.w3.org/1999/xhtml" >

<head runat="server">

<title>Черниговский государственный технологический университет</title>

</head>

<body>

<form id="form1" runat="server">

<table style="width:100%;" cellpadding="0" cellspacing="0">

<tr>

<td width="200">

<asp:Image ID="Image1" runat="server" ImageUrl="~/img/1.png" />

</td>

<td align="center" bgcolor="#8B0000">

<asp:Label ID="Label1" runat="server"

Font-Bold="True" Font-Size="20pt"

Text="Черниговский государственный технологический университет"

ForeColor="#EEC900">

</asp:Label>

</td>

</tr>

</table>

<table style="width:100%;">

<tr>

<td width="200" valign="top">

<table style="width:100%;">

<tr>

<td align="left">

<asp:Label ID="Label2" runat="server"

Text="МЕНЮ" Font-Size="16pt"

ForeColor="Maroon">

</asp:Label>

</td>

</tr>

<tr>

<td>

<asp:Menu ID="Menu1" runat="server"

Font-Size="16pt" ForeColor="Maroon">

<Items>

<asp:MenuItem Text="Группы" Value="Группы">

</asp:MenuItem>

<asp:MenuItem Text="Студенты"

Value="Студенты">

</asp:MenuItem>

</Items>

</asp:Menu>

</td>

</tr>

</table>

</td>

<td>

<asp:ContentPlaceHolder ID="ContentPlaceHolder1"

runat="server">

</asp:ContentPlaceHolder>

</td>

</tr>

</table>

<table style="width:100%;">

<tr>

<td>

<hr style="color: #800000" />

</td>

</tr>

<tr>

<td align="center">

<asp:Label ID="Label3" runat="server" Text="OrIoN (c)"

ForeColor="Maroon"></asp:Label>

</td>

</tr>

</table>

</form>

</body>

</html>

Рисунок 5.4 – Внешний вид шаблона страницы

13. Шаблон страницы удобно использовать для инициализации сессии NHibernate. Откройте C# код шаблона страница. Каждая страница в том числе и шаблоны в ASP.NET обязательно содержат С# код, открыть который можно раскрыв дерево, узлом которого является страницы. Если шаблон страницы называется University.Master, то его C# код будет называться University.Master.cs. Добавьте над методом Page_Load, который создается автоматически поля:

 

private ISessionFactory factory;

private ISession session;

 

За методом добавьте два вспомагательные метода:

 

//Метод открытия сессии

private ISession openSession(String host, int port, String database,

String user, String passwd)

{

ISession session = null;

//Получение ссылки на текущую сборку

Assembly mappingsAssemly = Assembly.GetExecutingAssembly();

if (factory == null)

{

//Конфигурирование фабрики сессий

factory = Fluently.Configure()

.Database(PostgreSQLConfiguration

.PostgreSQL82.ConnectionString(c => c

.Host(host)

.Port(port)

.Database(database)

.Username(user)

.Password(passwd)))

.Mappings(m => m.FluentMappings

.AddFromAssembly(mappingsAssemly))

.ExposeConfiguration(BuildSchema)

.BuildSessionFactory();

}

//Открытие сессии

session = factory.OpenSession();

return session;

}

 

//Метод для автоматического создания таблиц в базе данных

private static void BuildSchema(Configuration config)

{

//new SchemaExport(config).Create(false, true);

}

Добавьте обработчик события Page_Init:

 

protected void Page_Init(object sender, EventArgs e)

{

session = openSession("localhost", 5432,

"university", "postgres", "111111");

Session["hbmsession"] = session;

}

 

Обработчик события Page_Init вызывается при инициализации страницы, в этот момент и создается сессия NHibernate, которая помещается в объект Session – объект способный хранить необходимы данные, пока активна HTTP-сессия с приложением. Как видно из текста обработчика события Page_Init, настройки подключения к базе прописаны в коде программы, чего делать нежелательно. Все настройки приложения, в том числе и настройки подключения к базе должны храниться в специальном файле Web.config.

Наш шаблон готов и теперь мы можем использовать его для оформления наших страниц.

14. Приступим к реализации главной страницы, на которой будет располагаться список групп. Необходимо будет реализовать такие функции как добавление, удаление замена данных о группах, а также отображение списка студентов группы.

Страница Default.aspx – стартовая страница приложения – создалась в проекте автоматически, ее мы и будем использовать как страницу для отображения списка групп.

Откройте Default.aspx в режиме исходного кода. Удалите весь исходный код кроме первой строчки:

 

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="lab5._Default"%>

 

Вставьте тег <asp:Content> и підключите к странице Default.aspx шаблон страницы:

 

<asp:Content ID="Content1" ContentPlaceHolderID="ContentPlaceHolder1"

runat="server">

</asp:Content>

 

Начальный код страницы должен выглядеть следующим образом:

 

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="lab5._Default" MasterPageFile="~/University.Master"%>

<asp:Content ID="Content1" ContentPlaceHolderID="ContentPlaceHolder1"

runat="server">

</asp:Content>

 

Никаких тегов <html>, <body>, <form> на странице быть не должно. Если страница использует шаблон страницы, во все эти теги уже присутствуют в шаблоне.

15. Переходим к визуальному проектированию страницы Default.aspx. Откройте станицу в режиме исходного кода. Если шаблон был подключен правильно, то страница будет состоять из компонентов расположенных в шаблоне и из компонента, в который можно помещать содержимое текущей страницы. Разметку страницы, как и в шаблоне, будем производить с использованием таблиц.

Вставьте в редактируемую часть страницы таблицу, состоящую из одной колонки и двух рядков. В первом рядке будет отображаться название таблицы, а во втором рядке поместите компонент GridView с раздела «Данные». Этот компонент имеет ряд достоинств и недостатков. Так, например, он удобен для редактирования и удаления записей, но очень неудобен для добавления данных. Компонент GridView способен реагировать на ряд событий, таких как:

RowEditing – возникает, когда строка таблицы переводится в режим редактирования;

RowUpdating – возникает при нажатии на кнопку Update редактируемой строки;

RowDeleting – возникает при нажатии на кнопку Delete;

RowCancelingEdit – возникает при отмене редактирования строки;

RowCommand – это событие возникает при нажатии кнопок, размещенных в строчке таблицы;

PageIndexChanging – возникает при изменении индекса страницы GridView, если настроено постраничное отображение;

Исходный код страницы Default.aspx приведен ниже:

 

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="lab5._Default" MasterPageFile="~/University.Master"%>

 

<asp:Content ID="Content1"

ContentPlaceHolderID="ContentPlaceHolder1" runat="server">

<table align="center">

<!—Строка названия таблицы-->

<tr align="center">

<td>

<asp:Label ID="Label4" runat="server" Text="Список групп"

Font-Size="20pt" ForeColor="Maroon" Font-Bold="True"/>

</td>

</tr>

<!—-Строка, содержащая таблицу для отображения списка групп-->

<tr>

<td>

<asp:GridView ID="GridView1" runat="server"

AutoGenerateColumns="false"

ShowFooter="true" ShowHeader="true"

AllowPaging="true" PageSize="10"

onrowdeleting="GridView1_RowDeleting" Font-Size="14pt"

onrowediting="GridView1_RowEditing"

onrowcancelingedit="GridView1_RowCancelingEdit"

onpageindexchanging="GridView1_PageIndexChanging"

HorizontalAlign="Center"

onrowupdating="GridView1_RowUpdating"

onrowcommand="GridView1_RowCommand" >

<Columns>

<!—-Шаблон колонки для названия группы-->

<asp:TemplateField HeaderText="Название группы"

ItemStyle-Width="200">

<ItemTemplate>

<asp:Label id="myLabel1" runat="server"

Text='<%# Bind("GroupName")%>' />

</ItemTemplate>

<EditItemTemplate>

<asp:TextBox ID="myTextBox1" runat="server" Width="200"

Text='<%# Bind("GroupName") %>'/>

</EditItemTemplate>

<FooterTemplate>

<asp:TextBox ID="myFooterTextBox1" runat="server"

Width="200" Text='<%# Bind("GroupName") %>' />

</FooterTemplate>

</asp:TemplateField>

<!—-Шаблон колонки для ФИО куратора -->

<asp:TemplateField HeaderText="ФИО куратора"

ItemStyle-Width="300">

<ItemTemplate>

<asp:Label id="myLabel2" runat="server"

Text='<%# Bind("CuratorName")%>' />

</ItemTemplate>

<EditItemTemplate>

<asp:TextBox ID="myTextBox2" runat="server" Width="300"

Text='<%# Bind("CuratorName") %>'/>

</EditItemTemplate>

<FooterTemplate>

<asp:TextBox ID="myFooterTextBox2" runat="server" Width="300"

Text='<%# Bind("CuratorName") %>' />

</FooterTemplate>

</asp:TemplateField>

<!—-Шаблон колонки для ФИО старосты-->

<asp:TemplateField HeaderText="ФИО старосты"

ItemStyle-Width="300">

<ItemTemplate>

<asp:Label id="myLabel3" runat="server"

Text='<%# Bind("HeadmanName")%>' />

</ItemTemplate>

<EditItemTemplate>

<asp:TextBox ID="myTextBox3" runat="server" Width="300"

Text='<%# Bind("HeadmanName") %>'/>

</EditItemTemplate>

<FooterTemplate>

<asp:TextBox ID="myFooterTextBox3" runat="server"

Width="300" Text='<%# Bind("HeadmanName") %>' />

</FooterTemplate>

</asp:TemplateField>

<!—-Шаблон командной колонки-->

<asp:TemplateField HeaderText="Команды" ItemStyle-

HorizontalAlign="Center" FooterStyle-HorizontalAlign="Center">

<ItemTemplate>

<asp:ImageButton ID="ibEdit" runat="server"

CommandName="Edit" Text="Edit"

ImageUrl="~/img/6.png" />

<asp:ImageButton ID="ibDelete" runat="server"

CommandName="Delete" Text="Delete"

ImageUrl="~/img/3.png" />

<asp:ImageButton ID="lbSelect" runat="server"

CommandName="Select"

ImageUrl="~/img/4.png"

CommandArgument='<%# Container.DataItemIndex %>'/>

</ItemTemplate>

<EditItemTemplate>

<asp:ImageButton ID="ibUpdate" runat="server"

CommandName="Update" Text="Update"

ImageUrl="~/img/5.png" />

<asp:ImageButton ID="ibCancel" runat="server"

CommandName="Cancel" Text="Cancel"

ImageUrl="~/img/7.png" />

</EditItemTemplate>

<FooterTemplate>

<asp:ImageButton ID="ibInsert" runat="server"

CommandName="Insert" OnClick="ibInsert_Click"

ImageUrl="~/img/2.png" />

</FooterTemplate>

</asp:TemplateField>

</Columns>

<!—-Шаблон для отображения таблицы с пустыми данными-->

<EmptyDataTemplate>

<table border="1" cellpadding="0" cellspacing="0">

<tr>

<td width="200" align="center">Название группы</td>

<td width="300" align="center">ФИО куратора</td>

<td width="300" align="center">ФИО старосты</td>

<td>Команды</td>

</tr>

<tr>

<td>

<asp:TextBox ID="emptyGroupNameTextBox" runat="server"

Width="200"/>

</td>

<td>

<asp:TextBox ID="emptyCuratorNameTextBox" runat="server"

Width="300"/>

</td>

<td>

<asp:TextBox ID="emptyHeadmanNameTextBox" runat="server"

Width="300"/>

</td>

<td align="center">

<asp:ImageButton ID="emptyImageButton" runat="server"

ImageUrl="~/img/2.png"

OnClick="ibInsertInEmpty_Click"/>

</td>

</tr>

</table>

</EmptyDataTemplate>

<PagerStyle HorizontalAlign ="Center" />

</asp:GridView>

</td>

</tr>

</table>

</asp:Content>

 

Таблица состоит из колонок, размещенных в теге <Columns>. Для каждой колонки определен шаблон из трех частей. В первой части шаблона описывается, как будет выглядеть элемент строки в обычном состоянии. Во второй части шаблона описывается, как будет выглядеть элемент строки таблицы в режиме редактирования. В третьей части шаблона описывается, как будет выглядеть футер таблицы.

Поскольку компонент GridView при отсутствии данных в источнике данных не отображается на то его внешний вид при отсутствии данных необходимо описать с использование тега <EmptyDataTemplate>.

Для каждой кнопки таблицы необходимо выбрать изображение и поместить его в каталог img.

Далее необходимо реализовать обработчики событий по нажатия на кнопки компонента GridView.

16. Откройте C# код страницы Default.aspx. Поскольку все функции нашего приложения, которые нам необходимо запрограммировать будут использовать сессию NHibernate, то в первую получить сессию NHibernate c объекта Session.

Добавьте обработчик события Page_Prerender после пустого обработчика событий Page_Load:

 

protected void Page_Prerender(object sender, EventArgs e)

{

ISession session = (ISession)Session["hbmsession"];

DAOFactory factory = new NHibernateDAOFactory(session);

IGroupDAO groupDAO = factory.getGroupDAO();

List<Group> groups = groupDAO.GetAll();

GridView1.DataSource = groups;

GridView1.DataBind();

}

 

В этом обработчике из объекта Session происходит получение сессии NHibernate.

17. Далее необходимо реализовать функцию добавления группы. Поскольку компонент GridView не отображает данные при пустом источнике данных и кнопка добавления данных при непустом источнике данных и при пустом источнике данных – это две разные кнопки, то необходимо реализовывать два разных обработчика событий нажатия на кнопку добавить.

Ниже приведен код для обработчиков нажатия на кнопку «Добавить» для пустого и непустого источника данных:

 

//Обработчик нажатия на добавить

protected void ibInsert_Click(object sender, EventArgs e)

{

//Получаем значения полей

string s1 =

((TextBox)GridView1.FooterRow.FindControl("MyFooterTextBox1")).Text;

string s2 =

((TextBox)GridView1.FooterRow.FindControl("MyFooterTextBox2")).Text;

string s3 =

((TextBox)GridView1.FooterRow.FindControl("MyFooterTextBox3")).Text;

//Создаем группу

Group group = new Group();

group.GroupName = s1;

group.CuratorName = s2;

group.HeadmanName = s3;

//Создаем DAO группы

ISession session = (ISession)Session["hbmsession"];

DAOFactory factory = new NHibernateDAOFactory(session);

IGroupDAO groupDAO = factory.getGroupDAO();

groupDAO.SaveOrUpdate(group);

Response.Redirect(HttpContext.Current.Request.Url.ToString());

}

 

//Добавление первой записи в пустой GridView

protected void ibInsertInEmpty_Click(object sender, EventArgs e)

{

var parent = ((Control)sender).Parent;

var groupNameTextBox = parent

.FindControl("emptyGroupNameTextBox") as TextBox;

var curatorNameTextBox = parent

.FindControl("emptyCuratorNameTextBox") as TextBox;

var headmanNameTextBox = parent

.FindControl("emptyHeadmanNameTextBox") as TextBox;

Group group = new Group();

group.GroupName = groupNameTextBox.Text;

group.CuratorName = curatorNameTextBox.Text;

group.HeadmanName = headmanNameTextBox.Text;

ISession session = (ISession)Session["hbmsession"];

DAOFactory factory = new NHibernateDAOFactory(session);

IGroupDAO groupDAO = factory.getGroupDAO();

groupDAO.SaveOrUpdate(group);

Response.Redirect(HttpContext.Current.Request.Url.ToString());

}

 

18. Далее необходимо реализовать функцию удаления группы. Удаление группы происходит по событию RowDeleting, обработчик которого приведен ниже:

 

//Удаление записи

protected void GridView1_RowDeleting(object sender,

GridViewDeleteEventArgs e)

{

//Получить индекс выделенной строки

int index = e.RowIndex;

GridViewRow row = GridView1.Rows[index];

//Получить название группы

string key = ((Label)(row.Cells[0].FindControl("myLabel1"))).Text;

//Создание DAO группы

ISession hbmSession = (ISession)Session["hbmsession"];

DAOFactory factory = new NHibernateDAOFactory(hbmSession);

IGroupDAO groupDAO = factory.getGroupDAO();

//Получение группы по имени

Group group = groupDAO.getGroupByName(key);

//Удаление группы

if (group != null)

{

groupDAO.Delete(group);

}

Response.Redirect(HttpContext.Current.Request.Url.ToString());

}

 

19. Далее необходимо реализовать функцию редактирования записи. Строка компонента GridView может пребывать в обычном состоянии и в режиме редактирования. В обычном состоянии в командной колонке отображаются кнопки «Редактировать» и «Удалить», а в режиме редактирования отображаются кнопки «Обновить» и «Отменить». В процессе редактирования записи учувствует три кнопки «Редактировать», «Обновить» и «Отменить» и необходимо реализовать обработчики событий нажатия на эти кнопки. Ниже приведен код обработчиков:

 

//Перевести строку в режим редактирования

protected void GridView1_RowEditing(object sender, GridViewEditEventArgs e)

{

//Получить индекс выделенной строки

int index = e.NewEditIndex;

GridViewRow row = GridView1.Rows[index];

//Получение старых значений полей в строке GridView

string oldGroupName = ((Label)(row.Cells[0].FindControl("myLabel1"))).Text;

//Сохранение названия группы в коллекции ViewState

ViewState["oldGroupName"] = oldGroupName;

GridView1.EditIndex = index;

GridView1.ShowFooter = false;

GridView1.DataBind();

}

 

//Отмена редактирования записи

protected void GridView1_RowCancelingEdit(object sender,

GridViewCancelEditEventArgs e)

{

GridView1.EditIndex = -1;

GridView1.ShowFooter = true;

GridView1.DataBind();

}

 

//Редактирование строки

protected void GridView1_RowUpdating(object sender,

GridViewUpdateEventArgs e)

{

int index = e.RowIndex;

GridViewRow row = GridView1.Rows[index];

string newGroupName =

((TextBox)(row.Cells[0].FindControl("myTextBox1"))).Text;

string newCuratorName =

((TextBox)(row.Cells[1].FindControl("myTextBox2"))).Text;

string newHeadmanName =

((TextBox)(row.Cells[2].FindControl("myTextBox3"))).Text;

string oldGroupName = (string)ViewState["oldGroupName"];

//Создание DAO группы

ISession hbmSession = (ISession)Session["hbmsession"];

DAOFactory factory = new NHibernateDAOFactory(hbmSession);

IGroupDAO groupDAO = factory.getGroupDAO();

//Получение группы по имени

Group group = groupDAO.getGroupByName(oldGroupName);

group.GroupName = newGroupName;

group.CuratorName = newCuratorName;

group.HeadmanName = newHeadmanName;

groupDAO.SaveOrUpdate(group);

GridView1.EditIndex = -1;

GridView1.ShowFooter = true;

GridView1.DataBind();

}

 

20. Последней функцией будет отображение списка студентов по нажатию на кнопку студенты в строке группы. По нажатию на эту кнопку должна загрузиться страница со списком студентов заданной группы. Обработчик нажатия на кнопку «Студенты» приведен ниже:

 

//Вывод списка всех студентов

protected void GridView1_RowCommand(object sender,

GridViewCommandEventArgs e)

{

if (e.CommandName == "Select")

{

int index = Convert.ToInt32(e.CommandArgument);

GridViewRow row = GridView1.Rows[index];

string groupName = ((Label)(row.Cells[0].FindControl("myLabel1"))).Text;

Session["keyGroupName"] = groupName;

Response.Redirect("StudentForm.aspx");

}

}

 

21. Наш компонент GridView поддерживает постраничное отображение данных, и событие переключения между страницами необходимо обработать, иначе данные не будут правильно отображаться. Ниже приведен код обработчика события переключения между страницами:

 

//Изменение номера текущей страницы

protected void GridView1_PageIndexChanging(object sender,

GridViewPageEventArgs e)

{

GridView1.PageIndex = e.NewPageIndex;

GridView1.EditIndex = -1;

GridView1.ShowFooter = true;

GridView1.DataBind();

}

 

Внешний вид главной WEB-формы в запущенном виде приведен на рисунке 5.5.

Рисунок 5.5 – Внешний вид главной WEB-формы

Все функции касающиеся работы с группами успешно реализованы. Приступим к реализации функций связанных со студентами.

22. В первую очередь необходимо создать новую страницу – WEB-форму, как она называется в ASP.NET. Чтобы создать новую WEB-форму нажмите на проекте правой кнопкой мыши, выберите пункт меню «Добавить», затем «Создать элемент», в разделе «Web» появившегося диалога необходимо выбрать «Форма Web Form». Введите название новой WEB-формы, например StudentForm и нажмите на «Добавить».

23. Откройте новую WEB-форму StudentForm в режиме исходного кода. Удалите весь текст, кроме первой строки, и подключите к WEB-форме шаблон University. Исходный код WEB-формы StudentForm приведен ниже:

 

<%@ Page Language="C#" AutoEventWireup="true"

CodeBehind="StudentForm.aspx.cs" Inherits="lab5.StudentForm"

MasterPageFile="~/University.Master"%>

 

<asp:Content ID="Content1" ContentPlaceHolderID="ContentPlaceHolder1"

runat="server">

 

</asp:Content>

 

24. Приступим к визуальному проектированию новой WEB-формы. Откройте форму в режиме конструктора. Для разметки страницы можно использовать компонент Table. Поместите компонент Table с раздела «HTML» в редактируемой области страницы StudentForm. Оставьте у таблицы одну колонку и два рядка. В первом рядке разместите два компонента Label. Первуй компонент Label будет использоваться для отображения статического текста, а второй компонент будет использоваться для отображения названия группы. Во вторую строку таблицы поместите компонент GridView.

Полный текст StudentForm приведен ниже:

 

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="StudentForm.aspx.cs" Inherits="lab5.StudentForm" MasterPageFile="~/University.Master"%>

 

<asp:Content ID="Content1" ContentPlaceHolderID="ContentPlaceHolder1"

runat="server">

<table style="width:100%;">

<tr align="center">

<td>

<asp:Label ID="Label4" runat="server"

Text="Список студентов группы "

Font-Bold="True" Font-Size="20pt" ForeColor="Maroon">

</asp:Label>

<asp:Label ID="Label5" runat="server" Font-Bold="True"

Font-Size="20pt" ForeColor="Maroon">

</asp:Label>

</td>

</tr>

<tr>

<td>

<asp:GridView ID="GridView1" runat="server"

AutoGenerateColumns="false"

ShowFooter="true" ShowHeader="true"

AllowPaging="true" PageSize="10"

Font-Size="14pt" HorizontalAlign="Center"

onrowcancelingedit="GridView1_RowCancelingEdit"

onrowdeleting="GridView1_RowDeleting"

onrowediting="GridView1_RowEditing"

onrowupdating="GridView1_RowUpdating"

onpageindexchanging="GridView1_PageIndexChanging">

<Columns>

<asp:TemplateField HeaderText="Имя студента"

ItemStyle-Width="250">

<ItemTemplate>

<asp:Label id="myLabel1" runat="server"

Text='<%# Bind("FirstName")%>' />

</ItemTemplate>

<EditItemTemplate>

<asp:TextBox ID="myTextBox1" runat="server" Width="250"

Text='<%# Bind("FirstName") %>'/>

</EditItemTemplate>

<FooterTemplate>

<asp:TextBox ID="myFooterTextBox1" runat="server"

Width="250" Text='<%# Bind("FirstName") %>' />

</FooterTemplate>

</asp:TemplateField>

<asp:TemplateField HeaderText="Фамилия студента"

ItemStyle-Width="250">

<ItemTemplate>

<asp:Label id="myLabel2" runat="server"

Text='<%# Bind("LastName")%>' />

</ItemTemplate>

<EditItemTemplate>

<asp:TextBox ID="myTextBox2" runat="server" Width="250"

Text='<%# Bind("LastName") %>'/>

</EditItemTemplate>

<FooterTemplate>

<asp:TextBox ID="myFooterTextBox2" runat="server"

Width="250" Text='<%# Bind("LastName") %>' />

</FooterTemplate>

</asp:TemplateField>

<asp:TemplateField HeaderText="Пол" ItemStyle-Width="50">

<ItemTemplate>

<asp:Label id="myLabel3" runat="server"

Text='<%# Bind("Sex")%>' />

</ItemTemplate>

<EditItemTemplate>

<asp:TextBox ID="myTextBox3" runat="server" Width="50"

Text='<%# Bind("Sex") %>'/>

</EditItemTemplate>

<FooterTemplate>

<asp:TextBox ID="myFooterTextBox3" runat="server"

Width="50" Text='<%# Bind("Sex") %>' />

</FooterTemplate>

</asp:TemplateField>

<asp:TemplateField HeaderText="Год рождения"

ItemStyle-Width="100">

<ItemTemplate>

<asp:Label id="myLabel4" runat="server"

Text='<%# Bind("Year")%>' />

</ItemTemplate>

<EditItemTemplate>

<asp:TextBox ID="myTextBox4" runat="server" Width="100"

Text='<%# Bind("Year") %>'/>

</EditItemTemplate>

<FooterTemplate>

<asp:TextBox ID="myFooterTextBox4" runat="server"

Width="100" Text='<%# Bind("Year") %>' />

</FooterTemplate>

</asp:TemplateField>

<asp:TemplateField HeaderText="Команды"

ItemStyle-HorizontalAlign="Center"

FooterStyle-HorizontalAlign="Center">

<ItemTemplate>

<asp:ImageButton ID="ibEdit" runat="server"

CommandName="Edit" Text="Edit" ImageUrl="~/img/6.png"/>

<asp:ImageButton ID="ibDelete" runat="server"

CommandName="Delete" Text="Delete"

ImageUrl="~/img/3.png" />

</ItemTemplate>

<EditItemTemplate>

<asp:ImageButton ID="ibUpdate" runat="server"

CommandName="Update" Text="Update"

ImageUrl="~/img/5.png" />

<asp:ImageButton ID="ibCancel" runat="server"

CommandName="Cancel" Text="Cancel"

ImageUrl="~/img/7.png" />

</EditItemTemplate>

<FooterTemplate>

<asp:ImageButton ID="ibInsert" runat="server"

CommandName="Insert" OnClick="ibInsert_Click"

ImageUrl="~/img/2.png" />

</FooterTemplate>

</asp:TemplateField>

</Columns>

<EmptyDataTemplate>

<table border="1" cellpadding="0" cellspacing="0">

<tr>

<td width="250" align="center">

Имя студента

</td>

<td width="250" align="center">

Фамилия студента

</td>

<td width="50" align="center">

Пол

</td>

<td width="100" align="center">

Год рождения

</td>

<td>

Команды

</td>

</tr>

<tr>

<td>

<asp:TextBox ID="emptyFirstNameTextBox" runat="server"

Width="250"/>

</td>

<td>

<asp:TextBox ID="emptyLastNameTextBox" runat="server"

Width="250"/>

</td>

<td>

<asp:TextBox ID="emptySexTextBox" runat="server"

Width="50"/>

</td>

<td>

<asp:TextBox ID="emptyYearTextBox" runat="server"

Width="100"/>

</td>

<td align="center">

<asp:ImageButton ID="emptyImageButton" runat="server"

ImageUrl="~/img/2.png"

OnClick="ibInsertInEmpty_Click"/>

</td>

</tr>

</table>

</EmptyDataTemplate>

<PagerStyle HorizontalAlign ="Center" />

</asp:GridView>

</td>

</tr>

 

</table>

</asp:Content>

 

В отличие от таблицы групп, таблица студентов содержит не три колонки, а четыре, та также отсутствует кнопка для отображения списка студентов.

25. Далее необходимо запрограммировать функции добавления удаления, редактирования записей студентов. Откройте C# кода формы StudentForm. Как и в главной форме для начала необходимо реализовать функцию отображения студентов заданной группы в таблице. Это можно реализовать в обработчике события Page_Prerender. Текст обработчика этого события приведен ниже:

 

protected void Page_Prerender(object sender, EventArgs e)

{

string keyGroup = (string)Session["keyGroupName"];

Label5.Text = keyGroup;

ISession session = (ISession)Session["hbmsession"];

DAOFactory factory = new NHibernateDAOFactory(session);

IGroupDAO groupDAO = factory.getGroupDAO();

IList<Student> students = groupDAO.getAllStudentOfGroup(keyGroup);

GridView1.DataSource = students;

GridView1.DataBind();

}

 

26. Далее необходимо реализовать функцию добавления записей о студентах. Как и для таблицы групп, добавление представлено двумя обработчиками событий:

 

protected void ibInsert_Click(object sender, EventArgs e)

{

string keyGroup = (string)Session["keyGroupName"];

//Получаем значения полей

string s1 =

((TextBox)GridView1.FooterRow.FindControl("MyFooterTextBox1")).Text;

string s2 =

((TextBox)GridView1.FooterRow.FindControl("MyFooterTextBox2")).Text;

string s3 =

((TextBox)GridView1.FooterRow.FindControl("MyFooterTextBox3")).Text;

string s4 =

((TextBox)GridView1.FooterRow.FindControl("MyFooterTextBox4")).Text;

 

//Создаем сессию

ISession session = (ISession)Session["hbmsession"];

DAOFactory factory = new NHibernateDAOFactory(session);

IGroupDAO groupDAO = factory.getGroupDAO();

Group group = groupDAO.getGroupByName(keyGroup);

IStudentDAO studentDAO = factory.getStudentDAO();

//Создаем объект студента и заполняем его поля

Student student = new Student();

student.FirstName = s1;

student.LastName = s2;

student.Sex = s3[0];

student.Year = Convert.ToInt32(s4);

student.Group = group;

group.StudentList.Add(student);

//Сохраняем объект студента

studentDAO.SaveOrUpdate(student);

Response.Redirect(HttpContext.Current.Request.Url.ToString());

}

 

protected void ibInsertInEmpty_Click(object sender, EventArgs e)

{

string keyGroup = (string)Session["keyGroupName"];

//Получаем значения полей ввода

var parent = ((Control)sender).Parent;

var firstNameTextBox = parent

.FindControl("emptyFirstNameTextBox") as TextBox;

var lastNameTextBox = parent

.FindControl("emptyLastNameTextBox") as TextBox;

var sexTextBox = parent.FindControl("emptySexTextBox") as TextBox;

var yearTextBox = parent.FindControl("emptyYearTextBox") as TextBox;

//Создаем сессию

ISession session = (ISession)Session["hbmsession"];

DAOFactory factory = new NHibernateDAOFactory(session);

IGroupDAO groupDAO = factory.getGroupDAO();

Group group = groupDAO.getGroupByName(keyGroup);

IStudentDAO studentDAO = factory.getStudentDAO();

//Создаем объект студента и заполняем его поля

Student student = new Student();

student.FirstName = firstNameTextBox.Text;

student.LastName = lastNameTextBox.Text;

student.Sex = sexTextBox.Text[0];

student.Year = Convert.ToInt32(yearTextBox.Text);

student.Group = group;

group.StudentList.Add(student);

//Сохраняем объект студента

studentDAO.SaveOrUpdate(student);

Response.Redirect(HttpContext.Current.Request.Url.ToString());

}

 

27. Далее необходимо реализовать функцию удаления записи о студенте. Это происходит в обработчике события приведенном ниже:

 

//Удаление строки

protected void GridView1_RowDeleting(object sender,

GridViewDeleteEventArgs e)

{

string keyGroup = (string)Session["keyGroupName"];

//Получить индекс выделенной строки

int index = e.RowIndex;

GridViewRow row = GridView1.Rows[index];

//Получить имя студента

string firstName = ((Label)(row.Cells[0].FindControl("myLabel1"))).Text;

string lastName = ((Label)(row.Cells[1].FindControl("myLabel2"))).Text;

ISession hbmSession = (ISession)Session["hbmsession"];

DAOFactory factory = new NHibernateDAOFactory(hbmSession);

IStudentDAO studentDAO = factory.getStudentDAO();

Student student =

studentDAO.getStudentByGroupFirstNameAndLastName(keyGroup, firstName,

lastName);

//Удаление студента

if (student != null)

{

student.Group.StudentList.Remove(student);

studentDAO.Delete(student);

}

Response.Redirect(HttpContext.Current.Request.Url.ToString());

}

 

28. И последняя функция, которую необходимо реализовать, это замена студента, которая, как и в таблице группы представлена тремя обработчиками событий:

 

//Перевод строки в режим редактирования

protected void GridView1_RowEditing(object sender, GridViewEditEventArgs e)

{

//Получить индекс выделенной строки

int index = e.NewEditIndex;

GridViewRow row = GridView1.Rows[index];

//Получение старых значений полей в строке GridView

string oldFirstName = ((Label)(row.Cells[0].FindControl("myLabel1"))).Text;

string oldLastName = ((Label)(row.Cells[1].FindControl("myLabel2"))).Text;

//Сохранение названия группы в коллекции ViewState

ViewState["oldFirstName"] = oldFirstName;

ViewState["oldLastName"] = oldLastName;

GridView1.EditIndex = index;

GridView1.ShowFooter = false;

GridView1.DataBind();

}

 

//Отмена редактирования строки

protected void GridView1_RowCancelingEdit(object sender,

GridViewCancelEditEventArgs e)

{

GridView1.EditIndex = -1;

GridView1.ShowFooter = true;

GridView1.DataBind();

}

 

//Редактирование строки

protected void GridView1_RowUpdating(object sender,

GridViewUpdateEventArgs e)

{

string keyGroup = (string)Session["keyGroupName"];

int index = e.RowIndex;

GridViewRow row = GridView1.Rows[index];

string newFirstName =

((TextBox)(row.Cells[0].FindControl("myTextBox1"))).Text;

string newLastName =

((TextBox)(row.Cells[1].FindControl("myTextBox2"))).Text;

string newSex = ((TextBox)(row.Cells[2].FindControl("myTextBox3"))).Text;

string newYear = ((TextBox)(row.Cells[2].FindControl("myTextBox4"))).Text;

string oldFirstName = (string)ViewState["oldFirstName"];

string oldLastName = (string)ViewState["oldLastName"];

//Создание DAO группы

ISession hbmSession = (ISession)Session["hbmsession"];

DAOFactory factory = new NHibernateDAOFactory(hbmSession);

IStudentDAO studentDAO = factory.getStudentDAO();

//Получение группы по имени

Student student =

studentDAO.getStudentByGroupFirstNameAndLastName(keyGroup, oldFirstName,

oldLastName);

student.FirstName = newFirstName;

student.LastName = newLastName;

student.Sex = newSex[0];

student.Year = Convert.ToInt32(newYear);

studentDAO.SaveOrUpdate(student);

GridView1.EditIndex = -1;

GridView1.ShowFooter = true;

GridView1.DataBind();

}

 

29. Поскольку GridView поддерживает постраничное отображение данных то необходимо обработать события перехода на следующую страницу:

 

protected void GridView1_PageIndexChanging(object sender,

GridViewPageEventArgs e)

{

GridView1.PageIndex = e.NewPageIndex;

GridView1.EditIndex = -1;

GridView1.ShowFooter = true;

GridView1.DataBind();

}

 

Форма студентов в запущенном виде представлена на рисунке 5.6.

Рисунок 5.6 – Внешний вид WEB-формы студентов

Задание на лабораторную работу

Создайте WEB-приложение, описанное в ходе выполнения лабораторной работы, но объекты предметной области необходимо выбрать с таблицы 5.1. Номер варианта определяется последней цифрой зачетной книжки. Варианты полностью соответствуют вариантам заданий с предыдущей лабораторной работы.

Таблица 5.1 – Варианты заданий

Номер варианта Предметная область
Пиццерия (Официант, Посетитель)
Магазин (Поставщик, Товар)
Супермаркет (Продавец, Товар)
Отделение милиции (Милиционер, Нарушитель)
Больница (Врач, Пациент)
Кинотеатр (Кинозал, Посетитель)
Корабль (Каюта, Пассажир)
Предприятие (Отдел, Сотрудник)
Библиотека (Книга, Читатель)

 

Содержание отчета

- фамилия и имя исполнителя лабораторной работы;

- номер и название лабораторной работы;

- цель лабораторной работы;

- краткие теоретические сведенья на одну страницу;

- ход работы (листинги программ, скриншоты программ);

- выводы о проделанной работе.

Контрольные вопросы

1. Что такое шаблон страницы?

2. Для чего используется шаблон страницы?

3. Какие этапы жизненного цикла страницы ASP.NET?

4. Как происходит генерация кода страницы на основе шаблона страницы?

5. Для чего нужна трехслойная архитектура приложения?


 

6 Лабораторная работа № 6
модульное тестирование

Цель работы

Изучить технологии модульного тестирования. Получить практические навыки по работе с Unit Testing Framework от Microsoft.

Теоретические сведенья