Skip to content

11. برنامه [SimuPaie] – نسخه 7 از ASP.NET / چندنمای / چندصفحه‌ای


مطالعهٔ پیشنهادی: مرجع [1]، توسعهٔ WEB با ASP.NET بند ۱.۱: مثال‌ها


ما اکنون در حال بررسی نسخه‌ای هستیم که از نظر عملکردی با برنامه سه‌لایه 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. مورد ۱: یک صفحه کنترل‌کننده/ویو واحد

در مورد ۱، ما به معماری تک-کنترلر نسخه قبلی بازمی‌گردیم، جایی که صفحه [Default.aspx] همان صفحه P1 است:

  1. کلاینت درخواستی به صفحه P1 (1) ارسال می‌کند
  2. صفحه P1 این درخواست را پردازش می‌کند. برای این کار، ممکن است به کمک لایه [métier] (2) نیاز داشته باشد، که به نوبه خود ممکن است در صورت نیاز به تبادل داده با پایگاه داده، به لایه [dao] نیاز پیدا کند. برنامه کاربردی پاسخی را از لایه [métier] دریافت می‌کند.
  3. بر این اساس، نما (= پاسخ) را برای ارسال به کلاینت انتخاب می‌کند (۳) و اطلاعات (قالب) مورد نیاز آن را در اختیارش قرار می‌دهد (۴). این شامل انتخاب کامپوننت‌های [Panel] یا [View] برای نمایش از صفحه P1 و راه‌اندازی کامپوننت‌های موجود در آن‌ها است.
  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. مورد ۲: یک صفحه کنترل‌کننده، یک صفحه کنترل‌کننده/نما

مورد ۲ می‌تواند معماری‌های مختلفی را پوشش دهد. ما موارد زیر را انتخاب خواهیم کرد:

  1. کلاینت درخواستی به صفحه P1 (1) ارسال می‌کند
  2. صفحه P1 این درخواست را پردازش می‌کند. برای این کار، ممکن است به کمک لایه [métier] (2) نیاز داشته باشد که خود نیز در صورت نیاز به تبادل داده با پایگاه داده، ممکن است به لایه [dao] نیاز پیدا کند. برنامه کاربردی پاسخی را از لایه [métier] دریافت می‌کند.
  3. بر این اساس، نمای ارسال‌شده به کلاینت را انتخاب می‌کند (۳) و اطلاعات (قالب) مورد نیاز آن را در اختیارش قرار می‌دهد (۴). مشخص می‌شود که در این مورد، نمایی که باید تولید شود باید توسط صفحه‌ای غیر از P1، یعنی صفحه P2، تولید شود. برای انجام عملیات (۳) و (۴)، صفحه 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 زمانی مناسب است که نیازی به نگهداری مقادیر مدل برای درخواست مشتری آینده نباشد.
    • از کلاینت بخواهید با استفاده از عملیات [Response.Redirect(" P2.aspx ")] به صفحه P2 هدایت (redirect) کند. در این حالت، صفحه P1 قالب مربوط به صفحه P2 را در جلسه قرار می‌دهد، زیرا زمینه درخواست Context در پایان هر درخواست حذف می‌شود. با این حال، در این مورد، این تغییر مسیر باعث می‌شود که اولین درخواست مشتری به P1 پایان یابد و یک درخواست دوم از همان مشتری ارسال شود، این بار به P2. دو درخواست متوالی وجود دارد. ما می‌دانیم که یک جلسه یکی از روش‌های حفظ «حافظه» بین درخواست‌ها است. جایگزین‌هایی برای استفاده از جلسه وجود دارد.
  4. صرف‌نظر از نحوه تصاحب کنترل توسط P2، سپس به مورد ۱ بازمی‌گردیم: P2 درخواستی را دریافت کرده است که آن را پردازش (۵) و پاسخ را خود تولید (۶، ۷) خواهد کرد. همچنین قابل تصور است که پس از پردازش درخواست، صفحه 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] را از [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]

نماهای برنامه‌ای که در بخش ۱۱.۱ ارائه شده‌اند، بخش‌های مشترکی دارند که می‌توان آن‌ها را در یک صفحهٔ اصلی (Master Page) که در ویژوال استودیو با نام Master Page شناخته می‌شود، تجزیه و تحلیل کرد. برای مثال، ویو‌های [VueSaisies] و [VueSimulationsVides] زیر را در نظر بگیرید که به ترتیب توسط صفحات [Formulaire.aspx] و [Simulations.aspx] تولید شده‌اند:

این دو نما بنر بالایی (عنوان و گزینه‌های منو) را مشترکاً استفاده می‌کنند. این موضوع در مورد تمام نماهایی که به کاربر نمایش داده می‌شوند صادق است: همه آنها بنر بالایی یکسانی خواهند داشت. برای اینکه صفحات مختلف بتوانند یک قطعه ارائه یکسان را به اشتراک بگذارند، راه‌حل‌های مختلفی وجود دارد، از جمله موارد زیر:

  • قرار دادن این بخش مشترک در یک کامپوننت کاربر. این تکنیک اصلی مورد استفاده در ASP.NET 1.1 بود.
  • این بخش مشترک را در یک صفحه اصلی (Master page) قرار دهید. این تکنیک با ASP.NET 2.0 معرفی شد. این همان روشی است که ما در اینجا استفاده می‌کنیم.

برای ایجاد یک صفحه اصلی در یک برنامه وب، مراحل زیر را دنبال کنید:

  • روی پروژه کلیک راست کنید / عنصر جدید اضافه کنید / صفحه اصلی:

افزودن یک صفحهٔ اصلی به‌طور پیش‌فرض سه فایل به برنامهٔ وب اضافه می‌کند:

  • [MasterPage.master]: کد نمایش صفحهٔ اصلی
  • [MasterPage.master.cs]: کد کنترل برای صفحه اصلی
  • [Masterpage.Master.designer.cs]: اعلان کامپوننت صفحه اصلی

کد تولید شده توسط ویژوال استودیو در [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>
  • خط ۱: تگ <%@ Master ... %> برای تعریف صفحه به‌عنوان یک صفحهٔ اصلی استفاده می‌شود. کد کنترل صفحه در فایلی قرار دارد که توسط ویژگی CodeBehind تعریف شده است، و صفحه کلاس تعریف‌شده توسط ویژگی Inherits را ارث می‌برد.
  • خطوط ۱۲–۱۸: فرم روی صفحهٔ اصلی
  • خطوط ۱۴–۱۶: یک کانتینر خالی که در برنامه ما، یکی از صفحات [Formulaire.aspx, Simulations.aspx, Erreurs.aspx] را در خود جای خواهد داد. کلاینت همیشه همان صفحه را در پاسخ دریافت می‌کند – صفحه اصلی (Master page) – که در آن کانتینر [ContentPlaceHolder1] فید HTML را که توسط یکی از صفحات [Formulaire.aspx, Simulations.aspx, Erreurs.aspx] ارائه می‌شود، دریافت خواهد کرد. بنابراین، برای تغییر ظاهر صفحاتی که به کلاینت‌ها ارسال می‌شوند، کافی است ظاهر صفحهٔ اصلی (Master page) را تغییر دهید.
  • خطوط ۸–۹: یک کانتینر خالی که صفحات «فرزندی» می‌توانند برای سفارشی‌سازی هدر <head>...</head> از آن استفاده کنند.

نمایش بصری (زبانه‌ی Design) این کد منبع در (۱) زیر نشان داده شده است. علاوه بر این، می‌توان با استفاده از مؤلفه‌ی [ContentPlaceHolder] (۲) از نوار ابزار [Standard]، به تعداد دلخواه کانتینر اضافه کرد.

کد کنترلی تولید شده توسط ویژوال استودیو در [MasterPage.master.cs] به شرح زیر است:


using System;

public partial class MasterPage : System.Web.UI.MasterPage
{
    protected void Page_Load(object sender, EventArgs e)
    {

    }
}
  • خط ۳: کلاسی که توسط ویژگی [Inherits] از دستور <%@ Master ... %> در صفحه [MasterPage.master] ارجاع شده است، از کلاس [System.Web.UI.MasterPage] مشتق می‌شود

در بالا، می‌توانیم وجود متد Page_Load را مشاهده کنیم که رویداد Load صفحه اصلی (master page) را مدیریت می‌کند. صفحه اصلی یک صفحه دیگر را در خود جای خواهد داد. رویدادهای Load این دو صفحه به چه ترتیبی رخ می‌دهند؟ این یک قاعده کلی است: رویداد Load یک کامپوننت قبل از رویدادِ کانتینرِ آن رخ می‌دهد. بنابراین، رویداد Load صفحه‌ای که در صفحهٔ اصلی (master page) جاسازی شده است، قبل از رویداد خودِ صفحهٔ اصلی رخ خواهد داد.

برای ایجاد یک صفحه در که از صفحه قبلی [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>
  • خط ۱: دستور Page و ویژگی‌های آن
    • MasterPageFile: فایل صفحهٔ اصلی را برای صفحه‌ای که توسط دستور مشخص شده است تعیین می‌کند. نماد ~ نشان‌دهندهٔ پوشهٔ پروژه است.
    • سایر پارامترها، پارامترهای معمول برای یک صفحه وب هستند ASP
  • خطوط ۲–۳: تگ‌های <asp:Content> به صورت جداگانه از طریق ویژگی ContentPlaceHolderID به دستورهای <asp:ContentPlaceHolder> در صفحه اصلی متصل می‌شوند. کامپوننت‌های قرار گرفته بین خطوط ۲–۳ بالا، در زمان اجرا، درون کانتینر 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>
  • خط ۱: به نام کلاس صفحهٔ اصلی توجه کنید: MasterPage
  • خط ۸: یک تصویر پس‌زمینه برای صفحه تعریف شده است.
  • خطوط ۹–۶۴: فرم
  • خط ۱۰: کامپوننت ScriptManager مورد نیاز برای افکت‌های Ajax
  • خطوط ۱۱–۶۳: کانتینر AJax
  • خطوط ۱۲–۶۲: محتوای مجهز به Ajax
  • خطوط ۱۳–۵۵: کامپوننت پنل [entete]
  • خطوط ۵۷–۶۰: کامپوننت پنل [contenu]
  • خطوط ۵۸–۵۹: کامپوننت‌های 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>
  • خط ۱: دستور Page با ویژگی MasterPageFile آن
  • خط ۴: کلاس کنترل صفحه اصلی می‌تواند فیلدها و ویژگی‌های عمومی را ارائه دهد. این موارد با استفاده از دستورات Master.[champ] یا Master.[propriété] برای صفحات تو در تو قابل دسترسی هستند. ویژگی Master صفحه به صفحهٔ اصلی به‌عنوان نمونه‌ای از نوع [System.Web.UI.MasterPage] اشاره دارد. بنابراین، در مثال ما در واقع باید بنویسیم (MasterPage)(Master).[champ] یا (MasterPage)(Master).[propriété]. می‌توان از این تبدیل نوع با درج دستور MasterType از خط ۴ در صفحه جلوگیری کرد. ویژگی VirtualPath این دستور، فایل صفحهٔ اصلی را مشخص می‌کند. سپس کامپایلر می‌تواند فیلدها، ویژگی‌ها و متدهای عمومی ارائه شده توسط کلاس صفحهٔ اصلی را که در این مورد از نوع [MasterPage] است، شناسایی کند.
  • خطوط ۵–۲۲: محتوایی که باید در کانتینر [ContentPlaceHolder1] صفحهٔ اصلی درج شود.

این صفحه را می‌توان با تنظیم محتوای آن (خطوط ۶–۲۱) بر روی محتوای ویوی [VueSaisies] که در بخش ۸.۵.۳ توصیف شده و محتوای ویوی [VueSimulation] که در بخش ۸.۵.۴ توصیف شده، ساخت.

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>

این صفحه را می‌توان با تنظیم محتوای آن (خطوط ۵–۲۱) بر اساس محتوای نمای [VueSimulations] که در بخش ۸.۵.۵ توصیف شده و محتوای نمای [VueSimulationsVides] که در بخش ۸.۵.۶ توصیف شده، ساخت.

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. صفحهٔ درخواست‌شده این درخواست را پردازش می‌کند (مرحله ۱). برای این کار، ممکن است به کمک از لایهٔ [métier] نیاز داشته باشد (مرحله ۲)، که آن نیز در صورت نیاز به تبادل داده با پایگاه داده، ممکن است به لایهٔ [dao] نیاز پیدا کند. برنامه کاربردی پاسخی را از لایه [métier] دریافت می‌کند.
  3. بر اساس این، آن صفحه (D) را برای ارسال به کلاینت انتخاب می‌کند (مرحله ۳) و اطلاعات مورد نیاز آن (قالب) را در اختیارش قرار می‌دهد (مرحله ۴). ما سه امکان برای تولید این پاسخ دیده‌ایم:
    • صفحهٔ درخواستی (D) همچنین همان صفحهٔ (R) ارسال‌شده در پاسخ است. سپس ساخت قالب پاسخ (R) مستلزم اختصاص مقادیر لازم به برخی از اجزای صفحهٔ (D) است.
    • صفحهٔ درخواست‌شده (D) همان صفحه‌ای نیست که در پاسخ ارسال می‌شود (R). سپس صفحه (D) می‌تواند:
      • انتقال کنترل به صفحه (R) با استفاده از دستور Server.Transfer(" R "). قالب سپس می‌تواند با استفاده از Context.Items("key")=value یا، به ندرت، در جلسه با استفاده از Session.Items("key")=value در کانتکست قرار گیرد.
      • کاربر را با استفاده از دستور Response.redirect(" R ") به صفحه (R) هدایت کند. سپس قالب را می‌توان در جلسه قرار داد اما نه در زمینه.
  4. پاسخ به کلاینت ارسال می‌شود (مرحله ۵)

هر یک از صفحات [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)
    {
....
      }
    }
  }
}
  • خط ۵: کلاس [MasterPage] نامیده می‌شود و از کلاس سیستمی [System.Web.UI.MasterPage] مشتق شده است.
  • خطوط ۹–۱۴: شش گزینهٔ منو به‌عنوان ویژگی‌های عمومی کلاس تعریف شده‌اند
  • خطوط ۱۶–۱۹: متد عمومی SetMenu به صفحات [Formulaire.aspx, Simulations.aspx, Erreurs.aspx] اجازه می‌دهد منوی صفحه اصلی را تنظیم کنند
  • خطوط 22–25: روشی که کلیک روی لینک [LinkButtonTerminerSession] را مدیریت می‌کند
  • خطوط ۲۸–۳۱: رویه‌ای برای رسیدگی به رویداد 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
خروج از جلسهٔ جاری

اجزاء ۱ تا ۶ خارج از صفحه‌ای که شامل آن‌هاست قابل دسترسی نیستند. ویژگی‌های موجود در خطوط ۹ تا ۳۷ با هدف قابل دسترسی کردن آن‌ها برای کلاس‌های خارجی، در این مورد کلاس‌های صفحات دیگر برنامه، ارائه شده‌اند.

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]

مراحل ۱ و ۳ نیاز به دسترسی به کامپوننت‌های صفحه [Formulaire.aspx] دارند. این امر صادق نیست. در واقع، صفحه اصلی (master page) هیچ اطلاعی از کامپوننت‌های صفحاتی که ممکن است در کانتینر آن ([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)
    {
...
    }
 }
}
  • خطوط ۱۲–۱۵: وقتی رویداد Load در صفحه [Formulaire.aspx] رخ می‌دهد، کلاس [MasterPage] از صفحه اصلی instantiate شده است. ویژگی‌های عمومی 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] نتواند برنامه را به‌درستی راه‌اندازی کند، دو متغیر ثابت عمومی را مقداردهی می‌کند:

  • متغیر بولین 'Error' در خط 12 روی vrai تنظیم می‌شود
  • متغیر `Msg` در خط ۱۱ حاوی پیامی است که جزئیات خطای رخ‌داده را ارائه می‌دهد

هنگامی که کاربر یکی از صفحات [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] باشد، ما به سادگی (خط ۱۲) کلاینت را به صفحهٔ [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>
  • خطوط ۱–۱۳: کانتینر با شناسه «form1»
  • خطوط ۴–۶: کانتینر با شناسه "entete"، که در داخل کانتینر با شناسه "form1" قرار دارد
  • خطوط ۸–۱۱: کانتینر با شناسه «contenu»، که در داخل کانتینر با شناسه «form1» قرار دارد
  • خطوط ۹–۱۰: کانتینر با شناسه "ContentPlaceHolder1"، که در کانتینر با شناسه "content" قرار دارد

یک صفحه 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>
  • خط ۱۲: کامپوننت [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;
            }
        }
  • خط ۴: یک رویدادپرداز به رویداد Click روی لینک LinkButtonTerminerSession مرتبط شده است. این رویدادپرداز در کلاس MasterPage قرار دارد.
  • خط ۶: بررسی می‌شود که آیا کلاس [Global] مقدار بولی Erreur را تنظیم کرده است
  • خط ۹: اگر چنین باشد، بولین IsPageErreurs نشان می‌دهد که آیا صفحهٔ جاسازی‌شده در صفحهٔ اصلی، صفحهٔ [Erreurs.aspx] است یا خیر
  • خط ۱۲: اگر صفحهٔ جاسازی‌شده در صفحهٔ اصلی، صفحهٔ [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");
}
  • خط ۴: جلسهٔ جاری پاک می‌شود
  • خط ۶: کاربر به صفحه [Formulaire.aspx] هدایت می‌شود

همانطور که مشاهده می‌شود، این کد شامل هیچ‌یک از اجزای صفحات [Formulaire.aspx, Simulations.aspx, Erreurs.aspx] نیست. بنابراین، این رویداد می‌تواند توسط خود صفحه اصلی (master page) مدیریت شود.

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] نمایش خطای راه‌اندازی برنامه در صورت وقوع آن است:

  • خط ۱۰: بررسی می‌کند که آیا inicialization با شکست مواجه شده است
  • خطوط ۱۳–۱۴: اگر چنین باشد، پیام خطا (Global.Msg) در یک لیست [ErreursInitialisation] قرار می‌گیرد
  • خطوط ۱۶–۱۷: به کامپوننت [rptErreurs] دستور داده می‌شود که این لیست را نمایش دهد
  • خط ۲۰: در همه موارد (چه خطایی رخ داده باشد یا نه)، گزینه‌های منوی صفحه اصلی نمایش داده نمی‌شوند، بنابراین کاربر نمی‌تواند هیچ اقدام جدیدی را از این صفحه آغاز کند.

اگر کاربر مستقیماً صفحه [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]، ورودی‌های [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)
    {
        // اثر ایجکس
        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] در پاسخ (2)، صفحه [Formulaire.aspx] را دریافت کرد. ما می‌دانیم که درخواست (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" %>