Skip to content

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 з одним контролером.

Обробка запиту клієнта відбувається за такими етапами:

  1. клієнт надсилає запит до додатка. Він надсилає його на одну з двох сторінок [Formulaire.aspx, Simulations.aspx].
  2. запитана сторінка обробляє цей запит. Для цього їй може знадобитися допомога рівня [métier], якому, у свою чергу, може знадобитися рівень [dao], якщо необхідно обмінятися даними з базою даних. Додаток отримує відповідь від рівня [métier].
  3. Згідно з нею, воно вибирає (3) представлення (= відповідь), яке слід надіслати клієнту, надаючи йому (4) необхідну інформацію (шаблон).
  4. Відповідь надсилається клієнту (5)

11.1. Види додатка

Користувачеві доступні такі види:

  • - вигляд [VueSaisies], що відображає форму моделювання

Image

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

Image

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

Image

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

Image

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

Image

11.2. Генерація переглядів у середовищі з кількома контролерами

У попередній версії всі подання генерувалися на основі єдиної сторінки [Default.aspx]. Вона містила два компоненти [MultiView], а подання складалися з одного або двох компонентів [View], що належали до цих двох компонентів [MultiView].

Ця архітектура є ефективною, коли кількість переглядів невелика, але досягає своїх меж, щойно кількість компонентів, що утворюють різні перегляди, стає значною: адже при кожному запиті, що надходить на єдину сторінку [Default.aspx], всі її компоненти інстанціюються, хоча для формування відповіді користувачеві використовуються лише деякі з них. Таким чином, при кожному новому запиті виконується зайва робота, що стає обтяжливою, коли загальна кількість компонентів сторінки є значною.

Виходом із ситуації є розподіл представлень між різними сторінками. Саме це ми й робимо тут. Розглянемо два різні випадки формування представлень:

  1. запит надходить на сторінку P1, і вона формує відповідь
  2. запит надсилається на сторінку P1, яка звертається до сторінки P2 з проханням згенерувати відповідь

11.2.1. Випадок 1: одна сторінка-контролер / один вигляд

У випадку 1 ми повертаємося до архітектури з одним контролером попередньої версії, де сторінка [Default.aspx] є сторінкою P1:

  1. клієнт надсилає запит на сторінку P1 (1)
  2. сторінка P1 обробляє цей запит. Для цього їй може знадобитися допомога рівня [métier] (2), якому, у свою чергу, може знадобитися рівень [dao], якщо необхідно обмінятися даними з базою даних. Додаток отримує відповідь від шару [métier].
  3. Згідно з ним, вона обирає (3) представлення (= відповідь), яке слід надіслати клієнту, надаючи йому (4) інформацію (шаблон), яка їй потрібна. Тут йдеться про те, щоб вибрати на сторінці P1 компоненти [Panel] або [View] для відображення та ініціалізувати компоненти, що містяться в них.
  4. відповідь надсилається клієнту (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 може охоплювати різні архітектури. Ми оберемо таку:

  1. клієнт надсилає запит на сторінку P1 (1)
  2. сторінка P1 обробляє цей запит. Для цього їй може знадобитися допомога рівня [métier] (2), якому, у свою чергу, може знадобитися рівень [dao], якщо необхідно обмінятися даними з базою даних. Додаток отримує відповідь від шару [métier].
  3. Згідно з ним, вона обирає (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. Маємо два послідовні запити. Відомо, що сесія є одним із засобів збереження «пам’яті» між запитами. Існують й інші рішення, окрім сесії.
  4. Незалежно від того, яким чином 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] візуальний вигляд шаблону буде таким:

Тип
Назва
Роль
A
Панель (рожева, показана вище)
заголовок
заголовок сторінки
B
Панель (жовта, як показано вище)
вміст
вміст сторінки
1
LinkButton
LinkButtonFaireSimulation
запит на розрахунок симуляції
2
LinkButton
LinkButtonEffacerSimulation
очистити форму введення даних
3
LinkButton
LinkButtonVoirSimulations
відображає список вже виконаних моделювань
4
LinkButton
LinkButtonFormulaireSimulation
повертає до форми введення даних
5
LinkButton
LinkButtonEnregistrerSimulation
зберігає поточну симуляцію у списку симуляцій
6
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>
                &nbsp;&nbsp;&nbsp</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]: сторінка, яка відображається у разі помилки під час ініціалізації додатка. На цій сторінці неможливо виконувати жодних дій.

Обробка запиту клієнта відбувається за такими етапами:

  1. клієнт надсилає запит до додатка. Зазвичай він робить це на одній із двох сторінок [Formulaire.aspx, Simulations.aspx], але ніщо не заважає йому звернутися до сторінки [Erreurs.aspx]. Цей випадок слід передбачити.
  2. запитана сторінка обробляє цей запит (етап 1). Для цього їй може знадобитися допомога рівня [métier] (етап 2), якому, у свою чергу, може знадобитися рівень [dao], якщо необхідно обмінятися даними з базою даних. Додаток отримує відповідь від шару [métier].
  3. Згідно з ним, вона обирає (етап 3) вигляд (= відповідь), який потрібно надіслати клієнту, і надає йому (етап 4) інформацію (модель), яка їй потрібна. Ми розглянули три можливості для формування цієї відповіді:
    • запитана сторінка (D) є також сторінкою (R), надісланою у відповідь. Створення шаблону відповіді (R) полягає в тому, щоб присвоїти певним компонентам сторінки (D) значення, які вони повинні мати у відповіді.
    • запитана сторінка (D) не є сторінкою (R), що надсилається у відповідь. У цьому випадку сторінка (D) може:
      • передати потік виконання сторінці (R) за допомогою інструкції Server.Transfer(" R "). Тоді шаблон можна розмістити в контексті за допомогою Context.Items("ключ")=значення або, рідше, у сесії за допомогою Session.Items("ключ")=значення
      • перенаправити клієнта на сторінку (R) за допомогою команди Response.redirect(" R "). Після цього шаблон можна розмістити в сесії, але не в контексті.
  4. відповідь надсилається клієнту (крок 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; }
    }

...
  }
}

Щоб зрозуміти цей код, слід згадати компоненти, з яких складається головна сторінка:

Тип
Назва
Роль
A
Панель (рожева, показана вище)
заголовок
заголовок сторінки
B
Панель (жовта, як показано вище)
вміст
вміст сторінки
1
LinkButton
LinkButtonFaireSimulation
запит на розрахунок симуляції
2
LinkButton
LinkButtonEffacerSimulation
очистити форму введення даних
3
LinkButton
LinkButtonVoirSimulations
відображає список вже виконаних моделювань
4
LinkButton
LinkButtonFormulaireSimulation
повертає до форми введення даних
5
LinkButton
LinkButtonEnregistrerSimulation
зберігає поточну симуляцію у списку симуляцій
6
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]:

  1. перевірити введені дані (години, дні) на сторінці [Formulaire.aspx]
  2. провести розрахунок заробітної плати
  3. відобразити результати на сторінці [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, після чого дерево компонентів цієї сторінки набуває такого вигляду:

...
<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">
              <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:ContentPlaceHolder>
            </asp:Panel>
        </div>
    </form>
</body>
</html>
  • рядок 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] обробляє п’ять подій:

  1. подія Load на сторінці
  2. подія Click на посиланні [LinkButtonFaireSimulation] головної сторінки
  3. подія Click на посиланні [LinkButtonEffacerSimulation] головної сторінки
  4. подія Click за посиланням [LinkButtonEnregistrerSimulation] на головній сторінці
  5. подія 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" %>