11. Додаток [SimuPaie] — версія 7 — ASP.NET / багатовидовий / багатосторінковий
Рекомендовані матеріали: довідка [1], Розробка WEB з ASP.NET, 1.1 параграф: Приклади
Зараз ми розглядаємо версію, функціонально ідентичну трирівневому додатку ASP.NET, який ми вивчали раніше ([pam-v4-3tier-nhibernate-multivues-monopage]), але змінюємо архітектуру останнього наступним чином: якщо в попередній версії подання реалізовувалися за допомогою єдиної сторінки ASPX, то тут вони будуть реалізовані трьома сторінками ASPX.
Архітектура попереднього додатка була такою:
![]() |
Тут ми маємо архітектуру MVC (Модель – Вигляд – Контролер):
- [Default.aspx.cs] містить код контролера. Сторінка [Default.aspx] є єдиним посередником у взаємодії з клієнтом. Через неї проходять усі запити клієнта.
- [Saisies, Simulation, Simulations, ...] — це представлення. Ці представлення реалізовано тут за допомогою компонентів [View] на сторінці [Default.aspx].
Архітектура нової версії буде такою:
![]() |
- змінюється лише рівень [web]
- вигляд (те, що відображається користувачеві) не змінюється.
- Код контролера, який у попередній версії повністю містився у [Default.aspx.cs], тепер розподілено між кількома сторінками:
- [MasterPage.master]: сторінка, яка виокремлює елементи, спільні для різних переглядів: верхній банер із опціями меню
- [Formulaire.aspx]: сторінка, яка відображає форму симуляції та керує діями, що відбуваються в цій формі
- [Simulations.aspx]: сторінка, яка відображає список моделювань та керує діями, що відбуваються на цій сторінці
- [Erreurs.aspx]: сторінка, яка відображається у разі помилки під час ініціалізації додатка. На цій сторінці неможливо виконувати жодних дій.
Можна вважати, що тут маємо архітектуру MVC з декількома контролерами, тоді як архітектура попередньої версії була архітектурою MVC з одним контролером.
Обробка запиту клієнта відбувається за такими етапами:
- клієнт надсилає запит до додатка. Він надсилає його на одну з двох сторінок [Formulaire.aspx, Simulations.aspx].
- запитана сторінка обробляє цей запит. Для цього їй може знадобитися допомога рівня [métier], якому, у свою чергу, може знадобитися рівень [dao], якщо необхідно обмінятися даними з базою даних. Додаток отримує відповідь від рівня [métier].
- Згідно з нею, воно вибирає (3) представлення (= відповідь), яке слід надіслати клієнту, надаючи йому (4) необхідну інформацію (шаблон).
- Відповідь надсилається клієнту (5)
11.1. Види додатка
Користувачеві доступні такі види:
- - вигляд [VueSaisies], що відображає форму моделювання

- - вигляд [VueSimulation], що використовується для відображення детального результату моделювання:

- - погляд [VueSimulations], що містить перелік моделювань, виконаних клієнтом

- - вигляд [VueSimulationsVides], який вказує, що у клієнта немає або більше немає моделювань:

- перегляд [VueErreurs], який вказує на помилку ініціалізації програми:

11.2. Генерація переглядів у середовищі з кількома контролерами
У попередній версії всі подання генерувалися на основі єдиної сторінки [Default.aspx]. Вона містила два компоненти [MultiView], а подання складалися з одного або двох компонентів [View], що належали до цих двох компонентів [MultiView].
Ця архітектура є ефективною, коли кількість переглядів невелика, але досягає своїх меж, щойно кількість компонентів, що утворюють різні перегляди, стає значною: адже при кожному запиті, що надходить на єдину сторінку [Default.aspx], всі її компоненти інстанціюються, хоча для формування відповіді користувачеві використовуються лише деякі з них. Таким чином, при кожному новому запиті виконується зайва робота, що стає обтяжливою, коли загальна кількість компонентів сторінки є значною.
Виходом із ситуації є розподіл представлень між різними сторінками. Саме це ми й робимо тут. Розглянемо два різні випадки формування представлень:
- запит надходить на сторінку P1, і вона формує відповідь
- запит надсилається на сторінку P1, яка звертається до сторінки P2 з проханням згенерувати відповідь
11.2.1. Випадок 1: одна сторінка-контролер / один вигляд
У випадку 1 ми повертаємося до архітектури з одним контролером попередньої версії, де сторінка [Default.aspx] є сторінкою P1:
![]() |
- клієнт надсилає запит на сторінку P1 (1)
- сторінка P1 обробляє цей запит. Для цього їй може знадобитися допомога рівня [métier] (2), якому, у свою чергу, може знадобитися рівень [dao], якщо необхідно обмінятися даними з базою даних. Додаток отримує відповідь від шару [métier].
- Згідно з ним, вона обирає (3) представлення (= відповідь), яке слід надіслати клієнту, надаючи йому (4) інформацію (шаблон), яка їй потрібна. Тут йдеться про те, щоб вибрати на сторінці P1 компоненти [Panel] або [View] для відображення та ініціалізувати компоненти, що містяться в них.
- відповідь надсилається клієнту (5)
Ось два приклади, взяті з розглянутого додатка:
[page Formulaire.aspx]
![]() |
- у [1]: користувач, замовивши сторінку [Formulaire.aspx], запитує симуляцію
- у [2]: сторінка [Formulaire.aspx] обробила цей запит і самостійно згенерувала відповідь, відобразивши компонент [View], який не відображався на [1]
[page Simulations.aspx]
![]() |
- у [1]: користувач, після запиту сторінки [Simulations.aspx], хоче видалити симуляцію
- у [2]: сторінка [Simulations.aspx] опрацювала цей запит і самостійно сформувала відповідь, знову відобразивши новий список симуляцій.
2 ![]() |
11.2.2. Випадок 2: сторінка 1 — контролер, сторінка 2 — контролер / представлення
Випадок 2 може охоплювати різні архітектури. Ми оберемо таку:
![]() |
- клієнт надсилає запит на сторінку P1 (1)
- сторінка P1 обробляє цей запит. Для цього їй може знадобитися допомога рівня [métier] (2), якому, у свою чергу, може знадобитися рівень [dao], якщо необхідно обмінятися даними з базою даних. Додаток отримує відповідь від шару [métier].
- Згідно з ним, вона обирає (3) представлення (= відповідь), яке слід надіслати клієнту, надаючи йому (4) необхідну інформацію (шаблон). Виявляється, що в цьому випадку представлення має бути згенеровано не сторінкою P1, а сторінкою P2. Для виконання операцій (3) і (4) сторінка P1 має два варіанти:
- здійснити перехід виконання на сторінку P2 за допомогою операції [Server.Transfer(" P2.aspx ")]. У цьому випадку вона може розмістити шаблон, призначений для сторінки P2, у контексті запиту [Context.Items[" clé "]=valeur] або в сесії користувача [Session.[" clé "]=valeur]. Тоді сторінка P2 буде інстанційована, і під час обробки, наприклад, її події Load вона зможе отримати інформацію, передану сторінкою P1 за допомогою операцій [valeur=(Type)Context.Items[" clé "]] або [valeur=(Type)Session[" clé "]] залежно від випадку, де Type — це тип значення, пов’язаного з ключем. Передача значень через контекст Context є найбільш доцільною, якщо немає необхідності зберігати значення моделі для майбутнього запиту клієнта.
- попросити клієнта перейти на сторінку P2 за допомогою операції [Response.Redirect(" P2.aspx ")]. У цьому випадку сторінка P1 помістить шаблон, призначений для сторінки P2, у сесію, оскільки контекст запиту Context видаляється після завершення кожного запиту. Однак у даному випадку перенаправлення спричинить завершення першого запиту клієнта до P1 та надсилання другого запиту цим самим клієнтом, цього разу до P2. Маємо два послідовні запити. Відомо, що сесія є одним із засобів збереження «пам’яті» між запитами. Існують й інші рішення, окрім сесії.
- Незалежно від того, яким чином P2 бере на себе управління, далі ми знову повертаємося до випадку 1: P2 отримала запит, який вона обробить (5), і сама згенерує відповідь (6, 7). Можна також уявити, що сторінка P2 після обробки запиту передасть управління сторінці P3, і так далі.
Ось приклад із досліджуваного додатка:
![]() |
- на [1]: користувач, який запросив сторінку [Formulaire.aspx], просить переглянути список симуляцій
- на [2]: сторінка [Formulaire.aspx] обробляє цей запит і перенаправляє клієнта на сторінку [Simulations.aspx]. Саме остання надає відповідь користувачеві. Замість того, щоб просити клієнта перейти на іншу сторінку, сторінка [Formulaire.aspx] могла б перенаправити запит клієнта на сторінку [Simulations.aspx]. У цьому випадку на сторінці [2] відображався б той самий URL, що й на сторінці [1]. Адже браузер завжди відображає останній запитуваний URL:
- запитана дія на сторінці [1] призначена для сторінки [Formulaire.aspx]. Браузер виконує перехід на цю сторінку за адресою POST.
- якщо сторінка [Formulaire.aspx] обробляє запит, а потім перенаправляє його за допомогою [Server.Transfer(" Simulations.aspx ")] на сторінку [Simulations.aspx], ми залишаємося в межах одного запиту. Тоді браузер відобразить за адресою [2] сторінку URL, на яку відбувся перехід з [Formulaire.aspx] за адресою POST.
- якщо сторінка [Formulaire.aspx] обробляє запит, а потім перенаправляє його через [Response.Redirect(" Simulations.aspx ")] на сторінку [Simulations.aspx], то браузер надсилає другий запит — GET — на [Simulations.aspx]. Після цього браузер відобразить на сторінці [2] сторінку URL, яка є перенаправленням з [Simulations.aspx], куди відбулося перенаправлення GET. Саме це і демонструє наведений вище знімок екрана [2].
11.3. Проєкт Visual Web Developer шару [web]
Проєкт Visual Web Developer шару [web] має такий вигляд:
![]() |
- у [1] міститься:
- файл конфігурації [Web.config] додатка — ідентичний файлу конфігурації додатка [pam-v4-3tier-nhibernate-multivues-monopage].
- сторінка [Default.aspx] — просто перенаправляє клієнта на сторінку [Formulaire.aspx]
- сторінка [Formulaire.aspx], яка відображає користувачеві форму моделювання та обробляє дії, пов’язані з цією формою
- сторінка [Simulations.aspx], яка показує користувачеві список його моделювань та обробляє дії, пов’язані з цією сторінкою
- сторінку [Erreurs.aspx], яка показує користувачеві повідомлення про помилку, що виникла під час запуску веб-додатку.
- на сторінці [2] відображаються посилання на проект.
Повернемося до архітектури нового проєкту:
![]() |
У порівнянні з проектом [pam-v4-3tier-nhibernate-multivues-monopage] змінилися лише подання. Таким чином, новий проект переймає деякі файли з цього проекту:
- файл конфігурації [Web.config]
- файли DLL, на які посилається [pam-dao-nhibernate, pam-metier-dao-nhibernate, Spring.Core, NHibernate]
- глобальний клас додатка [Global.asax]
- папки [images, ressources, pam]
Щоб забезпечити узгодженість із проектом, що наразі розробляється, ми зробимо так, щоб простір імен для представлень та глобального класу додатка мав назву [pam-v7]:
![]() |
11.4. Код для відображення сторінок
11.4.1. Головна сторінка [MasterPage.master]
Види додатка, представлені в розділі 11.1, мають спільні частини, які можна винести в головну сторінку, що у Visual Studio називається Master Page. Візьмемо, наприклад, подання [VueSaisies] та [VueSimulationsVides], наведені нижче, які генеруються відповідно сторінками [Formulaire.aspx] та [Simulations.aspx]:
![]() |
Ці два види мають спільну верхню панель (заголовок та опції меню). Так само буде з усіма видами, що будуть представлені користувачеві: усі вони матимуть однакову верхню панель. Щоб різні сторінки використовували один і той самий фрагмент оформлення, існують різні рішення, зокрема такі:
- помістити цей спільний фрагмент у компонент користувача. Це була основна техніка, що використовувалася у ASP.NET 1.1
- помістити цей спільний фрагмент на головну сторінку. Ця техніка з’явилася у версії ASP.NET 2.0. Саме її ми використовуємо тут.
Щоб створити головну сторінку у веб-додатку, можна виконати такі дії:
- клацнути правою кнопкою миші на проекті / Додати новий елемент / Головна сторінка:
![]() |
Додавання головної сторінки за замовчуванням додає до веб-додатку три файли:
- [MasterPage.master]: код оформлення головної сторінки
- [MasterPage.master.cs]: код управління головної сторінки
- [Masterpage.Master.designer.cs]: оголошення компонентів головної сторінки
Код, згенерований Visual Studio у файлі [MasterPage.master], має такий вигляд:
<%@ Master Language="C#" AutoEventWireup="true" CodeBehind="MasterPage.master.cs" Inherits="pam_v7.MasterPage" %>
<!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>Untitled Page</title>
<asp:ContentPlaceHolder id="head" runat="server">
</asp:ContentPlaceHolder>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:ContentPlaceHolder id="ContentPlaceHolder1" runat="server">
</asp:ContentPlaceHolder>
</div>
</form>
</body>
</html>
- рядок 1: тег <%@ Master ... %> використовується для визначення сторінки як шаблону. Код управління сторінкою буде міститися у файлі, визначеному атрибутом CodeBehind, а сторінка успадкує клас, визначений атрибутом Inherits.
- рядки 12–18: форма головної сторінки
- рядки 14–16: порожній контейнер, який у нашому додатку міститиме одну зі сторінок [Formulaire.aspx, Simulations.aspx, Erreurs.aspx]. Клієнт отримує у відповідь завжди одну й ту саму сторінку — головну сторінку, на якій контейнер [ContentPlaceHolder1] отримає потік HTML, наданий однією зі сторінок [Formulaire.aspx, Simulations.aspx, Erreurs.aspx]. Отже, щоб змінити вигляд сторінок, що надсилаються клієнтам, достатньо змінити вигляд головної сторінки.
- рядки 8–9: порожній контейнер, за допомогою якого «дочірні» сторінки зможуть налаштовувати заголовок <head>...</head>.
Візуальне представлення (вкладка «Дизайн») цього вихідного коду наведено в (1) нижче. Крім того, завдяки компоненту [ContentPlaceHolder] (2) на панелі інструментів [Standard] можна додавати стільки контейнерів, скільки потрібно.
![]() |
Код управління, згенерований Visual Studio у [MasterPage.master.cs], має такий вигляд:
using System;
public partial class MasterPage : System.Web.UI.MasterPage
{
protected void Page_Load(object sender, EventArgs e)
{
}
}
- рядок 3: клас, на який посилається атрибут [Inherits] директиви <%@ Master ... %> на сторінці [MasterPage.master], походить від класу [System.Web.UI.MasterPage]
Вище ми бачимо наявність методу Page_Load, який обробляє подію Load головної сторінки. Головна сторінка міститиме в собі іншу сторінку. У якому порядку відбуваються події Load обох сторінок? Це загальне правило: подія Load компонента відбувається раніше, ніж подія його контейнера. Отже, у цьому випадку подія Load сторінки, вставленої в головну сторінку, відбудеться раніше, ніж подія самої головної сторінки.
Щоб у програмі « » створити сторінку, майстер-сторінкою якої є попередня сторінка [MasterPage.master], можна вчинити так:
![]() |
- у [1]: клацнути правою кнопкою миші на шаблоні сторінки, а потім вибрати опцію [Ajouter une page de contenu]
- у [2]: створюється сторінка за замовчуванням, у даному випадку [WebForm1.aspx].
Код оформлення [WebForm1.aspx] має такий вигляд:
<%@ Page Title="" Language="C#" MasterPageFile="~/MasterPage.Master" AutoEventWireup="true" CodeBehind="WebForm1.aspx.cs" Inherits="pam_v7.WebForm1" %>
<asp:Content ID="Content1" ContentPlaceHolderID="ContentPlaceHolder1" runat="server">
</asp:Content>
- рядок 1: директива Page та її атрибути
- MasterPageFile: вказує на файл шаблону сторінки, описаної цією директивою. Знак ~ позначає папку проєкту.
- інші параметри є типовими для веб-сторінки ASP
- рядки 2–3: теги <asp:Content> поодинці пов’язані з директивами <asp:ContentPlaceHolder> шаблону за допомогою атрибута ContentPlaceHolderID. Компоненти, розміщені між рядками 2–3 вище, під час виконання будуть розміщені в контейнері ID ContentPlaceHolder1 шаблону.
Перейменувавши таким чином створену сторінку [WebForm1.aspx], можна створити різні сторінки, для яких [MasterPage.master] виступає як головна сторінка.
Для нашого додатка [SimuPaie] візуальний вигляд шаблону буде таким:
![]() |
№ | Тип | Назва | Роль |
Панель (рожева, показана вище) | заголовок | заголовок сторінки | |
Панель (жовта, як показано вище) | вміст | вміст сторінки | |
LinkButton | LinkButtonFaireSimulation | запит на розрахунок симуляції | |
LinkButton | LinkButtonEffacerSimulation | очистити форму введення даних | |
LinkButton | LinkButtonVoirSimulations | відображає список вже виконаних моделювань | |
LinkButton | LinkButtonFormulaireSimulation | повертає до форми введення даних | |
LinkButton | LinkButtonEnregistrerSimulation | зберігає поточну симуляцію у списку симуляцій | |
LinkButton | LinkButtonTerminerSession | завершує поточну сесію |
Відповідний вихідний код виглядає так:
<%@ Master Language="C#" AutoEventWireup="true" CodeBehind="MasterPage.master.cs" Inherits="pam_v7.MasterPage" %>
<!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 id="Head1" runat="server">
<title>Application PAM</title>
</head>
<body background="ressources/standard.jpg">
<form id="form1" runat="server">
<asp:ScriptManager ID="ScriptManager1" runat="server" EnablePartialRendering="true" />
<asp:UpdatePanel runat="server" ID="UpdatePanelPam" UpdateMode="Conditional">
<ContentTemplate>
<asp:Panel ID="entete" runat="server" BackColor="#FFE0C0">
<table>
<tr>
<td>
<h2>
Simulateur de calcul de paie</h2>
</td>
<td>
<label>
 </label>
<asp:UpdateProgress ID="UpdateProgress1" runat="server">
<ProgressTemplate>
<img alt="" src="images/indicator.gif" />
<asp:Label ID="Label5" runat="server" BackColor="#FF8000"
EnableViewState="False" Text="Calcul en cours. Patientez ....">
</asp:Label>
</ProgressTemplate>
</asp:UpdateProgress>
</td>
<td>
<asp:LinkButton ID="LinkButtonFaireSimulation" runat="server"
CausesValidation="False">| Faire la simulation<br />
</asp:LinkButton>
<asp:LinkButton ID="LinkButtonEffacerSimulation" runat="server"
CausesValidation="False">| Effacer la simulation<br />
</asp:LinkButton>
<asp:LinkButton ID="LinkButtonVoirSimulations" runat="server"
CausesValidation="False">| Voir les simulations<br />
</asp:LinkButton>
<asp:LinkButton ID="LinkButtonFormulaireSimulation" runat="server"
CausesValidation="False">| Retour au formulaire de simulation<br />
</asp:LinkButton>
<asp:LinkButton ID="LinkButtonEnregistrerSimulation" runat="server"
CausesValidation="False">| Enregistrer la simulation<br />
</asp:LinkButton>
<asp:LinkButton ID="LinkButtonTerminerSession" runat="server"
CausesValidation="False">| Terminer la session<br />
</asp:LinkButton>
</td>
</tr>
</table>
<hr />
</asp:Panel>
<div>
<asp:Panel ID="contenu" runat="server" BackColor="#FFFFC0">
<asp:ContentPlaceHolder ID="ContentPlaceHolder1" runat="server">
</asp:ContentPlaceHolder>
</asp:Panel>
</div>
</ContentTemplate>
</asp:UpdatePanel>
</form>
</body>
</html>
- рядок 1: зверніть увагу на назву класу шаблону сторінки: MasterPage
- рядок 8: задається фонове зображення для сторінки.
- рядки 9–64: форма
- рядок 10: компонент ScriptManager, необхідний для ефектів Ajax
- рядки 11–63: контейнер AJax
- рядки 12–62: вміст із підтримкою Ajax
- рядки 13–55: компонент Panel [entete]
- рядки 57–60: компонент Panel [contenu]
- рядки 58–59: компонент ID [ContentPlaceHolder1], який міститиме інкапсульовану сторінку [Formulaire.aspx, Simulations.aspx, Erreurs.aspx]
Щоб створити цю сторінку, можна вставити в панель [entete] код ASPX з подання [VueEntete] сторінки [Default.aspx] версії [pam-v4-3tier-nhibernate-multivues-monopage], описаної в розділі 8.5.2.
11.4.2. Сторінка [Formulaire.aspx]
Для створення цієї сторінки слід дотримуватися методу, викладеного в пункті 11.4.1, і перейменувати сторінку [WebForm1.aspx], створену таким чином, на [Formulaire.aspx]. Зовнішній вигляд сторінки [Formulaire.aspx], що створюється, буде таким:
![]() |
Візуальний вигляд сторінки [Formulaire.aspx] складається з двох елементів:
- у [1] — головна сторінка з її контейнером [ContentPlaceHolder1] (2)
- [2] — компоненти, розміщені в контейнері [ContentPlaceHolder1]. Вони ідентичні компонентам попереднього додатка.
Вихідний код цієї сторінки такий:
<%@ Page Language="C#" MasterPageFile="~/MasterPage.master" AutoEventWireup="true"
CodeBehind="Formulaire.aspx.cs" Inherits="pam_v7.PageFormulaire" Title="Simulation de calcul de paie : formulaire" %>
<%@ MasterType VirtualPath="~/MasterPage.master" %>
<asp:Content ID="Content1" ContentPlaceHolderID="ContentPlaceHolder1" runat="Server">
<div>
<table>
<tr>
<td>
Employé
</td>
<td>
Heures travaillées
</td>
<td>
Jours travaillés
</td>
<td>
</td>
</tr>
...
</asp:Content>
- рядок 1: директива Page з атрибутом MasterPageFile
- рядок 4: клас управління шаблоном може надавати публічні поля та властивості. До них можна отримати доступ на вкладених сторінках за допомогою синтаксису Master.[champ] або Master.[propriété]. Властивість Master сторінки позначає головну сторінку у вигляді екземпляра типу [System.Web.UI.MasterPage]. Тому в нашому прикладі насправді слід було б написати (MasterPage)(Master).[champ] або (MasterPage)(Master).[propriété]. Цього перетворення типів можна уникнути, вставивши на сторінку директиву MasterType у рядку 4. Атрибут VirtualPath цієї директиви вказує на файл шаблону. Тоді компілятор може визначити публічні поля, властивості та методи, що надаються класом шаблону, у даному випадку типу [MasterPage].
- рядки 5–22: вміст, який буде вставлено в контейнер [ContentPlaceHolder1] шаблону сторінки.
Цю сторінку можна створити, вказавши як вміст (рядки 6–21) вміст подання [VueSaisies], описаного в розділі 8.5.3, та вміст подання [VueSimulation], описаного в розділі 8.5.4.
11.4.3. Сторінка [Simulations.aspx]
Для створення цієї сторінки слід дотримуватися методу, викладеного в розділі 11.4.1, і перейменувати сторінку [WebForm1.aspx], створену таким чином, на [Simulations.aspx]. Зовнішній вигляд сторінки [Simulations.aspx], що створюється, є таким:
![]() |
Візуальний вигляд сторінки [Simulations.aspx] складається з двох елементів:
- у [1] — головна сторінка з її контейнером [ContentPlaceHolder1]
- [2] — компоненти, розміщені в контейнері [ContentPlaceHolder1]. Вони ідентичні компонентам попереднього додатка.
Вихідний код цієї сторінки такий:
<%@ Page Language="C#" MasterPageFile="~/MasterPage.master" AutoEventWireup="true"
CodeBehind="Simulations.aspx.cs" Inherits="pam_v7.PageSimulations" Title="Pam : liste des simulations" %>
<%@ MasterType VirtualPath="~/MasterPage.master" %>
<asp:Content ID="Content1" ContentPlaceHolderID="ContentPlaceHolder1" runat="Server">
<asp:MultiView ID="MultiView1" runat="server">
<asp:View ID="View1" runat="server">
<h2>
Liste de vos simulations</h2>
<p>
<asp:GridView ID="GridViewSimulations" runat="server" ...>
...
</asp:GridView>
</p>
</asp:View>
<asp:View ID="View2" runat="server">
<h2>
La liste de vos simulations est vide</h2>
</asp:View>
</asp:MultiView><br />
</asp:Content>
Цю сторінку можна створити, вказавши як вміст (рядки 5–21) вміст подання [VueSimulations], описаного в розділі 8.5.5, та вміст подання [VueSimulationsVides], описаного в розділі 8.5.6.
11.4.4. Сторінка [Erreurs.aspx]
Щоб створити цю сторінку, слід дотримуватися методу, викладеного в розділі 11.4.1, і перейменувати сторінку [WebForm1.aspx], створену таким чином, на [Erreurs.aspx]. Візуальний вигляд сторінки [Erreurs.aspx], що створюється, є таким:
![]() |
Візуальний вигляд сторінки [Erreurs.aspx] складається з двох елементів:
- у [1] — головна сторінка з її контейнером [ContentPlaceHolder1]
- [2] — компоненти, розміщені в контейнері [ContentPlaceHolder1]. Вони ідентичні компонентам попереднього додатка.
Вихідний код цієї сторінки такий:
<%@ Page Language="C#" MasterPageFile="~/MasterPage.master" AutoEventWireup="true"
CodeBehind="Erreurs.aspx.cs" Inherits="pam_v7.PageErreurs" Title="Pam : erreurs" %>
<%@ MasterType VirtualPath="~/MasterPage.master" %>
<asp:Content ID="Content1" ContentPlaceHolderID="ContentPlaceHolder1" Runat="Server">
<h3>Les erreurs suivantes se sont produites au démarrage de l'application</h3>
<ul>
<asp:Repeater id="rptErreurs" runat="server">
<ItemTemplate>
<li>
<%# Container.DataItem %>
</li>
</ItemTemplate>
</asp:Repeater>
</ul>
</asp:Content>
11.5. Код перевірки сторінок
11.5.1. Загальний огляд
Повернемося до архітектури додатка:
![]() |
- [Global] — це об’єкт типу [HttpApplication], який ініціалізує (етап 0) додаток. Цей клас ідентичний класу з попередньої версії.
- Код контролера, який у попередній версії повністю містився в [Default.aspx.cs], тепер розподілений між кількома сторінками:
- [MasterPage.master]: головна сторінка для сторінок [Formulaire.aspx, Simulations.aspx, Erreurs.aspx]. Вона містить меню.
- [Formulaire.aspx]: сторінка, яка відображає форму моделювання та керує діями, що відбуваються в цій формі
- [Simulations.aspx]: сторінка, на якій відображається список моделювань та керуються діями, що відбуваються на цій сторінці
- [Erreurs.aspx]: сторінка, яка відображається у разі помилки під час ініціалізації додатка. На цій сторінці неможливо виконувати жодних дій.
Обробка запиту клієнта відбувається за такими етапами:
- клієнт надсилає запит до додатка. Зазвичай він робить це на одній із двох сторінок [Formulaire.aspx, Simulations.aspx], але ніщо не заважає йому звернутися до сторінки [Erreurs.aspx]. Цей випадок слід передбачити.
- запитана сторінка обробляє цей запит (етап 1). Для цього їй може знадобитися допомога рівня [métier] (етап 2), якому, у свою чергу, може знадобитися рівень [dao], якщо необхідно обмінятися даними з базою даних. Додаток отримує відповідь від шару [métier].
- Згідно з ним, вона обирає (етап 3) вигляд (= відповідь), який потрібно надіслати клієнту, і надає йому (етап 4) інформацію (модель), яка їй потрібна. Ми розглянули три можливості для формування цієї відповіді:
- запитана сторінка (D) є також сторінкою (R), надісланою у відповідь. Створення шаблону відповіді (R) полягає в тому, щоб присвоїти певним компонентам сторінки (D) значення, які вони повинні мати у відповіді.
- запитана сторінка (D) не є сторінкою (R), що надсилається у відповідь. У цьому випадку сторінка (D) може:
- передати потік виконання сторінці (R) за допомогою інструкції Server.Transfer(" R "). Тоді шаблон можна розмістити в контексті за допомогою Context.Items("ключ")=значення або, рідше, у сесії за допомогою Session.Items("ключ")=значення
- перенаправити клієнта на сторінку (R) за допомогою команди Response.redirect(" R "). Після цього шаблон можна розмістити в сесії, але не в контексті.
- відповідь надсилається клієнту (крок 5)
Кожна зі сторінок [MasterPage.master, Formulaire.aspx, Simulations.aspx, Erreurs.aspx] реагуватиме на одну або кілька з наведених нижче подій:
- Init: перша подія в життєвому циклі сторінки
- Load: відбувається під час завантаження сторінки
- Click: клік на одне з посилань у меню головної сторінки
Ми обробляємо сторінки послідовно, починаючи з головної сторінки.
11.5.2. Код управління сторінкою [MasterPage.master]
11.5.2.1. Скелет класу
Код управління головної сторінки має таку структуру:
using System.Web.UI.WebControls;
namespace pam_v7
{
public partial class MasterPage : System.Web.UI.MasterPage
{
// меню
public LinkButton OptionFaireSimulation
{
get { return LinkButtonFaireSimulation; }
}
...
// зафіксувати меню
public void SetMenu(bool boolFaireSimulation, bool boolEnregistrerSimulation, bool boolEffacerSimulation, bool boolFormulaireSimulation, bool boolVoirSimulations, bool boolTerminerSession)
{
....
}
// управління опцією [Terminer la session]
protected void LinkButtonTerminerSession_Click(object sender, System.EventArgs e)
{
....
}
// ініціалізувати головну сторінку
protected void Page_Init(object sender, System.EventArgs e)
{
....
}
}
}
}
- рядок 5: клас називається [MasterPage] і походить від системного класу [System.Web.UI.MasterPage].
- рядки 9–14: 6 пунктів меню представлені як загальнодоступні властивості класу
- рядки 16–19: публічний метод SetMenu дозволить сторінкам [Formulaire.aspx, Simulations.aspx, Erreurs.aspx] закріпити меню головної сторінки
- рядки 22–25: процедура, яка оброблятиме клік на посилання [LinkButtonTerminerSession]
- рядки 28–31: процедура обробки події Init головної сторінки
11.5.2.2. Загальнодоступні властивості класу
using System.Web.UI.WebControls;
namespace pam_v7
{
public partial class MasterPage : System.Web.UI.MasterPage
{
// меню
public LinkButton OptionFaireSimulation
{
get { return LinkButtonFaireSimulation; }
}
public LinkButton OptionEffacerSimulation
{
get { return LinkButtonEffacerSimulation; }
}
public LinkButton OptionEnregistrerSimulation
{
get { return LinkButtonEnregistrerSimulation; }
}
public LinkButton OptionVoirSimulations
{
get { return LinkButtonVoirSimulations; }
}
public LinkButton OptionTerminerSession
{
get { return LinkButtonTerminerSession; }
}
public LinkButton OptionFormulaireSimulation
{
get { return LinkButtonFormulaireSimulation; }
}
...
}
}
Щоб зрозуміти цей код, слід згадати компоненти, з яких складається головна сторінка:
![]() |
№ | Тип | Назва | Роль |
Панель (рожева, показана вище) | заголовок | заголовок сторінки | |
Панель (жовта, як показано вище) | вміст | вміст сторінки | |
LinkButton | LinkButtonFaireSimulation | запит на розрахунок симуляції | |
LinkButton | LinkButtonEffacerSimulation | очистити форму введення даних | |
LinkButton | LinkButtonVoirSimulations | відображає список вже виконаних моделювань | |
LinkButton | LinkButtonFormulaireSimulation | повертає до форми введення даних | |
LinkButton | LinkButtonEnregistrerSimulation | зберігає поточну симуляцію у списку симуляцій | |
LinkButton | LinkButtonTerminerSession | завершує поточну сесію |
Компоненти з 1 по 6 недоступні поза межами сторінки, на якій вони розміщені. Властивості рядків з 9 по 37 призначені для того, щоб зробити їх доступними для зовнішніх класів, у даному випадку — для класів інших сторінок додатка.
11.5.2.3. Метод SetMenu
Публічний метод SetMenu дозволяє сторінкам [Formulaire.aspx, Simulations.aspx, Erreurs.aspx] закріпити меню головної сторінки. Його код є простим:
// зафіксувати меню
public void SetMenu(bool boolFaireSimulation, bool boolEnregistrerSimulation, bool boolEffacerSimulation, bool boolFormulaireSimulation, bool boolVoirSimulations, bool boolTerminerSession)
{
// встановлення параметрів меню
LinkButtonFaireSimulation.Visible = boolFaireSimulation;
LinkButtonEnregistrerSimulation.Visible = boolEnregistrerSimulation;
LinkButtonEffacerSimulation.Visible = boolEffacerSimulation;
LinkButtonVoirSimulations.Visible = boolVoirSimulations;
LinkButtonFormulaireSimulation.Visible = boolFormulaireSimulation;
LinkButtonTerminerSession.Visible = boolTerminerSession;
}
11.5.2.4. Обробка подій головної сторінки
Головна сторінка оброблятиме дві події:
- подія Init, яка є першою подією життєвого циклу сторінки
- подія Click при натисканні на посилання [LinkButtonTerminerSession]
Головна сторінка має ще п’ять посилань: [LinkButtonFaireSimulation, LinkButtonEnregistrerSimulation, LinkButtonEffacerSimulation, LinkButtonVoirSimulations, LinkButtonFormulaireSimulation]. Як приклад, розглянемо, що слід зробити при натисканні на посилання [LinkButtonFaireSimulation]:
- перевірити введені дані (години, дні) на сторінці [Formulaire.aspx]
- провести розрахунок заробітної плати
- відобразити результати на сторінці [Formulaire.aspx]
Операції 1 і 3 передбачають доступ до компонентів сторінки [Formulaire.aspx]. Однак цього немає. Адже головна сторінка не має жодної інформації про компоненти сторінок, які можуть бути вставлені в її контейнер [ContentPlaceHolder1]. У нашому прикладі саме сторінка [Formulaire.aspx] повинна обробляти клік на посилання [LinkButtonFaireSimulation], оскільки саме вона відображається в момент настання цієї події. Як вона може отримати повідомлення про цю подію?
- Оскільки посилання [LinkButtonFaireSimulation] не є частиною сторінки [Formulaire.aspx], у [Formulaire.aspx] не можна написати звичайну процедуру:
private void LinkButtonFaireSimulation_Click(object sender, System.EventArgs e)
{
...
}
Цю проблему можна обійти за допомогою такого коду у файлі [Formulaire.aspx]:
using System.Collections.Generic;
...
namespace pam_v7
{
public partial class Formulaire : System.Web.UI.Page
{
// завантаження сторінки
protected void Page_Load(object sender, System.EventArgs e)
{
// менеджер подій
Master.OptionFaireSimulation.Click += OptFaireSimulation_Click;
Master.OptionEffacerSimulation.Click += OptEffacerSimulation_Click;
Master.OptionVoirSimulations.Click += OptVoirSimulations_Click;
Master.OptionEnregistrerSimulation.Click += OptEnregistrerSimulation_Click;
...
}
// розрахунок заробітної плати
private void OptFaireSimulation_Click(object sender, System.EventArgs e)
{
....
}
// очистити симуляцію
private void OptEffacerSimulation_Click(object sender, System.EventArgs e)
{
...
}
protected void OptVoirSimulations_Click(object sender, System.EventArgs e)
{
...
}
protected void OptEnregistrerSimulation_Click(object sender, System.EventArgs e)
{
...
}
}
}
- рядки 12–15: коли відбувається подія Load на сторінці [Formulaire.aspx], клас [MasterPage] головної сторінки вже інстанційовано. Його загальнодоступні властивості Optionxx доступні та мають тип LinkButton — компонент, що підтримує подію Click. Ми пов’язуємо з цими подіями Click такі методи:
- OptFaireSimulation_Click для події Click на посиланні LinkButtonFaireSimulation
- OptEffacerSimulation_Click для події Click за посиланням LinkButtonEffacerSimulation
- OptVoirSimulations_Click для події Click за посиланням LinkButtonVoirSimulations
- OptEnregistrerSimulation_Click для події Click за посиланням LinkButtonEnregistrerSimulation
Управління подіями Click за шістьма посиланнями меню буде розподілено наступним чином:
- сторінка [Formulaire.aspx] буде керувати посиланнями [LinkButtonFaireSimulation, LinkButtonEnregistrerSimulation, LinkButtonEffacerSimulation, LinkButtonVoirSimulations]
- сторінка [Simulations.aspx] буде керувати посиланням [LinkButtonFormulaireSimulation]
- головна сторінка [MasterPage.master] керуватиме посиланням [LinkButtonTerminerSession]. Для цієї події їй, власне, не потрібно знати, яку сторінку вона інкапсулює.
11.5.2.5. Подія Init головної сторінки
Три сторінки [Formulaire.aspx, Simulations.aspx, Erreurs.aspx] додатка мають [MasterPage.master] як головну сторінку. Позначимо головну сторінку як M, а інкапсульовану — як E. Коли клієнт запитує сторінку E, у такому порядку відбуваються наступні події:
- E.Init
- M.Init
- E.Load
- M.Load
- ...
Ми використаємо подію Init зі сторінки M для виконання коду, який було б доцільно виконати якомога раніше, незалежно від цільової сторінки E. Щоб ознайомитися з цим кодом, давайте ще раз розглянемо загальну схему додатка:
![]() |
На малюнку вище [Global] — це об’єкт типу [HttpApplication], який ініціалізує додаток. Цей клас є таким самим, як і у версії [pam-v4-3tier-nhibernate-multivues-monopage]:
using System;
...
namespace pam_v7
{
public class Global : System.Web.HttpApplication
{
// --- статичні дані програми ---
public static Employe[] Employes;
public static IPamMetier PamMetier = null;
public static string Msg;
public static bool Erreur = false;
// запуск додатка
public void Application_Start(object sender, EventArgs e)
{
...
}
public void Session_Start(object sender, EventArgs e)
{
...
}
}
}
Якщо клас [Global] не може правильно ініціалізувати додаток, він встановлює значення двох публічних статичних змінних:
- булева змінна «Помилка» у рядку 12 приймає значення vrai
- змінна «Msg» у рядку 11 містить повідомлення з детальною інформацією про помилку, що виникла
Коли користувач запитує одну зі сторінок [Formulaire.aspx, Simulations.aspx], а додаток не ініціалізувався належним чином, цей запит має бути перенаправлений на сторінку [Erreurs.aspx], яка відобразить повідомлення про помилку класу [Global]. Цей випадок можна обробити різними способами:
- виконати перевірку на помилку ініціалізації в обробнику подій Init або Load кожної зі сторінок [Formulaire.aspx, Simulations.aspx]
- виконати перевірку на помилки ініціалізації в обробнику подій Init або Load на головній сторінці цих двох сторінок. Перевага цього методу полягає в тому, що перевірка на помилки ініціалізації розміщується в одному місці.
Ми вирішили виконати перевірку на помилку ініціалізації в обробнику події Init головної сторінки:
protected void Page_Init(object sender, System.EventArgs e)
{
// менеджер подій
LinkButtonTerminerSession.Click += LinkButtonTerminerSession_Click;
// помилки ініціалізації?
if (Global.Erreur)
{
// чи є інкапсульована сторінка сторінкою помилок?
bool isPageErreurs =...;
// якщо відображається сторінка помилок, то залишаємо все як є, інакше перенаправляємо клієнта на сторінку помилок
if (!isPageErreurs)
Response.Redirect("Erreurs.aspx");
return;
}
}
Наведений вище код буде виконано, щойно буде зроблено запит на одну з сторінок [Formulaire.aspx, Simulations.aspx, Erreurs.aspx]. У разі, якщо запитується сторінка [Formulaire.aspx, Simulations.aspx], ми просто (у рядку 12) перенаправляємо клієнта на сторінку [Erreurs.aspx], яка відповідає за відображення повідомлення про помилку класу [Global]. У випадку, якщо запитувана сторінка — [Erreurs.aspx], це перенаправлення не повинно відбуватися: потрібно дозволити відобразитися сторінці [Erreurs.aspx]. Отже, нам потрібно дізнатися в методі [Page_Init] головної сторінки, яку саме сторінку вона інкапсулює.
Повернемося до дерева компонентів головної сторінки:
...
<body background="ressources/standard.jpg">
<form id="form1" runat="server">
<asp:Panel ID="entete" runat="server" BackColor="#FFE0C0" Width="1239px" >
...
</asp:Panel>
<div>
<asp:Panel ID="contenu" runat="server" BackColor="#FFFFC0">
<asp:ContentPlaceHolder ID="ContentPlaceHolder1" runat="server">
</asp:ContentPlaceHolder>
</asp:Panel>
</div>
</form>
</body>
</html>
- рядки 1–13: контейнер з ідентифікатором «form1»
- рядки 4–6: контейнер з ідентифікатором «entete», вкладений у контейнер з ідентифікатором «form1»
- рядки 8–11: контейнер з ідентифікатором «contenu», вкладений у контейнер з ідентифікатором «form1»
- рядки 9–10: контейнер з ідентифікатором «ContentPlaceHolder1», що входить до контейнера з ідентифікатором «contenu»
Сторінка E, вкладена в головну сторінку M, знаходиться в контейнері з ідентифікатором «ContentPlaceHolder1». Щоб зробити посилання на компонент з ідентифікатором C цієї сторінки E, потрібно написати:
this.FindControl("form1").FindControl("contenu").FindControl("ContentPlaceHolder1").FindControl("C");
Дерево компонентів сторінки [Erreurs.aspx] має такий вигляд:
<%@ Page Language="C#" MasterPageFile="~/MasterPage.master" AutoEventWireup="true"
CodeBehind="Erreurs.aspx.cs" Inherits="pam_v7.PageErreurs" Title="Pam : erreurs" %>
<%@ MasterType VirtualPath="~/MasterPage.master" %>
<asp:Content ID="Content1" ContentPlaceHolderID="ContentPlaceHolder1" Runat="Server">
<h3>Les erreurs suivantes se sont produites au démarrage de l'application</h3>
<ul>
<asp:Repeater id="rptErreurs" runat="server">
<ItemTemplate>
<li>
<%# Container.DataItem %>
</li>
</ItemTemplate>
</asp:Repeater>
</ul>
</asp:Content>
Коли сторінка [Erreurs.aspx] об’єднується з шаблоном M, вміст тегу <asp:Content>, наведеного вище (рядки 5–16), інтегрується в тег <asp:ContentPlaceHolder> з ідентифікатором «ContentPlaceholder1» на сторінці M, після чого дерево компонентів цієї сторінки набуває такого вигляду:
- рядок 12: компонент [rptErreurs] можна використовувати для визначення, чи містить головна сторінка M сторінку [Erreurs.aspx]. Адже цей компонент існує лише на цій сторінці.
Цих пояснень достатньо, щоб зрозуміти код процедури [Page_Init] головної сторінки:
protected void Page_Init(object sender, System.EventArgs e)
{
// менеджер подій
LinkButtonTerminerSession.Click += LinkButtonTerminerSession_Click;
// помилки ініціалізації?
if (Global.Erreur)
{
// чи є вкладена сторінка сторінкою помилок?
bool isPageErreurs = this.FindControl("form1").FindControl("contenu").FindControl("ContentPlaceHolder1").FindControl("rptErreurs") != null;
// якщо відображається сторінка помилок, то залишаємо все як є, інакше перенаправляємо клієнта на сторінку помилок
if (!isPageErreurs)
Response.Redirect("Erreurs.aspx");
return;
}
}
- рядок 4: до події Click на посиланні LinkButtonTerminerSession прив’язується обробник подій. Цей обробник знаходиться у класі MasterPage.
- рядок 6: перевіряється, чи клас [Global] встановив своє логічне значення Erreur
- рядок 9: якщо так, то булеве значення IsPageErreurs вказує, чи є сторінка, вкладена в головну сторінку, сторінкою [Erreurs.aspx]
- рядок 12: якщо сторінка, вбудована в головну сторінку, не є сторінкою [Erreurs.aspx], то клієнта перенаправляють на цю сторінку, інакше нічого не роблять.
11.5.2.6. Подія «Клік» на посилання [LinkButtonTerminerSession]
![]() |
Коли користувач натискає на посилання [Terminer la session] у вікні (1) вище, потрібно очистити сесію від її вмісту та відобразити порожню форму (2).
Код обробника цієї події може виглядати так:
protected void LinkButtonTerminerSession_Click(object sender, System.EventArgs e)
{
// сесію припиняють
Session.Abandon();
// відображаємо вигляд [formulaire]
Response.Redirect("Formulaire.aspx");
}
- рядок 4: поточна сесія припиняється
- рядок 6: клієнт перенаправляється на сторінку [Formulaire.aspx]
Як бачимо, цей код не задіює жодного з компонентів сторінок [Formulaire.aspx, Simulations.aspx, Erreurs.aspx]. Отже, подія може оброблятися самою головною сторінкою.
11.5.3. Код управління сторінки [Erreurs.aspx]
Код управління сторінки [Erreurs.aspx] може виглядати так:
using System.Collections.Generic;
namespace pam_v7
{
public partial class Erreurs : System.Web.UI.Page
{
protected void Page_Load(object sender, System.EventArgs e)
{
// помилки ініціалізації?
if (Global.Erreur)
{
// готується шаблон сторінки [erreurs]
List<string> erreursInitialisation = new List<string>();
erreursInitialisation.Add(Global.Msg);
// прив'язується список помилок до відповідного компонента
rptErreurs.DataSource = erreursInitialisation;
rptErreurs.DataBind();
}
// визначається меню
Master.SetMenu(false, false, false, false, false, false);
}
}
}
Нагадаємо, що єдина роль сторінки [Erreurs.aspx] полягає у відображенні помилки ініціалізації додатка, коли така помилка виникає:
- рядок 10: перевіряється, чи ініціалізація завершилася з помилкою
- рядки 13–14: якщо так, повідомлення про помилку (Global.Msg) додається до списку [ErreursInitialisation]
- рядки 16–17: компоненту [rptErreurs] надається завдання відобразити цей список
- рядок 20: у будь-якому випадку (незалежно від того, чи сталася помилка) опції меню головної сторінки не відображаються, тому користувач не може розпочати жодної нової дії з цієї сторінки.
Що станеться, якщо користувач безпосередньо завантажить сторінку [Erreurs.aspx] (чого він не повинен робити під час звичайного використання додатка)? Проаналізувавши код сторінок [MasterPage.master.cs] та [Erreurs.aspx.cs], можна помітити, що:
- якщо сталася помилка ініціалізації, вона відображається
- якщо помилки ініціалізації не сталося, користувач отримує сторінку, що містить лише заголовок [MasterPage.master] без відображення будь-яких опцій меню.
11.5.4. Контрольний код сторінки [Formulaire.aspx]
11.5.4.1. Скелет класу
Скелет коду управління сторінкою [Formulaire.aspx] може виглядати так:
using Pam.Metier.Entites;
...
partial class PageFormulaire : System.Web.UI.Page
{
// завантаження сторінки
protected void Page_Load(object sender, System.EventArgs e)
{
// менеджер подій
Master.OptionFaireSimulation.Click += OptFaireSimulation_Click;
Master.OptionEffacerSimulation.Click += OptEffacerSimulation_Click;
Master.OptionVoirSimulations.Click += OptVoirSimulations_Click;
Master.OptionEnregistrerSimulation.Click += OptEnregistrerSimulation_Click;
....
}
// розрахунок заробітної плати
private void OptFaireSimulation_Click(object sender, System.EventArgs e)
{
....
}
// очищення симуляції
private void OptEffacerSimulation_Click(object sender, System.EventArgs e)
{
...
}
protected void OptVoirSimulations_Click(object sender, System.EventArgs e)
{
....
}
protected void OptEnregistrerSimulation_Click(object sender, System.EventArgs e)
{
...
}
}
Код управління сторінки [Formulaire.aspx] обробляє п’ять подій:
- подія Load на сторінці
- подія Click на посиланні [LinkButtonFaireSimulation] головної сторінки
- подія Click на посиланні [LinkButtonEffacerSimulation] головної сторінки
- подія Click за посиланням [LinkButtonEnregistrerSimulation] на головній сторінці
- подія Click у посиланні [LinkButtonVoirSimulations] на головній сторінці
11.5.4.2. Подія завантаження сторінки
Скелет обробника події Load сторінки може виглядати наступним чином:
protected void Page_Load(object sender, System.EventArgs e)
{
// менеджер подій
Master.OptionFaireSimulation.Click += OptFaireSimulation_Click;
Master.OptionEffacerSimulation.Click += OptEffacerSimulation_Click;
Master.OptionVoirSimulations.Click += OptVoirSimulations_Click;
Master.OptionEnregistrerSimulation.Click += OptEnregistrerSimulation_Click;
// відображення виду [saisies]
...
// розміщення меню на головній сторінці
...
// обробка запиту GET
if (!IsPostBack)
{
// завантаження імен співробітників у комбінований список
...
// ініціалізація подання [saisies] із даними, збереженими в сесії, якщо такі є
....
}
}
Прикладом, що пояснює коментар у рядку 17, може бути такий:
![]() |
![]() |
- у [1] запитується перегляд списку моделювань. Дані були введені у [A, B, C].
- у [2] відображається список
- у [3] подається запит на повернення до форми
- у [4] форма відображається такою, якою її залишили. Оскільки було два запити, (1,2) та (3,4), це означає, що:
- під час переходу від [1] до [2] дані, введені в [1], були збережені
- під час переходу від [3] до [4] ці дані були відновлені. Саме процедура [Page_Load] з [Formulaire.aspx] здійснює це відновлення.
Завдання: доповніть процедуру Page_Load, користуючись коментарями та кодом версії [pam-v4-3tier-nhibernate-multivues-monopage]
11.5.4.3. Обробка подій кліків на посиланнях меню
Структура обробників подій Click для посилань на головній сторінці така:
// розрахунок заробітної плати
private void OptFaireSimulation_Click(object sender, System.EventArgs e)
{
// ефект Ajax
Thread.Sleep(3000);
// сторінка дійсна?
Page.Validate();
if (!Page.IsValid)
{
// відображення перегляду [saisie]
...
}
// сторінка дійсна — отримуємо введені дані
...
// розраховується заробітна плата працівника
FeuilleSalaire feuillesalaire;
try
{
feuillesalaire = ...;
}
catch (PamException ex)
{
// виникла проблема
...
return;
}
// результат зберігається в сесії
Session["simulation"] = ...;
// дані вводяться в сесію
...
// виведення на екран
...
// відображення переглядів
...
// відображення меню MasterPage
...
}
// очистити симуляцію
private void OptEffacerSimulation_Click(object sender, System.EventArgs e)
{
// відображення панелі [saisie]
...
// вибір першого співробітника
...
}
protected void OptVoirSimulations_Click(object sender, System.EventArgs e)
{
// заносимо введені дані в сесію
...
// відображення вікна [simulations]
Response.Redirect("simulations.aspx");
}
protected void OptEnregistrerSimulation_Click(object sender, System.EventArgs e)
{
// поточне моделювання зберігається в сесії користувача
...
// відображається вікно [simulations]
Response.Redirect("simulations.aspx");
}
Завдання: доповніть код наведених вище процедур, користуючись коментарями та кодом версії [pam-v4-3tier-nhibernate-multivues-monopage]
11.5.5. Код управління сторінкою [Simulations.aspx]
Структура коду управління сторінки [Simulations.aspx] може виглядати так:
using System.Collections.Generic;
using Pam.Web;
using System.Web.UI.WebControls;
partial class PageSimulations : System.Web.UI.Page
{
// симуляції
private List<Simulation> simulations;
// завантаження сторінки
protected void Page_Load(object sender, System.EventArgs e)
{
// менеджер подій
Master.OptionFormulaireSimulation.Click += OptFormulaireSimulation_Click;
GridViewSimulations.RowDeleting += GridViewSimulations_RowDeleting;
// отримання симуляцій у сесії
simulations = ...;
// чи є симуляції?
if (simulations.Count != 0)
{
// перший видимий вигляд
...
// заповнюємо GridView
...
}
else
{
// другий вигляд
...
}
// закріплюємо меню
...
}
protected void GridViewSimulations_RowDeleting(object sender, System.Web.UI.WebControls.GridViewDeleteEventArgs e)
{
// отримання симуляцій у сесії
List<Simulation> simulations = ...;
// видалення вказаної симуляції (e.RowIndex — номер видаленого рядка в GridView)
..
// чи залишилися ще симуляції?
if (simulations.Count != 0)
{
// заповнюється gridview
...
}
else
{
// перегляд [SimulationsVides]
...
}
}
protected void OptFormulaireSimulation_Click(object sender, System.EventArgs e)
{
// відображається вид [formulaire]
Response.Redirect("formulaire.aspx");
}
}
Завдання: доповніть код процедур, наведених вище, користуючись коментарями та кодом версії [pam-v4-3tier-nhibernate-multivues-monopage]
11.5.6. Код управління сторінкою [Default.aspx]
У додатку можна передбачити сторінку [Default.aspx], щоб користувач міг запитувати URL додатка без вказівки конкретної сторінки, як показано нижче:
![]() |
Запит [1] отримав у відповідь сторінку [Formulaire.aspx] (2). Відомо, що запит (1) за замовчуванням обробляється сторінкою [Default.aspx] додатка. Щоб отримати (2), достатньо, щоб [Default.aspx] перенаправив клієнта на сторінку [Formulaire.aspx]. Це можна реалізувати за допомогою такого коду:
partial class _Default : System.Web.UI.Page
{
protected void Page_Init(object sender, System.EventArgs e)
{
// перенаправлення до форми введення даних
Response.Redirect("Formulaire.aspx");
}
}
Сторінка-презентація [Default.aspx] містить лише директиву, яка пов’язує її зі сторінкою [Default.aspx.cs]:
<%@ Page Language="C#" AutoEventWireup="true"
CodeBehind="Default.aspx.cs" Inherits="pam_v7._Default" Title="Untitled Page" %>

























