Skip to content

5. إدارة واجهة المستخدم

5.1. Introduction

في العلاقة بين العميل والخادم على الويب، يرسل العميل المعلومات إلى الخادم في شكل سلسلة من المعلمات [param1=val1&param2=val2&...]. في الأمثلة السابقة، قمنا في الغالب بإنشاء هذه السلسلة يدويًا عن طريق طلب عناوين URL بالشكل [http://localhost/appli? param1=val1&param2=val2&...]. في الواقع، المعلومات التي يرسلها العميل إلى الخادم تأتي من النماذج التي ملأها المستخدم. نستكشف كيفية إنشاء هذه النماذج في هذا الفصل. كما نقدم أداة WebMatrix التي ستسمح لنا برسم واجهات المستخدم. يتم عرض تثبيت هذه الأداة في الملاحق.

5.2. لغة HTML

5.2.1. مثال

لنأخذ المثال التالي، الذي تم إنشاؤه باستخدام [Web Matrix] والذي يعرض:

  • جدول
  • صورة
  • رابط

Image

لنقم بتشغيل [WebMatrix] ثم نختار الخيار [File/New File]:

Image

نختار إنشاء صفحة HTML. ستؤدي المعلومات المذكورة أعلاه إلى إنشاء ملف [d:\data\devel\aspnet\chap4\exemple1\exemple1.htm]. يوفر [WebMatrix] خيارين لتحرير هذا الملف: الوضع [Design] والوضع [HTML]:

Image

يتيح وضع [Design] استخدام لوحة مكونات HTML التي يوفرها [WebMatrix]:

Image

لإدراج عنصر من هذه المجموعة، يكفي النقر عليه مرتين ثم وضعه في نافذة [Design]. يسمح الوضع [HTML] بإنشاء المستند HTML باستخدام محرر نصوص. ولذلك، يجب معرفة قواعد لغة HTML. في علامة التبويب [HTML]، تم إنشاء هيكل مستند:

Image

تعد نافذة [HTML] مفيدة جدًا لمن لا يعرف لغة HTML. فهو يقوم بإنشاء مستنده في النافذة [Design] ويتحقق من الكود HTML الذي تم إنشاؤه في النافذة [HTML]. وبذلك يكتسب تدريجياً إتقان لغة HTML ويمكنه العمل بسرعة كافية باستخدام محرر النصوص فقط دون الحاجة إلى وضع [Design]. سنوضح الآن كيفية إنشاء المستند HTML المقدم في بداية هذا القسم. نحن نعمل في النافذة [Design]. أولاً، ندخل السطر الأول من النص مباشرةً:

Image

  • نضيف المكون [Horizontal Rule] في لوحة المكونات:

Image

  • نضيف المكون [Table]:

Image

  • نضع المؤشر في السطر الثالث من الجدول لحذفه باستخدام الخيار [HTML/Edit Table/Delete Table Row]. ثم نكتب النص المطلوب في كل خلية:

Image

  • نضع المؤشر في إحدى خلايا الجدول وننظر إلى خصائصها. تظهر نافذة الخصائص في أسفل يمين بيئة العمل:

Image

  • يتم تمثيل الخلية بواسطة العلامة HTML <TD>. وبالتالي، يتم عرض خصائص العلامة <TD>. ننتقل إلى الجدول الذي يمثل كائنًا يشمل الخلية. نضغط على القائمة المنسدلة (click to see parent HTML elements) أعلاه لاختيار الكائن <TABLE>:

Image

  • يحتوي الكائن <TABLE> على خاصية [border] تحدد عرض الحدود المحيطة بخلايا الجدول. هنا، نأخذ border=1.

Image

  • نقوم الآن بتحرير سمات الكائن <TD> للخلية (1,2) لتعيين align=Center و width=200 (بكسل). سيتم توسيط النص في الخلية (align=center) وستكون عرضها 200 بكسل. لرؤية التعديل، قد تضطر أحيانًا إلى تحديد علامة التبويب [HTML] ثم العودة إلى علامة التبويب [Design]:

Image

  • الآن نضع النص الذي يسبق الصورة:

Image

  • ثم الصورة بالنقر المزدوج على المكون [image] من اللوحة:

Image

  • نختار الصورة لتعديل خصائصها:

Image

  • في السمة [src]، نضع اسم الملف الذي يحتوي على الصورة، هنا [univ01.gif]:

Image

  • نضع النص الذي يسبق الرابط:

Image

  • نقوم بتحويل النص [ici] إلى رابط إلى عنوان URL [http://istia.univ-angers.fr]. للقيام بذلك، نحدده ثم نختار الخيار [HTML/Insert Hyperlink]:

Image

  • نحصل على النتيجة التالية:

Image

  • لقد أوشكنا على الانتهاء. لنلقِ نظرة على الكود HTML الذي تم إنشاؤه في علامة التبويب [HTML]:
<html>
<head>
</head>
<body>
    <p>
        Le langage HTML - 1 
    </p>
    <hr />
    <table border="1">
        <tbody>
            <tr>
                <td>
                    cellule(1,1)</td>
                <td align="middle" width="200">
                    cellule(1,2)</td>
                <td>
                    cellule(1,3)</td>
            </tr>
            <tr>
                <td>
                    cellule(2,1)</td>
                <td>
                    cellule(2,2)</td>
                <td>
                    cellule(2,3)</td>
            </tr>
        </tbody>
    </table>
    <p>
        Une image <img src="univ01.gif" /> 
    </p>
    <p>
        Le site de l'istia <a href="http://istia.univ-angers.fr">ici</a>
    </p>
</body>
</html>

لا يزال لدينا بعض التفاصيل التي يجب تسويتها. أولاً، نود أن نضع عنواناً لوثيقتنا. لا يسمح [WebMatrix] بذلك في الوضع [Design]. في علامة التبويب [HTML]، نستبدل التسلسل <head>..</head> بالتسلسل التالي:

<head>
    <title>HTML1</title>
</head>

بالإضافة إلى ذلك، نرغب في عرض النص [Le langage HTML - 1] بحروف أكبر. تسمح التسلسلات <Hi>نص</Hi> بتحديد حجم النص باستخدام i الذي يتراوح من 1 إلى 6 من الأكبر إلى الأصغر. هنا، سنختار H2. التسلسل

    <p>
        Le langage HTML - 1 
    </p>

يصبح:

<h2>Le langage HTML - 1</h2>

تعكس النافذة [Design] التغييرات التي أجريناها:

Image

لم يتبق لنا سوى إجراء الاختبار باستخدام الخيار [View/Start] أو [F5]. أما الخيار [WebMatrix] فيتطلب بعض المعلومات لتشغيل خادم الويب [Cassini]:

Image

يمكننا قبول القيم المقترحة افتراضيًا. يتم تشغيل الخادم [Cassini] وتظهر صفحتنا في متصفح:

Image

بدافع الفضول، يمكننا التحقق من المعلمات التي تم تشغيل [Cassini] بها:

Image

لقد قدمنا أساسيات إنشاء صفحة HTML باستخدام [WebMatrix]. ندعو القارئ إلى إنشاء صفحات HTML أخرى والتحقق في كل مرة من الكود HTML الذي تم إنشاؤه. وبالتدريج، سيتمكن من إنشاء صفحة دون الحاجة إلى استخدام الوضع [Design]. يتخذ المستند HTML الشكل العام التالي:

<html>
    <head>
        <title>Un titre</title>
        ...
    </head>
    <body attributs>
        ...
    </body>
</html>

يتم تأطير المستند بأكمله بعلامات <html>...</html>. ويتكون من جزأين:

<head>...</head>: هذا هو الجزء غير القابل للعرض من المستند. وهو يوفر معلومات للمتصفح الذي سيقوم بعرض المستند. غالبًا ما نجد فيه العلامة <title>...</title> التي تحدد النص الذي سيتم عرضه في شريط عنوان المتصفح. يمكن أن نجد فيه علامات أخرى، لا سيما العلامات التي تحدد الكلمات المفتاحية للمستند، وهي الكلمات المفتاحية التي تستخدمها محركات البحث لاحقًا. يمكن أيضًا العثور في هذا الجزء على نصوص برمجية، مكتوبة غالبًا بلغة جافا سكريبت أو في بي سكريبت، والتي سيتم تنفيذها بواسطة المتصفح.

<body attributs>...</body>: هذا هو الجزء الذي سيعرضه المتصفح. تشير العلامات HTML الموجودة في هذا الجزء إلى المتصفح الشكل المرئي "المطلوب" للوثيقة. سيقوم كل متصفح بتفسير هذه العلامات بطريقته الخاصة. وبالتالي، يمكن لمتصفحين مختلفين عرض نفس المستند على الويب بشكل مختلف. وهذا عادةً ما يمثل أحد التحديات التي يواجهها مصممو الويب.

كان رمز HTML للوثيقة السابقة كما يلي:

<html>
<head>
    <title>HTML1</title>
</head>
<body>
    <h2>Le langage HTML - 1 
    </h2>
    <hr />
    <table border="1">
        <tbody>
            <tr>
                <td>
                    cellule(1,1)</td>
                <td align="middle" width="200">
                    cellule(1,2)</td>
                <td>
                    cellule(1,3)</td>
            </tr>
            <tr>
                <td>
                    cellule(2,1)</td>
                <td>
                    cellule(2,2)</td>
                <td>
                    cellule(2,3)</td>
            </tr>
        </tbody>
    </table>
    <p>
        Une image <img src="univ01.gif" /> 
    </p>
    <p>
        Le site de l'istia <a href="http://istia.univ-angers.fr">ici</a> 
    </p>
</body>
</html>
عنصر
العلامات والأمثلة HTML
titre du document
<title>HTML1</title>
HTML1 سيظهر في شريط عنوان المتصفح الذي سيعرض المستند
barre horizontale
<hr>: يعرض خطًا أفقيًا
tableau
<سمات الجدول>....</table>: لتعريف الجدول
<tr attributes>...</tr>: لتعريف سطر
<td سمات>...</td>: لتعريف خلية
أمثلة:
<table border="1">...</table>: تحدد السمة border سماكة حدود الجدول
<td align="center" width="200">خلية(1,2)</td>: تحدد خلية سيكون محتواها cellule(1,2). سيتم توسيط هذا المحتوى أفقيًا (align="center"). سيكون عرض الخلية 200 بكسل (width="200")
image
<img src="univ01.gif" />: يحدد صورة ملفها الأصلي هو univ01.gif على خادم الويب (src="univ01.gif"). يوجد هذا الرابط في مستند ويب تم الحصول عليه باستخدام URL http://localhost/exemple1.htm. وبالتالي، سيطلب المتصفح ملف URL http://localhost/univ01.gif للحصول على الصورة المشار إليها هنا.
lien
<a href="http://istia.univ-angers.fr">هنا</a>: يجعل النص ici بمثابة رابط إلى URL http://istia.univ-angers.fr.

نرى في هذا المثال البسيط أنه لإنشاء المستند بالكامل، يجب على المتصفح إرسال طلبين إلى الخادم:

http://localhost/exemple1.htm للحصول على مصدر المستند HTML

http://localhost/univ01.gif للحصول على الصورة univ01.gif

5.2.2. إنشاء نموذج

الغرض من النموذج HTML هو تقديم صفحة إدخال معلومات للمستخدم تشبه نماذج الإدخال الموجودة في نظام ويندوز. يتم إرسال نموذج الإدخال إلى المتصفح في شكل مستند HTML. وسيعرض المتصفح النموذج للمستخدم الذي سيقوم بملئه والتحقق من صحته باستخدام زر مخصص لهذه الوظيفة. ثم يقوم المتصفح بنقل القيم المدخلة إلى الخادم للمعالجة. وسنلاحظ أنه لا يعيد إرسال النموذج بالكامل إلى الخادم، بل القيم المدخلة فقط. يعرض المثال التالي نموذج ويب تم إنشاؤه أيضًا باستخدام WebMatrix:

Image

الرمز HTML الذي تم إنشاؤه بواسطة [WebMatrix] هو التالي:


<html>
    <head>
        <title>Formulaire</title>
        <script language="javascript">
        function effacer(){
            alert("Vous avez cliqué sur le bouton [Effacer]");
        }
        </script>
    </head>
    <body>
        <p>
            Gestion d'un formulaire
        </p>
        <hr />
        <form name="formulaire" method="post">
            <table border="1">
                <tr>
                    <td>
                        Etes-vous marié(e)</td>
                    <td>
                        <p align="center">
                            <input type="radio" value="oui" name="rdMarie" />Oui 
                            <input type="radio" checked value="non" name="rdMarie" />Non
                        </p>
                    </td>
                </tr>
                <tr>
                    <td>
                        Cases à cocher
                    </td>
                    <td>
                        <p align="center">
                            <input type="checkbox" value="un" name="C1" />1
                            <input type="checkbox" checked value="deux" name="C2" />2
                            <input type="checkbox" value="trois" name="C3" />3
                        </p>
                    </td>
                </tr>
                <tr>
                    <td>
                        Champ de saisie</td>
                    <td>
                        <p align="center">
                            <input type="text" maxlength="30" value="qqs mots" name="txtSaisie" />
                        </p>
                    </td>
                </tr>
                <tr>
                    <td>
                        Mot de passe</td>
                    <td>
                        <p align="center">
                            <input type="password" maxlength="12" size="12" value="unMotDePasse" name="txtMdp" />
                        </p>
                    </td>
                </tr>
                <tr>
                    <td>
                        Boîte de saisie</td>
                    <td>
                        <p align="center">
                        </p>
                        <textarea name="areaSaisie">ligne1
ligne2</textarea>
                    </td>
                </tr>
                <tr>
                    <td>
                        ComboBox</td>
                    <td>
                        <p align="center">
                        </p>
                        <select name="cmbValeurs">
                            <option value="1">choix1</option>
                            <option value="2" selected>choix2</option>
                            <option value="3">choix3</option>
                        </select>
                    </td>
                </tr>
                <tr>
                    <td>
                        Liste à choix simple</td>
                    <td>
                        <p align="center">
                        </p>
                        <select size="3" name="lstSimple">
                            <option value="1" selected>liste1</option>
                            <option value="2">liste2</option>
                            <option value="3">liste3</option>
                            <option value="4">liste4</option>
                            <option value="5">liste5</option>
                        </select>
                    </td>
                </tr>
                <tr>
                    <td>
                        Liste à choix multiple</td>
                    <td>
                        <p align="center">
                        </p>
                        <select multiple size="3" name="lstMultiple">
                            <option value="1" selected>multiple1</option>
                            <option value="2">multiple2</option>
                            <option value="3" selected>multiple3</option>
                            <option value="4">multiple4</option>
                            <option value="5">multiple5</option>
                        </select>
                    </td>
                </tr>
                <tr>
                    <td>
                        Bouton simple</td>
                    <td>
                        <p align="center">
                            <input onclick="effacer()" type="button" value="Effacer" name="btnEffacer" />
                        </p>
                    </td>
                </tr>
                <tr>
                    <td>
                        Bouton submit</td>
                    <td>
                        <p align="center">
                            <input type="submit" value="Envoyer" name="btnEnvoyer" />
                        </p>
                    </td>
                </tr>
                <tr>
                    <td>
                        Bouton reset</td>
                    <td>
                        <p align="center">
                            <input type="reset" value="Rétablir" name="btnRetablir" runat="server" />
                        </p>
                    </td>
                </tr>
            </table>
            <input type="hidden" name="secret" value="uneValeur" />
        </form>
    </body>
</html>

الارتباط بين الفحص البصري <--> العلامة HTML هو التالي:

التحكم
العلامة HTML
formulaire
<form name="formulaire" method="post">
champ de saisie
<input type="text" maxlength="30" value="بضع كلمات" name="txtSaisie" />
champ de saisie cachée
<input type="password" maxlength="12" size="12" value="unMotDePasse" name="txtMdp" />
champ de saisie multilignes
<textarea name="areaSaisie">السطر 1
السطر 2</textarea>
boutons radio
<input type="radio" value="نعم" name="rdMarie" />نعم
<input type="radio" checked value="لا" name="rdMarie" />لا
cases à cocher
<input type="checkbox" value="واحد" name="C1" />1
<input type="checkbox" checked value="اثنان" name="C2" />2
<input type="checkbox" value="ثلاثة" name="C3" />3
Combo
<select name="cmbValeurs">
<option value="1">الخيار 1</option>
<option value="2" selected>الخيار 2</option>
<option value="3">الخيار 3</option>
</select>
liste à sélection unique
<select size="3" name="lstSimple">
<option value="1" selected>القائمة 1</option>
<option value="2">القائمة 2</option>
<option value="3">القائمة 3</option>
<option value="4">القائمة 4</option>
<option value="5">القائمة 5</option>
</select>
liste à sélection multiple
<select multiple size="3" name="lstMultiple">
<option value="1" selected>multiple1</option>
<option value="2">multiple2</option>
<option value="3" selected>multiple3</option>
<option value="4">multiple4</option>
<option value="5">multiple5</option>
</select>
champ caché
<input type="hidden" name="secret" value="uneValeur" />
bouton de type submit
<input type="submit" value="إرسال" name="btnEnvoyer" />
bouton de type reset
<input type="reset" value="إعادة تعيين" name="btnRetablir" runat="server" />
bouton de type button
<input onclick="effacer()" type="button" value="مسح" name="btnEffacer" />

لنستعرض هذه العناصر المختلفة.

5.2.2.1. النموذج

formulaire
<form name="formulaire" method="post">
balise HTML
<form name="..." method="..." action="...">...</form>
attributs
name="frmexemple": اسم النموذج
method="..." : الطريقة التي يستخدمها المتصفح لإرسال القيم التي تم جمعها في النموذج إلى خادم الويب
action="..." : URL التي سيتم إرسال القيم التي تم جمعها في النموذج إليها.
يُحاط النموذج الإلكتروني بعلامات <form>...</form>. يمكن أن يكون للنموذج اسم (name="xx"). وينطبق ذلك على جميع عناصر التحكم الموجودة في النموذج. ويكون هذا الاسم مفيدًا إذا كان المستند الإلكتروني يحتوي على نصوص برمجية يجب أن تشير إلى عناصر النموذج. الغرض من النموذج هو جمع المعلومات التي يقدمها المستخدم عبر لوحة المفاتيح/الماوس وإرسالها إلى عنوان خادم ويب. أي عنوان؟ العنوان المشار إليه في السمة action="URL". إذا كان هذا السمة غير موجود، فسيتم إرسال المعلومات إلى خادم المستند الذي يوجد فيه النموذج. كيف يقوم عميل الويب بإرسال المعلومات (الموجودة في النموذج) إلى خادم الويب؟ لقد رأينا ذلك بالتفصيل. يمكنه استخدام طريقتين مختلفتين تسميان POST و GET. السمة method="méthode"، مع طريقة تساوي GET أو POST، في العلامة <form> يحدد للمتصفح الطريقة التي يجب استخدامها لإرسال المعلومات التي تم جمعها في النموذج إلى URL المحددة بواسطة السمة action="URL". عندما لا يتم تحديد السمة method، يتم استخدام الطريقة GET بشكل افتراضي.

5.2.2.2. حقل الإدخال

Image

champ de saisie
<input type="text" maxlength="30" value="بضع كلمات" name="txtSaisie" />
<input type="password" maxlength="12" size="12" value="unMotDePasse" name="txtMdp" />
balise HTML
<input type="..." name="..." size=".." value="..">
توجد علامة input لمختلف عناصر التحكم. السمة type هي التي تسمح بالتمييز بين عناصر التحكم المختلفة.
attributs
type="text": يحدد أن هذا حقل إدخال
type="password": يتم استبدال الأحرف الموجودة في حقل الإدخال بأحرف *. هذا هو الفرق الوحيد عن حقل الإدخال العادي. هذا النوع من عناصر التحكم مناسب لإدخال كلمات المرور.
size="12": عدد الأحرف المرئية في الحقل - لا يمنع إدخال المزيد من الأحرف
maxlength="30": يحدد العدد الأقصى للأحرف بـ 30 - يتولى المتصفح مهمة الالتزام بهذا السمة
name="txtSaisie": اسم عنصر التحكم
value="بعض الكلمات": النص الذي سيتم عرضه في حقل الإدخال.

5.2.2.3. حقل إدخال متعدد الأسطر

Image

champ de saisie multilignes
<textarea name="areaSaisie">السطر 1
السطر 2</textarea>
balise HTML
<textarea ...>نص</textarea>
يعرض منطقة إدخال متعددة الأسطر مع وجود نص بداخلها في البداية
attributs
rows="2": عدد الأسطر
cols="'20" : عدد الأعمدة
name="areaSaisie": اسم عنصر التحكم

5.2.2.4. أزرار الاختيار

Image

boutons radio
<input type="radio" value="نعم" name="rdMarie" />نعم
<input type="radio" checked value="لا" name="rdMarie" />لا
balise HTML
<input type="radio" attribut2="valeur2" ..../>نص
يعرض زر اختيار مع نص بجانبه.
attributs
name="rdMarie": اسم عنصر التحكم. تشكل أزرار الاختيار التي تحمل نفس الاسم مجموعة من الأزرار المتنافية: لا يمكن تحديد سوى واحد منها.
value="القيمة" : القيمة المخصصة لزر الاختيار. لا ينبغي الخلط بين هذه القيمة والنص المعروض بجانب زر الاختيار، حيث إن هذا النص مخصص للعرض فقط.
checked: إذا كانت هذه الكلمة الرئيسية موجودة، يكون زر الاختيار محددًا، وإلا فإنه غير محدد.

5.2.2.5. مربعات الاختيار

cases à cocher
<input type="checkbox" value="واحد" name="C1" />1
<input type="checkbox" checked value="deux" name="C2" />2
<input type="checkbox" value="ثلاثة" name="C3" />3

Image

balise HTML
<input type="checkbox" attribut2="valeur2" ..../>نص
يعرض مربع اختيار مع نص بجانبه.
attributs
name="C1": اسم عنصر التحكم. يمكن أن تحمل مربعات الاختيار نفس الاسم أو لا. تشكل المربعات التي تحمل نفس الاسم مجموعة من المربعات المرتبطة.
value="القيمة": القيمة المخصصة لمربع الاختيار. لا يجب الخلط بين هذه القيمة والنص المعروض بجانب زر الاختيار. فهذا النص مخصص للعرض فقط.
checked: إذا كانت هذه الكلمة الرئيسية موجودة، يكون زر الاختيار محددًا، وإلا فإنه غير محدد.

5.2.2.6. قائمة منسدلة (combo)

Combo
<select name="cmbValeurs">
<option value="1">الخيار 1</option>
<option value="2" selected>الخيار 2</option>
<option value="3">الخيار 3</option>
</select>

Image

balise HTML
<select size=".." name="..">
<option [selected="selected"] [value="valeur"]>نص</option>
...
</select>
يعرض في قائمة النصوص الموجودة بين العلامات <option>...</option>
attributs
name="cmbValeurs": اسم عنصر التحكم.
size="1": عدد عناصر القائمة المرئية. size="1" يجعل القائمة تعادل مربع الاختيار. هذه هي القيمة الافتراضية في حالة عدم وجود السمة [size].
selected="selected": إذا كانت هذه الكلمة الرئيسية موجودة لعنصر في القائمة، فسيظهر هذا العنصر محدداً في القائمة. في المثال أعلاه، يظهر عنصر القائمة choix2 كعنصر محدد في القائمة المنسدلة عند عرضها لأول مرة.
value="القيمة": يحدد القيمة التي سيتم إرسالها إلى الخادم إذا تم تحديد العنصر. إذا كان هذا السمة غير موجود، فسيتم إرسال النص المرتبط بالخيار إلى الخادم.

5.2.2.7. قائمة الاختيار الفردي

liste à sélection unique
<select size="3" name="lstSimple">
<option value="1" selected>القائمة 1</option>
<option value="2">القائمة 2</option>
<option value="3">القائمة 3</option>
<option value="4">القائمة 4</option>
<option value="5">القائمة 5</option>
</select>

Image

balise HTML
<select size=".." name="..">
<option [selected] [value="valeur"]>...</option>
...
</select>
يعرض في قائمة النصوص الموجودة بين العلامات <option>...</option>
attributs
نفس العناصر الموجودة في القائمة المنسدلة التي تعرض عنصرًا واحدًا فقط. لا يختلف هذا العنصر عن القائمة المنسدلة السابقة إلا في سمة size>1.

5.2.2.8. قائمة متعددة الاختيارات

liste à sélection multiple
<select multiple size="3" name="lstMultiple">
<option value="1" selected>multiple1</option>
<option value="2">multiple2</option>
<option value="3" selected>multiple3</option>
<option value="4">multiple4</option>
<option value="5">multiple5</option>
</select>

Image

balise HTML
<select size=".." name=".." multiple>
<option [selected] ] [value="valeur"]>...</option>
...
</select>
يعرض في قائمة النصوص الموجودة بين العلامات <option>...</option>
attributs
multiple: يسمح بتحديد عدة عناصر في القائمة. في المثال أعلاه، تم تحديد العنصرين liste1 و liste3.

5.2.2.9. زر من النوع button

bouton de type button
<input onclick="effacer()" type="button" value="Effacer" name="btnEffacer" />

Image

balise HTML
<input type="button" value="..." name="..." onclick="effacer()" ....>
attributs
type="button": يحدد عنصر تحكم زر. هناك نوعان آخران من الأزرار، وهما submit و reset.
value="حذف": النص المعروض على الزر
onclick="وظيفة()": يسمح بتعريف وظيفة يتم تنفيذها عندما ينقر المستخدم على الزر. هذه الوظيفة هي جزء من البرامج النصية المحددة في المستند الويب المعروض. الصيغة السابقة هي صيغة javascript. إذا كانت البرامج النصية مكتوبة بلغة vbscript، فيجب كتابة onclick="وظيفة" بدون الأقواس. تصبح الصيغة متطابقة إذا كان من الضروري تمرير معلمات إلى الدالة: onclick="dالة(val1, val2,...)"
في مثالنا، يؤدي النقر على الزر Effacer إلى استدعاء وظيفة جافا سكريبت effacer التالية:

        <script language="javascript">
        function effacer(){
            alert("Vous avez cliqué sur le bouton [Effacer]");
        }
        </script>
تعرض الدالة effacer رسالة:

5.2.2.10. زر من نوع submit

bouton de type submit
<input type="submit" value="إرسال" name="btnEnvoyer" />

Image

balise HTML
<input type="submit" value="إرسال" name="btnEnvoyer">
attributs
type="submit": يحدد الزر كزر لإرسال بيانات النموذج إلى خادم الويب. عندما ينقر العميل على هذا الزر، سيرسل المتصفح بيانات النموذج إلى URL المحددة في سمة action لعلامة <form> وفقًا للطريقة المحددة بواسطة سمة method لنفس العلامة.
value="إرسال": النص المعروض على الزر

5.2.2.11. زر من نوع reset

bouton de type reset
<input type="reset" value="إعادة الضبط" name="btnRetablir" runat="server" />

Image

balise HTML
<input type="reset" value="إعادة الضبط" name=" btnRetablir ">
attributs
type="reset": يحدد الزر كزر لإعادة تعيين النموذج. عندما ينقر العميل على هذا الزر، سيعيد المتصفح النموذج إلى الحالة التي استلمه بها.
value="إعادة تعيين": النص المعروض على الزر

5.2.2.12. حقل مخفي

champ caché
<input type="hidden" name="secret" value="uneValeur" />
balise HTML
<input type="hidden" name="..." value="...">
attributs
type="hidden": يحدد أن هذا حقل مخفي. الحقل المخفي جزء من النموذج ولكنه لا يظهر للمستخدم. ومع ذلك، إذا طلب المستخدم من متصفحه عرض شفرة المصدر، فسيرى وجود العلامة <input type="hidden" value="..."> وبالتالي قيمة الحقل المخفي.
value="uneValeur": قيمة الحقل المخفي.
ما فائدة الحقل المخفي؟ يمكن أن يسمح ذلك لخادم الويب بالاحتفاظ بالمعلومات خلال طلبات العميل. لنفترض تطبيقًا للتسوق عبر الويب. يشتري العميل منتجًا أول art1 بكمية q1 على الصفحة الأولى من الكتالوج ثم ينتقل إلى صفحة جديدة من الكتالوج. ولتذكر أن العميل اشترى q1 من المنتج art1، يمكن للخادم وضع هاتين المعلومتين في حقل مخفي في نموذج الويب الخاص بالصفحة الجديدة. في هذه الصفحة الجديدة، يشتري العميل المنتجين q2 و art2. عندما يتم إرسال بيانات هذا النموذج الثاني إلى الخادم (submit)، لن يتلقى الخادم المعلومات (q2،art2) فحسب، بل أيضًا (q1،art1) التي تشكل أيضًا جزءًا من النموذج كحقل مخفي لا يمكن للمستخدم تعديله. ثم سيضع خادم الويب المعلومات (q1,art1) و (q2,art2) في حقل مخفي جديد ويرسل صفحة جديدة من الكتالوج. وهكذا دواليك.

5.3. إرسال قيم نموذج إلى خادم ويب بواسطة متصفح

نعلم بالفعل، من الفصل السابق، كيف يقوم العميل بإرسال المعلومات إلى الخادم، ويقوم بذلك إما عن طريق:

  • طلب HTTP GET url?param1=va1&param2=val2&....
  • طلب HTT POST url متبوعًا بوثيقة تحتوي على سلسلة المعلمات param1=va1&param2=val2&....

سيستخدم المتصفح إحدى هاتين الطريقتين حسب ما إذا كان السمة [method] لعلامة [form] هي GET أو POST. وهذا ما سنوضحه الآن. الصفحة التي تمت دراستها سابقًا هي صفحة ثابتة. من أجل الوصول إلى الرؤوس HTTP المرسلة من المتصفح الذي سيطلب هذا المستند، نقوم بتحويلها إلى صفحة ديناميكية لخادم ويب .NET (IIS أو Cassini). يتم وضع الكود الثابت السابق في ملف [formulaire_get.aspx] ومحتواه كما يلي:


<%@ Page src="formulaire_get.aspx.vb" Language="vb" AutoEventWireup="false" Inherits="formulaire_get" %>
<html>
    <head>
        <title>Formulaire</title>
        <script language="javascript">
        function effacer(){
            alert("Vous avez cliqué sur le bouton [Effacer]");
        }
        </script>
    </head>
    <body>
.....
    </body>
</html>

ترتبط صفحة العرض أعلاه بوحدة التحكم [formulaire_get.aspx.vb]:


Public Class formulaire_get
    Inherits System.Web.UI.Page

    Private Sub Page_Init(ByVal Sender As Object, ByVal e As System.EventArgs) Handles MyBase.Init
        ' يتم حفظ الطلب الحالي في request.txt من مجلد الصفحة
        Dim requestFileName As String = Me.MapPath(Me.TemplateSourceDirectory) + "\request.txt"
        Me.Request.SaveAs(requestFileName, True)
    End Sub
End Class

عند كل استدعاء للوثيقة [formulaire_get.aspx]، سيتم حفظ طلب العميل في ملف [request.txt] بواسطة الإجراء Page_Init. لقد سبق أن تعاملنا مع طريقة العمل هذه، لذا لن نعلق أكثر على وحدة التحكم.

5.3.1. طريقة GET

لنقم بإجراء اختبار أولي، حيث يتم تعريف العلامة FORM في كود HTML للوثيقة على النحو التالي:


        <form name="formulaire" method="get">

نضع الملفين [formulaire_get.aspx] و [formulaire_get.aspx.vb] في مجلد <application-path> ونقوم بتشغيل خادم Cassini باستخدام المعلمات (<application-path>,/form2). نطلب عنوان URL http://localhost/form2/formulaire_get.aspx:

Image

قام المتصفح للتو بإرسال طلب ونعلم أن هذا الطلب قد تم تسجيله في الملف [request.txt]. لنلقِ نظرة على محتوى هذا الملف:

GET /form2/formulaire_get.aspx HTTP/1.1
Cache-Control: max-age=0
Connection: keep-alive
Keep-Alive: 300
Accept: application/x-shockwave-flash,text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,image/jpeg,image/gif;q=0.2,*/*;q=0.1
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Accept-Encoding: gzip,deflate
Accept-Language: en-us,en;q=0.5
Host: localhost
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7b) Gecko/20040316

استخدم المتصفح طلب HTTP GET لطلب عنوان URL [http://localhost/form2/formulaire_get.aspx]. ويحدث هذا دائمًا عندما يتم تقديم عنوان URL من قبل المستخدم. يتم ملء النموذج بالطريقة التالية:

Image

نستخدم الزر [Envoyer] أعلاه. رمزه HTML هو التالي:

<form method="get">
    ...
    <input type="submit" value="Envoyer">
    ...
</form>

عند تنشيط زر من النوع [Submit]، يرسل المتصفح معلمات النموذج (العلامة <form>) إلى URL المحددة في السمة [action] للعلامة <form action="URL"> إن وجدت. إذا لم يكن هذا السمة موجودًا، يتم إرسال معلمات النموذج إلى URL الذي أرسل النموذج. وهذا هو الحال هنا. لذلك، من المفترض أن يؤدي الزر [Envoyer] إلى إرسال طلب من المتصفح إلى URL [http://localhost/form2/formulaire_get.aspx] مع نقل معلمات النموذج. نظرًا لأن الصفحة [formulaire_get.aspx] تحتفظ بالطلب المستلم، يجب أن نعرف كيف قام العميل بنقل هذه المعلمات. لنجرب ذلك. نضغط على الزر [Envoyer]. نتلقى الرد التالي من المتصفح:

Image

هذه هي الصفحة الأولية، ولكن يمكننا ملاحظة أن URL قد تغير في حقل [Adresse] بالمتصفح. وأصبح كما يلي:

http://localhost/form2/formulaire_get.aspx?rdMarie=نعم&C1=واحد&C2=اثنان&txtSaisie=برمجة+asp.net&txtMdp=unMotDePasse&areaSaisie=أساسيات+البرمجة+الويب%0D%0Aprogrammation+web%0D%0A&cmbValeurs=3&lstSimple=1&lstMultiple=2&lstMultiple=4&btnEnvoyer=إرسال&secret=uneValeur

نلاحظ أن الاختيارات التي تمت في النموذج موجودة في URL. لنلقِ نظرة على محتوى الملف [request.txt] الذي سجل طلب العميل:

GET /form2/formulaire_get.aspx?rdMarie=oui&C1=un&C2=deux&txtSaisie=programmation+asp.net&txtMdp=ceciestsecre&areaSaisie=les+bases+de+la%0D%0Aprogrammation+web%0D%0A&cmbValeurs=3&lstSimple=1&lstMultiple=2&lstMultiple=4&btnEnvoyer=Envoyer&secret=uneValeur HTTP/1.1
Connection: keep-alive
Keep-Alive: 300
Accept: application/x-shockwave-flash,text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,image/jpeg,image/gif;q=0.2,*/*;q=0.1
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Accept-Encoding: gzip,deflate
Accept-Language: en-us,en;q=0.5
Host: localhost
Referer: http://localhost/form2/formulaire_get.aspx
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7b) Gecko/20040316

نجد طلبًا HTTP مشابهًا إلى حد كبير للطلب الذي قدمه المتصفح في البداية عندما طلب المستند دون إرسال أي معلمات. هناك اختلافان:

GET URL HTTP/1.1
تمت إضافة معلمات النموذج بعد URL الخاص بالوثيقة على النحو التالي: ?param1=val1&param2=val2&...
Referer
يُشير العميل من خلال هذا العنوان HTTP إلى URL الخاص بالوثيقة التي كان يعرضها عند إرسال الطلب

دعونا نلقي نظرة فاحصة على كيفية تمرير المعلمات في الأمر GET URL?param1=value1&param2=value2&... HTTP/1.1 حيث parami هي أسماء عناصر التحكم في نموذج الويب و valeuri هي القيم المرتبطة بها. نقدم أدناه جدولًا مكونًا من ثلاثة أعمدة:

  • العمود 1: يتضمن تعريف عنصر تحكم HTML من المثال
  • العمود 2: يعرض شكل هذا عنصر التحكم في المتصفح
  • العمود 3: يعرض القيمة التي يرسلها المتصفح إلى الخادم لعنصر التحكم في العمود 1 بالشكل الذي تظهر به في الاستعلام GET في المثال
عنصر التحكم HTML
العرض قبل التحقق من الصحة
القيمة (القيم) المرتجعة
<input type="radio" value="نعم" name="rdMarie" />نعم
<input type="radio" checked
value="لا" name="rdMarie" />لا
rdMarie=نعم
- قيمة السمة value للزر
الذي حدده المستخدم.
<input type="checkbox"
value="un" name="C1" />1
<input type="checkbox"
checked value="deux" name="C2" />2
<input type="checkbox"
value="ثلاثة" name="C3" />3
C1=واحد
C2=اثنان
- قيم سمات value للمربعات
التي حددها المستخدم
<input type="text" maxlength="30" value="بعض
كلمات" name="txtSaisie" />
txtSaisie=programmation+asp.net
- النص الذي يكتبه المستخدم في حقل
الإدخال. تم استبدال المسافات
بالعلامة +
<input type="password"
maxlength="12" size="12"
value="كلمة مرور"
name="txtMdp" />
txtMdp=هذا_سر
- النص الذي كتبه المستخدم في حقل
الإدخال. النص الذي تمت كتابته فعليًا هو
"هذا_سر". فقد
فقدان الحرف الأخير لأن السمة
maxlength="12" عدد
الأحرف بـ 12.
<textarea name="areaSaisie">
السطر 1
السطر 2</textarea>
areaSaisie=les+bases+de+
ال%0D%0A
البرمجة+الويب
- النص الذي يكتبه المستخدم في حقل
الإدخال. %OD%OA هي علامة
نهاية السطر. تم استبدال المسافات
بالعلامة +
<select name="cmbValeurs">
<option value="1">الخيار 1
</option>
<option value="2" selected>الخيار 2
</option>
<option value="3">الخيار 3
</option>
</select>
cmbValeurs=3
- القيمة التي اختارها المستخدم في
قائمة الاختيار الفردي
<select size="3"
name="lstSimple">
<option value="1"
selected>القائمة 1</option>
<option value="2">القائمة 2
</option>
<option value="3">القائمة 3
</option>
<option value="4">القائمة 4
</option>
<option value="5">القائمة 5
</option>
</select>
lstSimple=3
- القيمة التي اختارها المستخدم في
قائمة الاختيار الفردي
<select multiple size="3"
name="lstMultiple">
<option value="1" selected>multiple1
</option>
<option value="2">multiple2
</option>
<خيار القيمة="3" محدد>multiple3
</option>
<option value="4">multiple4
</option>
<option value="5">multiple5
</option>
</select>
lstMultiple=2
lstMultiple=4
- القيم التي اختارها المستخدم في
قائمة الاختيار المتعدد
<input type="submit"
value="إرسال"
name="btnEnvoyer" />
btnEnvoyer=إرسال
- اسم وسمة value للزر الذي
لإرسال بيانات النموذج
إلى الخادم
<input type="hidden"
name="secret"
value="uneValeur" />
 
secret=uneValeur
- سمة value للحقل المخفي

قد يتساءل المرء عما فعله الخادم بالمعلمات التي تم تمريرها إليه. في الواقع، لم يفعل شيئًا. عند استلام الأمر

GET /form2/formulaire_get.aspx?rdMarie=oui&C1=un&C2=deux&txtSaisie=programmation+asp.net&txtMdp=ceciestsecre&areaSaisie=les+bases+de+la%0D%0Aprogrammation+web%0D%0A&cmbValeurs=3&lstSimple=1&lstMultiple=2&lstMultiple=4&btnEnvoyer=Envoyer&secret=uneValeur HTTP/1.1

قام خادم الويب بنقل المعلمات إلى URL إلى المستند [http://localhost/form2/formulaire_get.aspxc.a.d. إلى المستند الذي أنشأناه في البداية. لم نكتب أي كود لاسترداد ومعالجة المعلمات التي يرسلها لنا العميل. لذا، يبدو الأمر كما لو أن طلب العميل كان ببساطة:

GET http://localhost/form2/formulaire_get.aspx

ولهذا السبب، استجابةً لزرنا [Envoyer]، حصلنا على نفس الصفحة التي حصلنا عليها في البداية عند طلب URL [http://localhost/form2/formulaire_get.aspx] بدون معلمات.

5.3.2. طريقة POST

تم الآن برمجة المستند HTML بحيث يستخدم المتصفح طريقة POST لإرسال قيم النموذج إلى خادم الويب. للقيام بذلك، نقوم بنسخ الملف [formulaire_get.aspx] إلى [formulaire_post.aspx] ونقوم بتعديل العلامة <form> فقط في [formulaire_post.aspx]:


<%@ Page src="formulaire_get.aspx.vb" Language="vb" AutoEventWireup="false" Inherits="formulaire_get" %>
<html>
    <head>
        ...
    </head>
    <body>
        <p>
            Gestion d'un formulaire
        </p>
        <hr />
        <form name="formulaire" method="post">
            <table border="1">

ليس هناك حاجة لتغيير وحدة التحكم [formulaire_get.aspx.vb]، لذا سنبقيها كما هي. نطلب المستند الجديد عبر URL [http://localhost/form2/formulaire_post.aspx]، ونملأ النموذج كما في طريقة GET ونرسل المعلمات إلى الخادم باستخدام الزر [Envoyer]. نحصل من الخادم على صفحة الرد التالية:

Image

وبالتالي نحصل على نفس النتيجة التي حصلنا عليها مع الطريقة GET، c.a.d. الصفحة الأولية. سنلاحظ اختلافًا: في حقل [Adresse] بالمتصفح، لا تظهر المعلمات المرسلة. الآن، لنلقِ نظرة على الطلب الذي أرسله العميل والذي تم تخزينه في الملف [request.txt]:

POST /form2/formulaire_post.aspx HTTP/1.1
Connection: keep-alive
Keep-Alive: 300
Content-Length: 222
Content-Type: application/x-www-form-urlencoded
Accept: application/x-shockwave-flash,text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,image/jpeg,image/gif;q=0.2,*/*;q=0.1
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Accept-Encoding: gzip,deflate
Accept-Language: en-us,en;q=0.5
Host: localhost
Referer: http://localhost/form2/formulaire_post.aspx
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7b) Gecko/20040316

rdMarie=oui&C1=un&C2=deux&txtSaisie=programmation+asp.net&txtMdp=ceciestsecre&areaSaisie=les+bases+de+la%0D%0Aprogrammation+web%0D%0A&cmbValeurs=3&lstSimple=3&lstMultiple=2&lstMultiple=4&btnEnvoyer=Envoyer&secret=uneValeur

تظهر مستجدات في استعلام العميل HTTP:

POST URL HTTP/1.1
استبدل الاستعلام GET باستعلام POST. لم تعد المعلمات موجودة في السطر الأول من الاستعلام. يمكن ملاحظة أنها أصبحت الآن موضوعة بعد الاستعلام HTTP بعد سطر فارغ. ترميزها مطابق للترميز الذي كانت عليه في الاستعلام GET.
Content-Length
عدد الأحرف "المرسلة"، c.a.d. عدد الأحرف التي سيتعين على خادم الويب قراءتها بعد استلام الرؤوس HTTP لاسترداد المستند الذي يرسله إليه العميل. المستند المعني هنا هو قائمة قيم النموذج.
Content-type
يحدد نوع المستند الذي سيرسله العميل بعد الرؤوس HTTP. يشير النوع [application/x-www-form-urlencoded] إلى أنه مستند يحتوي على قيم النموذج.

هناك طريقتان لنقل البيانات إلى خادم الويب: GET و POST. هل هناك طريقة أفضل من الأخرى؟ لقد رأينا أنه إذا تم إرسال قيم النموذج بواسطة المتصفح باستخدام الطريقة GET، فإن المتصفح يعرض في حقل Adresse الخاص به القيمة المطلوبة URL بالصيغة URL?param1=val1&param2=val2&.... يمكن اعتبار ذلك ميزة أو عيبًا:

  • ميزة إذا أردنا السماح للمستخدم بوضع هذا URL المُعد في قائمة الروابط المفضلة لديه
  • عيب إذا كنا لا نرغب في أن يتمكن المستخدم من الوصول إلى بعض المعلومات في النموذج، مثل الحقول المخفية على سبيل المثال

بعد ذلك، سنستخدم طريقة POST بشكل حصري تقريبًا في نماذجنا.

5.4. معالجة قيم النموذج من جانب الخادم

5.4.1. عرض المثال

الآن بعد أن ربطنا بين العلامة HTML <form method="GET/POST" ...> والطريقة التي يستخدمها المتصفح لإرسال قيم النموذج، أصبحنا نعرف كيفية استرداد هذه القيم من جانب الخادم. وقد أعطانا الفصل السابق الإجابة:

  • إذا كانت طريقة العلامة <form> هي GET، فسيتم استرداد قيم المعلمات في المجموعة [Request.QueryString]
  • إذا كانت طريقة العلامة <form> هي POST، فسيتم استرداد قيم المعلمات "المرسلة" في المجموعة [Request.Form]. يجب هنا توضيح نقطة ما. يمكن لعلامة <form> تحديد عنوان URL الهدف لـ GET أو POST باستخدام السمة [action]. يمكن ضبط عنوان URL هذا سواء كان لدينا GET أو POST، بالصيغة action="url?param1=val1&param2=val2&..". تُضاف هذه المعلمات إذن إلى تلك الموجودة بين العلامتين <form> و </form> والتي ستُحمل إلى الخادم باستخدام GET أو POST. ونظرًا لأنها جزء من عنوان URL الهدف، فسيتم الحصول عليها في المجموعة [Request.QueryString] سواء كنا نتعامل مع GET أو POST.

نكتب الآن تطبيق MVC ذو عرضين:

  • الطريقة الأولى هي النموذج السابق. سنسميها [vue_formulaire].
  • الطريقة الثانية هي صفحة معلومات تسرد القيم التي تم إدخالها في الصفحة الأولى. يتيح رابط العودة إلى النموذج. سنسمي هذه الطريقة [vue_confirmation].

يتم إرسال العرض [vue_formulaire] إلى المستخدم الذي يقوم بملئه والتحقق من صحته. قد يبدو كما يلي قبل التحقق من الصحة مباشرة:

Image

يستخدم المستخدم الزر [Envoyer] للتحقق من صحة إدخالاته. ويتلقى في المقابل العرض التالي [vue_validation]:

Image

5.4.2. وحدة التحكم في التطبيق

لقد رأينا في الفصل السابق أنه يمكننا أن نُعهد بدور وحدة التحكم في تطبيق MVC إلى الملف [global.asax] الذي تمر عبره جميع طلبات العملاء. لقد قدمنا بالفعل تطبيق MVC الذي تم إنشاؤه بهذه الطريقة، وسنتبع هنا نموذج التطوير الذي تم عرضه آنذاك. سيكون ملف [global.asax] كما يلي:

<%@ Application src="Global.asax.vb" Inherits="Global" %>

وهو يتكون من سطر واحد يشير إلى وحدة التحكم الموجودة في الملف [global.asax.vb]:


Imports System
Imports System.Web
Imports System.Web.SessionState

Public Class Global
    Inherits System.Web.HttpApplication

    Sub Application_BeginRequest(ByVal sender As Object, ByVal e As EventArgs)
        ' يتم استرداد الإجراء المطلوب
        Dim action As String
        If Request.QueryString("action") Is Nothing Then
            action = "init"
        Else
            action = Request.QueryString("action").ToString.ToLower
        End If
        ' يتم تنفيذ الإجراء
        Select Case action
            Case "init"
                Server.Transfer("formulaire.aspx", False)
            Case "validation"
                Server.Transfer("validation.aspx", True)
            Case Else
                Server.Transfer("formulaire.aspx", True)
        End Select
    End Sub
End Class

مبدأ عمل وحدة التحكم هو كما يلي:

  • ينتظر في عنوان URL الهدف سلسلة من المعلمات تحتوي على المعلمة [action]. إذا كانت هذه المعلمة غائبة، يتم التعامل مع الأمر كما لو كان لدينا [action=init] في سلسلة المعلمات.
  • يتم التعرف على إجراءين فقط:
    • init: يتم تسليم النموذج المملوء مسبقًا إلى العميل
    • validation: يتم تسليم الصفحة التي تؤكد الإدخالات التي قام بها العميل
  • إذا لم يكن الإجراء أحد الإجراءات السابقة، يتم التعامل مع الأمر كما لو كان لدينا [action=init]. يمكن أيضًا تقديم صفحة خطأ.

5.4.3. معالجة الإجراء init

عندما يعالج المتحكم الإجراء "init"، يجب عليه إنشاء نموذج مملوء مسبقًا. وتقع مسؤولية القيام بهذه المهمة على عاتق الصفحة [formulaire.aspx]. وفيما يلي شفرة البرمجة الخاصة بها:


<HTML>
    <HEAD>
        <title>Formulaire</title>
        <script language="javascript">
        function effacer(){
            alert("Vous avez cliqué sur le bouton [Effacer]");
        }
        function raz(liste){
            liste.selectedIndex=-1
        }
        </script>
    </HEAD>
    <body>
        <p>
            Gestion d'un formulaire
        </p>
        <hr>
        <form name="formulaire" method="post" action="?action=validation">
            <table border="1">
                <tr>
                    <td>
                        Etes-vous marié(e)</td>
                    <td>
                        <p align="center">
                            <input type="radio" value="oui" name="rdMarie">Oui <input type="radio" checked value="non" name="rdMarie">Non
                        </p>
                    </td>
                </tr>
....
                    <td>
                        <select size="3" name="lstSimple">
                            <option value="1" selected>liste1</option>
                            <option value="2">liste2</option>
                            <option value="3">liste3</option>
                            <option value="4">liste4</option>
                            <option value="5">liste5</option>
                        </select>
                        <INPUT type="button" value="Raz" name="btnRazSimple" onclick="raz(lstSimple)">
                    </td>
....
                    <td>
                        <select multiple size="3" name="lstMultiple">
                            <option value="1" selected>multiple1</option>
                            <option value="2">multiple2</option>
                            <option value="3" selected>multiple3</option>
                            <option value="4">multiple4</option>
                            <option value="5">multiple5</option>
                        </select>
                        <INPUT type="button" value="Raz" name="btnRazMultiple" onclick="raz(lstMultiple)">
                    </td>
...

            </table>
            <input type="hidden" name="secret" value="uneValeur">
        </form>
    </body>
</HTML>

نجد الرمز HTML من النموذج الذي تمت دراسته سابقًا مع بعض الاختلافات الطفيفة. تم تعديل رمز العلامة <form>:


        <form name="formulaire" method="post" action="?action=validation">
  • post: القيم التي يدخلها المستخدم ثم ترسل إلى الخادم عند استخدام الزر من النوع [submit] ستُستخدم بواسطة الطريقة HTTP POST
  • الإجراء: تُستخدم صيغة action="url" لتحديد عنوان URL الذي يجب إرسال قيم النموذج إليه. قد يتضمن عنوان URL هذا سلسلة من المعلمات بالصيغة param1=val1&param2=val2&... وهذا ما يتم هنا حيث نمرر المعلمة [action=validation] لإرشاد وحدة التحكم إلى الإجراء الذي يجب أن تتخذه. تجدر الإشارة إلى أن سلسلة المعلمات هذه لا يسبقها عنوان ويب. سيقوم المتصفح عندئذ بإرسال معلمات النموذج إلى العنوان الذي قدم له هذا النموذج. في المثال المقدم أعلاه، هذا العنوان هو [http://localhost/mvcform1]. سيقوم المتصفح إذن بإرسال طلب [POST /mvcform1?action=validation] إلى الجهاز [localhost].

تمت إضافة أزرار لتمكين المستخدم من إلغاء تحديد العناصر في القوائم [lstSimple] و [lstMultiple]:

Image

وينتج عن ذلك الكود HTML التالي:


                    <td>
                        <select size="3" name="lstSimple">
                            <option value="1" selected>liste1</option>
                            <option value="2">liste2</option>
                            <option value="3">liste3</option>
                            <option value="4">liste4</option>
                            <option value="5">liste5</option>
                        </select>
                        <INPUT type="button" value="Raz" name="btnRazSimple" onclick="raz(lstSimple)">
                    </td>
....
                    <td>
                        <select multiple size="3" name="lstMultiple">
                            <option value="1" selected>multiple1</option>
                            <option value="2">multiple2</option>
                            <option value="3" selected>multiple3</option>
                            <option value="4">multiple4</option>
                            <option value="5">multiple5</option>
                        </select>
                        <INPUT type="button" value="Raz" name="btnRazMultiple" onclick="raz(lstMultiple)">
                    </td>

يؤدي النقر على زر [Raz] إلى إلغاء تحديد جميع العناصر في القائمة المرتبطة به. لنأخذ قائمة [lstMultiple] كمثال. يؤدي النقر على الزر [Raz] المقابل إلى تنفيذ وظيفة جافا سكريبت [raz(lstMultiple)]. تجدر الإشارة إلى أن كود جافا سكريبت الخاص بوثيقة HTML المعروضة بواسطة متصفح يتم تنفيذه بواسطة هذا المتصفح نفسه وليس بواسطة الخادم. جافا سكريبت هي لغة شاملة للغاية تسمح بإضفاء مظهر ديناميكي على الصفحات دون تدخل من الخادم. وظيفة [raz] هي كما يلي:

        function raz(liste){
            liste.selectedIndex=-1
        }

تستقبل هذه الوظيفة معلمةً هي كائن جافا سكريبت يمثل قائمة HTML. يحتوي هذا الكائن على خصائص وأساليب. إحدى خصائصه هي [selectedIndex] التي تكون قيمتها رقم الخيار الأول المحدد في القائمة HTML. إذا لم يكن هناك أي خيار، فإن قيمة هذه الخاصية تساوي -1. وبالمقابل، فإن تعيين قيمة لهذه الخاصية يعادل تحديد عنصر جديد في القائمة HTML، وإعطائها القيمة -1 يعادل عدم تحديد أي عنصر. وهذا ما يتم هنا.

وأخيرًا، نلاحظ أن كود العرض [formulaire.aspx] لا يرافقه وحدة تحكم [formulaire.aspx.vb]. في الواقع، لا يوجد أي جزء ديناميكي تم إنشاؤه بواسطة الخادم في المستند HTML، وبالتالي لا توجد حاجة لوحدة تحكم.

5.4.4. معالجة إجراء التحقق من الصحة

عندما يعالج وحدة التحكم إجراء "التحقق من الصحة"، يجب أن يولد صفحة تسرد القيم التي أدخلها المستخدم. وتقع مسؤولية القيام بهذه المهمة على عاتق الصفحة [validation.aspx]. وتظهر الصفحة بصريًا على النحو التالي:

Image

ورمزها HTML هو كما يلي:


<%@ Page src="validation.aspx.vb" Language="vb" AutoEventWireup="false" Inherits="validation" %>
<HTML>
    <HEAD>
        <title>validation</title>
    </HEAD>
    <body>
        <P>Valeurs saisies</P>
        <HR width="100%" SIZE="1">
        <TABLE id="Table1" cellSpacing="1" cellPadding="1" width="300" border="1">
            <TR>
                <TD width="84">rdMarie</TD>
                <TD><% =rdMarie%></TD>
            </TR>
            <TR>
                <TD width="84">C1</TD>
                <TD><%=C1%></TD>
            </TR>
            <TR>
                <TD width="84">C2</TD>
                <TD><%=C2%></TD>
            </TR>
            <TR>
                <TD width="84">C3</TD>
                <TD><%=C3%></TD>
            </TR>
            <TR>
                <TD width="84">txtSaisie</TD>
                <TD><%=txtSaisie%></TD>
            </TR>
            <TR>
                <TD width="84">txtMdp</TD>
                <TD><%=txtMdp%></TD>
            </TR>
            <TR>
                <TD width="84">areaSaisie</TD>
                <TD><%=areaSaisie%></TD>
            </TR>
            <TR>
                <TD width="84">cmbValeurs</TD>
                <TD><%=cmbValeurs%></TD>
            </TR>
            <TR>
                <TD width="84">lstSimple</TD>
                <TD><%=lstSimple%></TD>
            </TR>
            <TR>
                <TD width="84">lstMultiple</TD>
                <TD><%=lstMultiple%></TD>
            </TR>
            <TR>
                <TD width="84">secret</TD>
                <TD><%=secret%></TD>
            </TR>
        </TABLE>
    </body>
</HTML>

يتم حساب الأجزاء الديناميكية <%=variable%> من المستند بواسطة وحدة التحكم [validation.aspx.vb] المرتبطة:


Imports System.Text.RegularExpressions

Public Class validation
    Inherits System.Web.UI.Page

    Protected rdMarie As String
    Protected C1 As String
    Protected C2 As String
    Protected C3 As String
    Protected txtSaisie As String
    Protected txtMdp As String
    Protected areaSaisie As String
    Protected cmbValeurs As String
    Protected lstSimple As String
    Protected lstMultiple As String
    Protected secret As String
    Protected delimiteur As New Regex("\r\n")

    Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        'يتم استرداد المعلمات المرسلة
        rdMarie = getValue("rdMarie")
        C1 = getValue("C1")
        C2 = getValue("C2")
        C3 = getValue("C3")
        txtSaisie = getValue("txtSaisie")
        txtMdp = getValue("txtMdp")
        areaSaisie = String.Join(",", delimiteur.Split(getValue("areaSaisie")))
        cmbValeurs = getValue("cmbValeurs")
        lstSimple = getValue("lstSimple")
        lstMultiple = getValue("lstMultiple")
        secret = getValue("secret")
    End Sub

    Private Function getValue(ByVal champ As String) As String
        ' يسترد قيمة الحقل [champ] من الطلب المرسل
        ' شيء ما؟
        If Request.Form(champ) Is Nothing Then Return ""
        ' يتم استرداد قيمة أو قيم الحقل
        Dim valeurs() As String = Request.Form.GetValues(champ)
        Dim valeur As String = ""
        Dim i As Integer
        For i = 0 To valeurs.Length - 1
            valeur += "[" + valeurs(i) + "]"
        Next
        Return valeur
    End Function

End Class

يتم حساب القيم المراد عرضها في الإجراء [Form_Load]. يتم الحصول على قيمة حقل "منشور" من خلال الدالة getValue(C) حيث C هو اسم الحقل. النقاط الرئيسية لهذه الدالة هي التالية:

  • إذا لم يكن C موجودًا في سلسلة المعلمات المنشورة، يتم إرجاع السلسلة فارغة كقيمة لـ C
  • وإلا يتم الحصول على جدول قيم الحقل C بواسطة [Request.Form.GetValues(C). ويتم ربط هذه القيم في سلسلة أحرف بالشكل [val1][val2]...[valn] حيث [vali] هي القيمة رقم i للحقل C

يتم معالجة الحقل [areaSaisie] بطريقة خاصة. يتم إرسال قيمته بواسطة المتصفح في شكل areaSaisie=سطر1\r\nسطر2\r\n... حيث \r هو الحرف ذو الرمز ASCII 13 (رجوع عربة) و\n هو الحرف ذو الرمز ASCII 10 (انتقال سطر). وبالتالي، فإن الدالة getValue(areaSaisie) هي السلسلة "السطر1\r\nالسطر2\r\n...". يتم تقسيم هذه السلسلة إلى أسطر بواسطة الطريقة [Regex.Split]. وبذلك نحصل على مصفوفة من السلاسل {السطر1،السطر2،...}. يتم تحويل هذه المصفوفة إلى سلسلة "السطر1،السطر2،..." بواسطة الطريقة [String.Join]. وهذه السلسلة الأخيرة هي التي سيتم عرضها كقيمة للحقل [areaSaisie]. كان الهدف هنا هو إظهار كيفية الحصول على الأسطر المختلفة لحقل HTML من النوع [TextArea].

5.4.5. الاختبارات

نضع جميع الملفات (global.asax، global.asax.vb، formulaire.aspx، validation.aspx، validation.aspx.vb) في مجلد <application-path>. نقوم بتشغيل خادم Cassini باستخدام المعلمات (<application-path>،/mvcform1). نقوم بإنشاء ملف فارغ باسم [default.aspx] في المجلد <application-path> ثم نطلب عنوان URL [http://localhost/mvcform1]. نظرًا لأن [/mvcform1] هو المسار الافتراضي لمجلد وليس لمستند، فسيعرض خادم الويب المستند [default.aspx] إذا كان موجودًا. ولهذا السبب قمنا بإنشائه. قبل عرضه، سيتم تنفيذ البرنامج النصي [global.asax]، مما سيؤدي في النهاية إلى عرض الصفحة [formulaire.aspx]. ولهذا السبب يمكن أن يكون الملف [default.aspx] فارغًا.

لنفترض أن النموذج الذي تم التحقق من صحته هو التالي:

Image

يؤدي استخدام الزر [Envoyer] إلى عرض الصفحة التالية:

Image

لنلاحظ أولاً عنوان URL الخاص بالاستجابة: [http://localhost/mvcform1/?action=validation]. إنه URL الخاص بالسمة [action] لعلامة <form> في النموذج [formulaire.aspx]:


        <form name="formulaire" method="post" action="?action=validation">

دعونا ندرس واحدة تلو الأخرى القيم التي تم الحصول عليها لمختلف حقول النموذج:

الحقل
القيمة
HTML
تعليقات
rdMarie
نعم
<input type="radio" value="نعم"
name="rdMarie">نعم
<input type="radio" checked
value="لا" name="rdMarie">لا
القيمة التي تم الحصول عليها هي السمة [value] للزر المحدد
C1
واحد
<input type="checkbox"
value="un" name="C1">1
نفس الشيء
C2
اثنان
<input type="checkbox"
checked value="اثنان" name="C2">2
نفس الشيء
C3
 
<input type="checkbox"
value="ثلاثة" name="C3">3
لم يتم تحديد هذا الزر من قبل المستخدم. وبالتالي لم يتم إرسال قيمته من قبل المتصفح. في الكود، كانت الشرط [Request.Form("C3") is Nothing] صحيحة.
txtSaisie
البرمجة
asp.net
<input type="text"
... name="txtSaisie">
القيمة التي يتم الحصول عليها هي النص الموجود في حقل الإدخال عند التحقق من الصحة
txtMdp
mdp
<input type="password"
...name="txtMdp">
نفس الشيء
areaSaisie
أساسيات
البرمجة على الويب
<textarea name="areaSaisie">
...</textarea>
نفس الشيء
cmbValeurs
3
<select name="cmbValeurs">
...
<option value="3">الخيار 3</option>
</select>
القيمة التي تم الحصول عليها هي السمة [value] للخيار المحدد
lstSimple
3
<select size="3" name="lstSimple">
....
<option value="3">قائمة 3</option>
...
</select>
نفس الشيء
lstMultiple
2 4
<select multiple size="3" name="lstMultiple">
...
<option value="2">multiple2
</option>
...
<option value="4">multiple4
</option>
...
</select>
القيم التي تم الحصول عليها هي قيم سمات [value] للخيارات المحددة
secret
uneValeur
<input type="hidden"
name="secret" value="uneValeur">
القيمة التي تم الحصول عليها هي السمة [value] للحقل المخفي

الآن لننتقل إلى القوائم. لنفترض أن حالة النموذج عند التحقق من الصحة هي كما يلي:

Image

  • تم تحديد الخيار [choix1] في comboBox
  • ولم يتم تحديد أي خيار في القائمتين الأخريين. وقد استخدمنا الأزرار [Raz] لتحقيق ذلك.

فيما يلي الصفحة التي تم إرجاعها بعد التحقق من الصحة:

Image

عندما لا يتم تحديد أي قيمة في قائمة ما، لا يرسل المتصفح أي معلمة لها. في كود [validation.aspx.vb]، فإن التعبيرات [Request.Form("lstSimple")] و [Request.Form("lstMultiple")] تساوي الثابت [Nothing]، ومن هنا جاءت النتيجة المعروضة أعلاه.

5.5. الحفاظ على حالة الصفحة

5.5.1. الحفاظ على حالة الصفحة باستخدام جلسة عمل

نقوم بنسخ التطبيق السابق بالكامل إلى مجلد جديد. نضيف رابطًا في الصفحة [validation.aspx] يتيح للمستخدم العودة إلى النموذج:

Image

التعديل المطلوب إجراؤه على الصفحة [validation.aspx] هو إضافة الرابط:


.....
            <TR>
                <TD width="84">secret</TD>
                <TD><%=secret%></TD>
            </TR>
        </TABLE>
        <P>
            <a href="?action=formulaire">Retour au formulaire</a>
        </P>
    </body>
</HTML>

تحتوي السمة [href] للرابط على عنوان URL معلمة مع المعلمة الوحيدة [action=formulaire]، مما يسمح للخادم بمعرفة أنه يجب عليه عرض النموذج كما كان عند التحقق من صحته. وبالتالي، هناك فرق مع الإجراء [init] الذي يعرض نموذجًا محددًا مسبقًا. لا يحتوي عنوان URL المُعَرَّف [?action=formulaire] في الواقع على عنوان URL. وبالتالي، سيكون هذا العنوان هو نفسه الذي سمح بعرض صفحة التحقق. إذا تذكرنا الدراسة السابقة، فإن هذا هو عنوان URL لمجلد التطبيق. وبالتالي، ستمر الطلب عبر وحدة التحكم. ويجب على هذه الوحدة الآن معالجة الإجراء [formulaire]. يتم تعديل كود [global.asax.vb] على النحو التالي:


    Sub Application_BeginRequest(ByVal sender As Object, ByVal e As EventArgs)
        ' يتم استرداد الإجراء المطلوب
        Dim action As String
        If Request.QueryString("action") Is Nothing Then
            action = "init"
        Else
            action = Request.QueryString("action").ToString.ToLower
        End If
        ' يتم تنفيذ الإجراء
        Select Case action
            Case "init"
                Server.Transfer("formulaire.aspx", False)
            Case "validation"
                Server.Transfer("validation.aspx", True)
            Case "formulaire"
                Server.Transfer("formulaire.aspx", True)
            Case Else
                Server.Transfer("formulaire.aspx", True)
        End Select
    End Sub

في حالة ما إذا كانت الإجراء هو "نموذج"، فإننا نكتفي بتمرير الطلب إلى الصفحة [formulaire.aspx]. ونعلم أن هذه الصفحة تعرض نموذجًا محددًا مسبقًا لا يحتوي على أي أجزاء متغيرة. وبالتالي، لا يمكن لهذه الصفحة عرض النموذج بالقيم التي كان يحتوي عليها عند التحقق من صحته. نسعى هنا إلى توضيح هذه النقطة. إذا تم وضع جميع ملفات التطبيق في <application-path>، فإننا نطلق Cassini بالمعلمات (<application-path>,/mvcform2) ثم نطلب عنوان URL [http://localhost/mvcform2]. نحصل على الصفحة التالية (عرض جزئي):

Image

نملأ النموذج بالطريقة التالية ثم نؤكده:

Image

نحصل على صفحة التأكيد التالية:

Image

نستخدم الرابط [Retour au formulaire] الموجود (ولكن غير معروض) في الصفحة أعلاه. نحصل على الرد التالي من الخادم:

Image

نلاحظ أن:

  • أن عنوان URL المطلوب يحتوي بالفعل على المعلمة action=formulaire كما كان مطلوبًا
  • أن النموذج المعروض قد فقد القيم التي تم إدخالها.

نحن نعرف سبب عدم ظهور القيم التي تم إدخالها. إذا نظرنا إلى كود المستند [formulaire.aspx]، نلاحظ أن كل شيء ثابت وأنه مضطر بالتالي إلى عرض نفس الصفحة في كل مرة. من الواضح أننا بحاجة إلى جعل هذا الكود ديناميكيًا. يجب أن يعرض القيم التي أقرها المستخدم. ولكن أين نخزن هذه القيم؟

لنتذكر القاعدة الحديدية لبروتوكول HTTP الذي لا يعتمد على الحالة:

  • يتم طلب عنوان URL [http://localhost/mvcform2] - يتم تلقي استجابة. تم فتح اتصال TCP-IP بين العميل والخادم في بداية الطلب وانتهى في نهاية الاستجابة.
  • يقوم المستخدم بإدخال البيانات ثم تأكيدها. يتم طلب عنوان URL [http://localhost/mvcform2/?action=validation] - يتم تلقي استجابة. تم فتح اتصال جديد TCP-IP ثم إغلاقه بين الطرفين.
  • يستخدم المستخدم الرابط [Retour au formulaire]. يتم طلب عنوان URL [http://localhost/mvcform2/?action=formulaire] - ويتم تلقي استجابة. تم فتح اتصال جديد TCP-IP مرة أخرى ثم إغلاقه بين الشريكين.

دورات الطلب والاستجابة مستقلة عن بعضها البعض لأن كل منها يستخدم اتصالاً جديداً TCP-IP. عندما يستخدم تطبيق عميل-خادم اتصالاً واحداً TCP-IP لسلسلة من التبادلات، يمكن للخادم تحديد هوية العميل عبر اتصاله. وبالتالي يمكنه تخزين المعلومات التي سيربطها باتصال محدد، وبذلك يتتبع التبادلات. عندما تتم التبادلات عبر اتصالات مختلفة، لا يمكن للخادم تحديد هوية العميل في اتصال معين. يلزم وجود وسيلة أخرى. وقد عرضنا إحداها في الفصل السابق: آلية الجلسة. فهي تسمح لدورات الطلب والاستجابة بتخزين المعلومات في كائن [Session] يمكن الوصول إليه من قبل جميع الدورات المتتالية.

الآن بعد أن أصبح لدينا تطبيق MVC مع جلسة عمل، لم يعد بإمكاننا استخدام الملف [global.asax] كوحدة تحكم كما تم توضيحه في الفصل السابق. يجب أن تؤدي صفحة معينة مخصصة لهذا الغرض دور وحدة التحكم في التطبيق. هنا، ستكون هذه الصفحة هي [main.aspx]. وسنقوم بما يلي:

  • عندما يقوم المستخدم بالتحقق من صحة بياناته (action=validation)، سيقوم وحدة التحكم [main.aspx.vb] بتخزينها في الجلسة الحالية قبل عرض صفحة التحقق من الصحة.
  • عندما يتعين عرض النموذج مع القيم التي تم إدخالها (action=formulaire)، سيسترد وحدة التحكم [main.aspx.vb] هذه القيم من الجلسة ويضعها في السياق قبل عرض النموذج.

5.5.2. وحدة التحكم الجديدة في التطبيق

يتكون وحدة التحكم في التطبيق من ملفين [main.aspx, main.aspx.vb]:

[main.aspx]

<%@ Page src="main.aspx.vb" Language="vb" AutoEventWireup="false" Inherits="main" %>

[main.aspx.vb]


Imports System.Collections.Specialized
Imports Microsoft.VisualBasic

Public Class main
    Inherits System.Web.UI.Page

    Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        ' يتم استرداد الإجراء المطلوب
        Dim action As String
        If Request.QueryString("action") Is Nothing Then
            action = "init"
        Else
            action = Request.QueryString("action").ToString.ToLower
        End If
        ' يتم تنفيذ الإجراء
        Select Case action
            Case "init"
                ' يتم عرض النموذج المملوء مسبقًا
                Context.Items("formulaire") = initForm()
                Server.Transfer("formulaire.aspx", True)
            Case "validation"
                ' يتم عرض صفحة التأكيد بعد تسجيل القيم المرسلة في الجلسة
                Session.Item("formulaire") = Request.Form
                Server.Transfer("validation.aspx", True)
            Case "formulaire"
                ' يتم عرض النموذج مع القيم المأخوذة من الجلسة
                Context.Items("formulaire") = Session.Item("formulaire")
                Server.Transfer("formulaire.aspx", True)
            Case Else
                ' يتم عرض النموذج المملوء مسبقًا
                Context.Items("formulaire") = initForm()
                Server.Transfer("formulaire.aspx", True)
        End Select
    End Sub

    Private Function initForm() As NameValueCollection
        ' يتم تهيئة النموذج
        Dim form As New NameValueCollection
        form.Set("rdMarie", "non")
        form.Set("C2", "deux")
        form.Set("txtSaisie", "qqs mots")
        form.Set("txtMdp", "ceciestsecret")
        form.Set("areasaisie", "ligne1" + ControlChars.CrLf + "ligne2" + ControlChars.CrLf)
        form.Set("cmbValeurs", "2")
        form.Set("lstSimple", "1")
        form.Set("lstMultiple", "1")
        form.Add("lstMultiple", "3")
        Return form
    End Function
End Class

نجد جوهر بنية وحدة التحكم في التطبيق التي تمت دراستها سابقًا مع الاختلافات التالية:

  • يتم عمل وحدة التحكم في الإجراء [Form_Load]
  • في حالة الإجراء [validation]، يتم تخزين قيم النموذج الموجودة في [Request.Form] في الجلسة المرتبطة بالمفتاح "نموذج". بعد ذلك، يتم نقل التنفيذ إلى الصفحة [validation.aspx] التي ستعرض هذه القيم.
  • بالنسبة للإجراءات الأخرى، يتم نقل التنفيذ في جميع الحالات إلى الصفحة [formulaire.aspx]. تنتظر هذه الصفحة في سياقها مفتاح "نموذج" سيتم ربطه بكائن من النوع [Request.form] c.a.d. من النوع [NameValueCollection]. يجب أن يحتوي هذا الكائن على مجموعة قيم حقول النموذج.
  • في حالة ما إذا كانت الإجراء هو [init] أو إجراء غير معروف، يتم إنشاء مجموعة القيم بشكل تعسفي بواسطة الدالة [initForm].
  • في حالة ما إذا كانت الإجراء هي [formulaire]، فإن هذه المجموعة هي المجموعة [Request.Form] التي تم وضعها في الجلسة بواسطة الإجراء [validation]

5.5.3. النموذج الجديد

نظرًا لأن التطبيق لم يعد يعرض نفس المحتوى في النموذج، يجب إنشاء هذا النموذج ديناميكيًا. تصبح الصفحة الجديدة [formulaire.aspx] كما يلي:


<%@ Page src="formulaire.aspx.vb" Language="vb" AutoEventWireup="false" Inherits="formulaire" %>
<HTML>
    <HEAD>
        <title>Formulaire</title>
        <script language="javascript">
        function effacer(){
            alert("Vous avez cliqué sur le bouton [Effacer]");
        }
        function raz(liste){
            liste.selectedIndex=-1
        }
        </script>
    </HEAD>
    <body>
        <p>
            Gestion d'un formulaire
        </p>
        <hr>
        <form name="formulaire" method="post" action="main.aspx?action=validation">
            <table border="1">
                <tr>
                    <td>
                        Etes-vous marié(e)</td>
                    <td>
                        <p align="center">
                            <INPUT type="radio" value="oui" name="rdMarie" <%=rdouichecked%>>Oui
                         <INPUT type="radio" value="non" name="rdMarie" <%=rdnonchecked%>>Non
                        </p>
                    </td>
                </tr>
                <TR>
                    <TD>Cases à cocher
                    </TD>
                    <TD>
                        <P align="center">
                            <INPUT type="checkbox" value="un" name="C1" <%=c1checked%>>1
                             <INPUT type="checkbox" value="deux" name="C2" <%=c2checked%>>2
                            <INPUT type="checkbox" value="trois" name="C3" <%=c3checked%>>3
                        </P>
                    </TD>
                </TR>
                <TR>
                    <TD>Champ de saisie</TD>
                    <TD>
                        <P align="center">
                            <INPUT type="text" maxLength="30" value="<%=txtSaisie%>" name="txtSaisie">
                        </P>
                    </TD>
                </TR>
                <tr>
                    <td>
                        Mot de passe</td>
                    <td>
                        <p align="center">
                            <input type="password" maxlength="12" size="12" value="<%=txtMdp%>" name="txtMdp">
                        </p>
                    </td>
                </tr>
                <tr>
                    <td>
                        Boîte de saisie</td>
                    <td>
                        <textarea name="areaSaisie"><%=areaSaisie%></textarea>
                    </td>
                </tr>
                <tr>
                    <td>
                        ComboBox</td>
                    <td>
                        <select name="cmbValeurs">
                            <%=cmbValeursOptions%>
                        </select>
                    </td>
                </tr>
                <tr>
                    <td>
                        Liste à choix simple</td>
                    <td>
                        <select size="3" name="lstSimple">
                            <%=lstSimpleOptions%>
                        </select>
                        <INPUT type="button" value="Raz" name="btnRazSimple" onclick="raz(lstSimple)">
                    </td>
                </tr>
                <tr>
                    <td>
                        Liste à choix multiple</td>
                    <td>
                        <select multiple size="3" name="lstMultiple">
                            <%=lstMultipleOptions%>
                        </select>
                        <INPUT type="button" value="Raz" name="btnRazMultiple" onclick="raz(lstMultiple)">
                    </td>
                </tr>
                <tr>
                    <td>
                        Bouton simple</td>
                    <td>
                        <p align="center">
                            <input onclick="effacer()" type="button" value="Effacer" name="btnEffacer">
                        </p>
                    </td>
                </tr>
                <tr>
                    <td>
                        Bouton submit</td>
                    <td>
                        <p align="center">
                            <input type="submit" value="Envoyer" name="btnEnvoyer">
                        </p>
                    </td>
                </tr>
                <tr>
                    <td>
                        Bouton reset</td>
                    <td>
                        <p align="center">
                            <input type="reset" value="Rétablir" name="btnRetablir" runat="server">
                        </p>
                    </td>
                </tr>
            </table>
            <input type="hidden" name="secret" value="uneValeur">
        </form>
    </body>
</HTML>

دعونا نعلق على المتغيرات الديناميكية التي تظهر في الكود HTML:

المتغير
الدور
rdouichecked
ستكون قيمتها "checked" إذا كان يجب تحديد زر الاختيار [oui]، وإلا فستكون قيمتها ""
rdnonchecked
نفس الشيء بالنسبة لزر الاختيار [non]
c1checked
نفس الشيء بالنسبة لمربع الاختيار [C1]
c2checked
نفس الشيء بالنسبة لمربع الاختيار [C2]
c3checked
وينطبق الأمر نفسه على خانة الاختيار [C3]
txtSaisie
النص المراد وضعه في الحقل [txtSaisie]
txtMdp
النص المراد وضعه في الحقل [txtMdp]
areaSaisie
النص المراد وضعه في الحقل [areaSaisie]
cmbValeursOptions
النص HTML خيارات قائمة الاختيار [cmbValeurs]
lstSimpleOptions
النص HTML من خيارات قائمة الاختيار [lstSimple]
lstMultipleOptions
النص HTML من خيارات قائمة الاختيار [lstMultiple]
  

يتم حساب قيم هذه المتغيرات بواسطة وحدة التحكم في الصفحة [formulaire.aspx.vb]:


Imports Microsoft.VisualBasic
Imports System.Collections.Specialized

Public Class formulaire
    Inherits System.Web.UI.Page

    ' الحقول الثابتة في النموذج
    Private libellésCmbValeurs() As String = {"choix1", "choix2", "choix3"}
    Private valeursCmbValeurs() As String = {"1", "2", "3"}
    Private libellésLstSimple() As String = {"liste1", "liste2", "liste3"}
    Private valeursLstSimple() As String = {"1", "2", "3"}
    Private libellésLstMultiple() As String = {"multiple1", "multiple2", "multiple3", "multiple4", "multiple5"}
    Private valeursLstMultiple() As String = {"1", "2", "3", "4", "5"}

    ' الحقول الديناميكية للنموذج
    Protected rdouichecked As String
    Protected rdnonchecked As String
    Protected c1checked As String
    Protected c2checked As String
    Protected c3checked As String
    Protected txtSaisie As String
    Protected txtMdp As String
    Protected areaSaisie As String
    Protected cmbValeursOptions As String
    Protected lstSimpleOptions As String
    Protected lstMultipleOptions As String

    Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        ' يتم استرداد الطلب السابق في الجلسة
        Dim form As NameValueCollection
        If Not Context.Items("formulaire") Is Nothing Then
            form = Context.Items("formulaire")
        Else
            form = New NameValueCollection
        End If
        ' يتم تجهيز الصفحة للعرض
        ' أزرار الاختيار
        rdouichecked = ""
        rdnonchecked = "checked"
        If isEqual(form("rdMarie"), "oui") Then
            rdouichecked = "checked"
            rdnonchecked = ""
        End If
        ' مربعات الاختيار
        c1checked = ""
        If isEqual(form("C1"), "un") Then c1checked = "checked"
        c2checked = ""
        If isEqual(form("C2"), "deux") Then c2checked = "checked"
        c3checked = ""
        If isEqual(form("C3"), "trois") Then c3checked = "checked"
        ' حقول الإدخال
        txtSaisie = ""
        If Not form("txtSaisie") Is Nothing Then txtSaisie = form("txtSaisie").ToString
        txtMdp = ""
        If Not form("txtMdp") Is Nothing Then txtMdp = form("txtMdp").ToString
        areaSaisie = ""
        If Not form("areaSaisie") Is Nothing Then areaSaisie = form("areaSaisie").ToString
        ' القوائم
        Dim sélections() As String = {}
        If Not form("cmbValeurs") Is Nothing Then sélections = form.GetValues("cmbValeurs")
        cmbValeursOptions = getOptions(valeursCmbValeurs, libellésCmbValeurs, sélections)
        sélections = New String() {}
        If Not form("lstSimple") Is Nothing Then sélections = form.GetValues("lstSimple")
        lstSimpleOptions = getOptions(valeursLstSimple, libellésLstSimple, sélections)
        sélections = New String() {}
        If Not form("lstMultiple") Is Nothing Then sélections = form.GetValues("lstMultiple")
        lstMultipleOptions = getOptions(valeursLstMultiple, libellésLstMultiple, sélections)
    End Sub

    Private Function getOptions(ByRef valeurs() As String, ByRef libelles() As String, ByRef sélections() As String) As String
        ' يعرض كود HTML لخيارات علامة <select>
        ' القيم: جدول قيم خيارات العلامة
        ' التسميات: جدول تسميات خيارات العلامة
        ' التحديدات: الخيارات المطلوب تحديدها
        Dim iValeur As Integer
        Dim iSelection As Integer
        Dim selected As String
        Dim toString As String = ""
        ' يتم تصفح قائمة قيم الخيارات
        For iValeur = 0 To valeurs.Length - 1
            ' التحقق مما إذا كان يجب تحديد القيمة الحالية
            selected = "" : iSelection = 0
            Do While iSelection < sélections.Length And selected = ""
                If valeurs(iValeur) = sélections(iSelection) Then selected = "selected"
                iSelection += 1
            Loop
            ' يتم تضمين رمز HTML الخاص بالخيار
            toString += "<option " + selected + " value='" + valeurs(iValeur) + "'> " _
            + libelles(iValeur) + "</option>" + ControlChars.CrLf
        Next
        ' نقوم بإرجاع النتيجة
        Return toString
    End Function

    Private Function isEqual(Byval champ As Object, ByVal valeur As String) As Boolean
        ' تُرجع القيمة "صحيح" إذا كان الحقل يساوي القيمة
        If champ Is Nothing OrElse champ.ToString <> valeur Then
            Return false
        Else
            Return true
        End If
    end function
End Class

عندما تبدأ الصفحة [formulaire.aspx] في التشغيل، ستجد في سياقها مفتاح "نموذج" مرتبط بمجموعة قيم الحقول التي يجب عليها عرضها.


         ' نسترد الاستعلام السابق في الجلسة
        Dim form As NameValueCollection
        If Not Context.Items("formulaire") Is Nothing Then
            form = Context.Items("formulaire")
        Else
            form = New NameValueCollection
        End If

قد يتساءل المرء عن سبب التحقق من وجود [Context.Items("formulaire")]. في الواقع، يقوم وحدة التحكم بتعيين قيمة لهذا الكائن في جميع الحالات. ومع ذلك، لا شيء يمنع العميل من طلب الصفحة [formulaire.aspx] مباشرةً دون المرور عبر وحدة التحكم. إذا كان الأمر كذلك، فسيعمل الكود السابق مع مجموعة قيم فارغة ولكن لن يحدث "تعطل".

يستكشف الكود مجموعة القيم التي تلقاها لحساب جميع المتغيرات الديناميكية للصفحة HTML المرتبطة بها. على الرغم من طول هذا الكود، إلا أنه ليس معقدًا بشكل خاص، وسنترك للقارئ حرية استكشافه حتى لا نثقل هذا الشرح. ومع ذلك، سنركز على كيفية إنشاء الكود HTML من القوائم الثلاث من النوع [select]. يتم إنشاء هذا الكود بواسطة الدالة التالية:

    Private Function getOptions(ByRef valeurs() As String, ByRef libelles() As String, ByRef sélections() As String) As String
         ' يعطي الرمز HTML لخيارات علامة <select>
         ' القيم: جدول قيم خيارات العلامة
         ' التسميات: جدول تسميات خيارات العلامة
         ' التحديدات: الخيارات المطلوب تحديدها
        Dim iValeur As Integer
        Dim iSelection As Integer
        Dim selected As String
        Dim toString As String = ""
         ' يتم تصفح قائمة قيم الخيارات
        For iValeur = 0 To valeurs.Length - 1
             ' التحقق مما إذا كان يجب تحديد القيمة الحالية
            selected = "" : iSelection = 0
            Do While iSelection < sélections.Length And selected = ""
                If valeurs(iValeur) = sélections(iSelection) Then selected = "selected"
                iSelection += 1
            Loop
             ' يتم تضمين رمز HTML الخاص بالخيار
            toString += "<option " + selected + " value='" + valeurs(iValeur) + "'> " _
            + libelles(iValeur) + "</option>" + ControlChars.CrLf
        Next
         ' نقوم بإرجاع النتيجة
        Return toString
    End Function

تجدر الإشارة إلى أن خيارات علامة <select> تتوافق مع الرمز HTML التالي:

<option [selected] value="...">texte</option>

لذلك، هناك ثلاث معلومات يجب إنشاؤها لكل خيار:

  • قيمة الخيار في السمة [value]
  • نص الخيار بين العلامتين <option> و </option>
  • الكلمة الرئيسية [selected] إذا كان يجب تحديد الخيار من القائمة

لإنشاء هذه المعلومات الثلاث لكل خيار، تتلقى الدالة [getOptions] ثلاث قيم:

  1. جدول قيم الخيارات في [valeurs]
  2. جدول نصوص الخيارات في [libelles]
  3. جدول القيم المطلوب تحديدها في [sélections]

5.5.4. صفحة التحقق

تظل صفحة التحقق دون تغيير:

[validation.aspx]


<%@ Page src="validation.aspx.vb" Language="vb" AutoEventWireup="false" Inherits="validation" %>
<HTML>
    <HEAD>
        <title>validation</title>
    </HEAD>
    <body>
        <P>Valeurs saisies</P>
        <HR width="100%" SIZE="1">
        <TABLE id="Table1" cellSpacing="1" cellPadding="1" width="300" border="1">
            <TR>
                <TD width="84">rdMarie</TD>
                <TD><% =rdMarie%></TD>
            </TR>
            <TR>
                <TD width="84">C1</TD>
                <TD><%=C1%></TD>
            </TR>
            <TR>
                <TD width="84">C2</TD>
                <TD><%=C2%></TD>
            </TR>
            <TR>
                <TD width="84">C3</TD>
                <TD><%=C3%></TD>
            </TR>
            <TR>
                <TD width="84">txtSaisie</TD>
                <TD><%=txtSaisie%></TD>
            </TR>
            <TR>
                <TD width="84">txtMdp</TD>
                <TD><%=txtMdp%></TD>
            </TR>
            <TR>
                <TD width="84">areaSaisie</TD>
                <TD><%=areaSaisie%></TD>
            </TR>
            <TR>
                <TD width="84">cmbValeurs</TD>
                <TD><%=cmbValeurs%></TD>
            </TR>
            <TR>
                <TD width="84">lstSimple</TD>
                <TD><%=lstSimple%></TD>
            </TR>
            <TR>
                <TD width="84">lstMultiple</TD>
                <TD><%=lstMultiple%></TD>
            </TR>
            <TR>
                <TD width="84">secret</TD>
                <TD><%=secret%></TD>
            </TR>
        </TABLE>
        <P>
            <a href="main.aspx?action=formulaire">Retour au formulaire</a>
        </P>
    </body>
</HTML>

[validation.aspx.vb]


Imports Microsoft.VisualBasic
Imports System.Text.RegularExpressions

Public Class validation
    Inherits System.Web.UI.Page

    Protected rdMarie As String
    Protected C1 As String
    Protected C2 As String
    Protected C3 As String
    Protected txtSaisie As String
    Protected txtMdp As String
    Protected areaSaisie As String
    Protected cmbValeurs As String
    Protected lstSimple As String
    Protected lstMultiple As String
    Protected secret As String
    Protected delimiteur As New Regex("\r\n")

    Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        'يتم استرداد المعلمات المرسلة
        rdMarie = getValue("rdMarie")
        C1 = getValue("C1")
        C2 = getValue("C2")
        C3 = getValue("C3")
        txtSaisie = getValue("txtSaisie")
        txtMdp = getValue("txtMdp")
        areaSaisie = String.Join(",", delimiteur.Split(getValue("areaSaisie")))
        cmbValeurs = getValue("cmbValeurs")
        lstSimple = getValue("lstSimple")
        lstMultiple = getValue("lstMultiple")
        secret = getValue("secret")
        ' يتم حفظها في الجلسة
        'Session("formulaire") = Request.Form
    End Sub

    Private Function getValue(ByVal champ As String) As String
        ' نسترد قيمة الحقل [champ] من الطلب المرسل
        ' شيء ما؟
        If Request.Form(champ) Is Nothing Then Return ""
        ' يتم استرداد قيمة الحقل أو قيم الحقول
        Dim valeurs() As String = Request.Form.GetValues(champ)
        Dim valeur As String = ""
        Dim i As Integer
        For i = 0 To valeurs.Length - 1
            valeur += "[" + valeurs(i) + "]"
        Next
        Return valeur
    End Function
End Class

5.5.5. الاختبارات

يتم وضع ملفات [main.aspx, main.aspx.vb,formulaire.aspx,formulaire.aspx.vb, validation.aspx, validation.aspx.vb] في <application-path> ويتم تشغيل Casini باستخدام المعلمات (<application-path>,/mvcform3). ثم نطلب عنوان URL [http://localhost/mvcform3/main.aspx]. ونحصل على النموذج المُهيأ مسبقًا:

Image

نملأ النموذج بالطريقة التالية:

Image

نستخدم الزر [Envoyer] أعلاه. نحصل على الرد التالي من الخادم:

Image

نستخدم الرابط [Retour au formulaire] أعلاه للعودة إلى النموذج. ونحصل على الرد الجديد التالي:

Image

نجد النموذج بالفعل كما قمنا بتأكيده.

5.5.6. الخلاصة

أظهر لنا المثال السابق أنه من الممكن الحفاظ على حالة الصفحة خلال دورات الطلب والاستجابة بين العميل والخادم. ومع ذلك، فإن هذه المهمة ليست سهلة. سنرى في فصل لاحق أنه من الممكن باستخدام ASP.NET السماح للخادم بإعادة تعيين حالة الصفحة بنفسه.