5. إدارة واجهة المستخدم
5.1. Introduction
في العلاقة بين العميل والخادم على الويب، يرسل العميل المعلومات إلى الخادم في شكل سلسلة من المعلمات [param1=val1¶m2=val2&...]. في الأمثلة السابقة، قمنا في الغالب بإنشاء هذه السلسلة يدويًا عن طريق طلب عناوين URL بالشكل [http://localhost/appli? param1=val1¶m2=val2&...]. في الواقع، المعلومات التي يرسلها العميل إلى الخادم تأتي من النماذج التي ملأها المستخدم. نستكشف كيفية إنشاء هذه النماذج في هذا الفصل. كما نقدم أداة WebMatrix التي ستسمح لنا برسم واجهات المستخدم. يتم عرض تثبيت هذه الأداة في الملاحق.
5.2. لغة HTML
5.2.1. مثال
لنأخذ المثال التالي، الذي تم إنشاؤه باستخدام [Web Matrix] والذي يعرض:
- جدول
- صورة
- رابط

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

- لقد أوشكنا على الانتهاء. لنلقِ نظرة على الكود 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> بالتسلسل التالي:
بالإضافة إلى ذلك، نرغب في عرض النص [Le langage HTML - 1] بحروف أكبر. تسمح التسلسلات <Hi>نص</Hi> بتحديد حجم النص باستخدام i الذي يتراوح من 1 إلى 6 من الأكبر إلى الأصغر. هنا، سنختار H2. التسلسل
يصبح:
تعكس النافذة [Design] التغييرات التي أجريناها:

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

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

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

لقد قدمنا أساسيات إنشاء صفحة HTML باستخدام [WebMatrix]. ندعو القارئ إلى إنشاء صفحات HTML أخرى والتحقق في كل مرة من الكود HTML الذي تم إنشاؤه. وبالتدريج، سيتمكن من إنشاء صفحة دون الحاجة إلى استخدام الوضع [Design]. يتخذ المستند 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 |
<title>HTML1</title> HTML1 سيظهر في شريط عنوان المتصفح الذي سيعرض المستند | |
<hr>: يعرض خطًا أفقيًا | |
<سمات الجدول>....</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") | |
<img src="univ01.gif" />: يحدد صورة ملفها الأصلي هو univ01.gif على خادم الويب (src="univ01.gif"). يوجد هذا الرابط في مستند ويب تم الحصول عليه باستخدام URL http://localhost/exemple1.htm. وبالتالي، سيطلب المتصفح ملف URL http://localhost/univ01.gif للحصول على الصورة المشار إليها هنا. | |
<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:

الرمز 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 |
<form name="formulaire" method="post"> | |
<input type="text" maxlength="30" value="بضع كلمات" name="txtSaisie" /> | |
<input type="password" maxlength="12" size="12" value="unMotDePasse" name="txtMdp" /> | |
<textarea name="areaSaisie">السطر 1 السطر 2</textarea> | |
<input type="radio" value="نعم" name="rdMarie" />نعم <input type="radio" checked value="لا" name="rdMarie" />لا | |
<input type="checkbox" value="واحد" name="C1" />1 <input type="checkbox" checked value="اثنان" name="C2" />2 <input type="checkbox" value="ثلاثة" name="C3" />3 | |
<select name="cmbValeurs"> <option value="1">الخيار 1</option> <option value="2" selected>الخيار 2</option> <option value="3">الخيار 3</option> </select> | |
<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> | |
<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="hidden" name="secret" value="uneValeur" /> | |
<input type="submit" value="إرسال" name="btnEnvoyer" /> | |
<input type="reset" value="إعادة تعيين" name="btnRetablir" runat="server" /> | |
<input onclick="effacer()" type="button" value="مسح" name="btnEffacer" /> |
لنستعرض هذه العناصر المختلفة.
5.2.2.1. النموذج
<form name="formulaire" method="post"> |
<form name="..." method="..." action="...">...</form> | |
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. حقل الإدخال

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

<textarea name="areaSaisie">السطر 1 السطر 2</textarea> |
<textarea ...>نص</textarea> يعرض منطقة إدخال متعددة الأسطر مع وجود نص بداخلها في البداية | |
rows="2": عدد الأسطر cols="'20" : عدد الأعمدة name="areaSaisie": اسم عنصر التحكم |
5.2.2.4. أزرار الاختيار
![]()
<input type="radio" value="نعم" name="rdMarie" />نعم <input type="radio" checked value="لا" name="rdMarie" />لا |
<input type="radio" attribut2="valeur2" ..../>نص يعرض زر اختيار مع نص بجانبه. | |
name="rdMarie": اسم عنصر التحكم. تشكل أزرار الاختيار التي تحمل نفس الاسم مجموعة من الأزرار المتنافية: لا يمكن تحديد سوى واحد منها. value="القيمة" : القيمة المخصصة لزر الاختيار. لا ينبغي الخلط بين هذه القيمة والنص المعروض بجانب زر الاختيار، حيث إن هذا النص مخصص للعرض فقط. checked: إذا كانت هذه الكلمة الرئيسية موجودة، يكون زر الاختيار محددًا، وإلا فإنه غير محدد. |
5.2.2.5. مربعات الاختيار
<input type="checkbox" value="واحد" name="C1" />1 <input type="checkbox" checked value="deux" name="C2" />2 <input type="checkbox" value="ثلاثة" name="C3" />3 |
![]()
<input type="checkbox" attribut2="valeur2" ..../>نص يعرض مربع اختيار مع نص بجانبه. | |
name="C1": اسم عنصر التحكم. يمكن أن تحمل مربعات الاختيار نفس الاسم أو لا. تشكل المربعات التي تحمل نفس الاسم مجموعة من المربعات المرتبطة. value="القيمة": القيمة المخصصة لمربع الاختيار. لا يجب الخلط بين هذه القيمة والنص المعروض بجانب زر الاختيار. فهذا النص مخصص للعرض فقط. checked: إذا كانت هذه الكلمة الرئيسية موجودة، يكون زر الاختيار محددًا، وإلا فإنه غير محدد. |
5.2.2.6. قائمة منسدلة (combo)
<select name="cmbValeurs"> <option value="1">الخيار 1</option> <option value="2" selected>الخيار 2</option> <option value="3">الخيار 3</option> </select> |
![]()
<select size=".." name=".."> <option [selected="selected"] [value="valeur"]>نص</option> ... </select> يعرض في قائمة النصوص الموجودة بين العلامات <option>...</option> | |
name="cmbValeurs": اسم عنصر التحكم. size="1": عدد عناصر القائمة المرئية. size="1" يجعل القائمة تعادل مربع الاختيار. هذه هي القيمة الافتراضية في حالة عدم وجود السمة [size]. selected="selected": إذا كانت هذه الكلمة الرئيسية موجودة لعنصر في القائمة، فسيظهر هذا العنصر محدداً في القائمة. في المثال أعلاه، يظهر عنصر القائمة choix2 كعنصر محدد في القائمة المنسدلة عند عرضها لأول مرة. value="القيمة": يحدد القيمة التي سيتم إرسالها إلى الخادم إذا تم تحديد العنصر. إذا كان هذا السمة غير موجود، فسيتم إرسال النص المرتبط بالخيار إلى الخادم. |
5.2.2.7. قائمة الاختيار الفردي
<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> |

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

<select size=".." name=".." multiple> <option [selected] ] [value="valeur"]>...</option> ... </select> يعرض في قائمة النصوص الموجودة بين العلامات <option>...</option> | |
multiple: يسمح بتحديد عدة عناصر في القائمة. في المثال أعلاه، تم تحديد العنصرين liste1 و liste3. |
5.2.2.9. زر من النوع button
<input onclick="effacer()" type="button" value="Effacer" name="btnEffacer" /> |
![]()
<input type="button" value="..." name="..." onclick="effacer()" ....> | |
type="button": يحدد عنصر تحكم زر. هناك نوعان آخران من الأزرار، وهما submit و reset. value="حذف": النص المعروض على الزر onclick="وظيفة()": يسمح بتعريف وظيفة يتم تنفيذها عندما ينقر المستخدم على الزر. هذه الوظيفة هي جزء من البرامج النصية المحددة في المستند الويب المعروض. الصيغة السابقة هي صيغة javascript. إذا كانت البرامج النصية مكتوبة بلغة vbscript، فيجب كتابة onclick="وظيفة" بدون الأقواس. تصبح الصيغة متطابقة إذا كان من الضروري تمرير معلمات إلى الدالة: onclick="dالة(val1, val2,...)" في مثالنا، يؤدي النقر على الزر Effacer إلى استدعاء وظيفة جافا سكريبت effacer التالية: تعرض الدالة effacer رسالة: ![]() |
5.2.2.10. زر من نوع submit
<input type="submit" value="إرسال" name="btnEnvoyer" /> |
![]()
<input type="submit" value="إرسال" name="btnEnvoyer"> | |
type="submit": يحدد الزر كزر لإرسال بيانات النموذج إلى خادم الويب. عندما ينقر العميل على هذا الزر، سيرسل المتصفح بيانات النموذج إلى URL المحددة في سمة action لعلامة <form> وفقًا للطريقة المحددة بواسطة سمة method لنفس العلامة. value="إرسال": النص المعروض على الزر |
5.2.2.11. زر من نوع reset
<input type="reset" value="إعادة الضبط" name="btnRetablir" runat="server" /> |
![]()
<input type="reset" value="إعادة الضبط" name=" btnRetablir "> | |
type="reset": يحدد الزر كزر لإعادة تعيين النموذج. عندما ينقر العميل على هذا الزر، سيعيد المتصفح النموذج إلى الحالة التي استلمه بها. value="إعادة تعيين": النص المعروض على الزر |
5.2.2.12. حقل مخفي
<input type="hidden" name="secret" value="uneValeur" /> |
<input type="hidden" name="..." value="..."> | |
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¶m2=val2&....
- طلب HTT POST url متبوعًا بوثيقة تحتوي على سلسلة المعلمات param1=va1¶m2=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:

قام المتصفح للتو بإرسال طلب ونعلم أن هذا الطلب قد تم تسجيله في الملف [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 من قبل المستخدم. يتم ملء النموذج بالطريقة التالية:

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

هذه هي الصفحة الأولية، ولكن يمكننا ملاحظة أن 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 مشابهًا إلى حد كبير للطلب الذي قدمه المتصفح في البداية عندما طلب المستند دون إرسال أي معلمات. هناك اختلافان:
تمت إضافة معلمات النموذج بعد URL الخاص بالوثيقة على النحو التالي: ?param1=val1¶m2=val2&... | |
يُشير العميل من خلال هذا العنوان HTTP إلى URL الخاص بالوثيقة التي كان يعرضها عند إرسال الطلب |
دعونا نلقي نظرة فاحصة على كيفية تمرير المعلمات في الأمر GET URL?param1=value1¶m2=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.aspx]، c.a.d. إلى المستند الذي أنشأناه في البداية. لم نكتب أي كود لاسترداد ومعالجة المعلمات التي يرسلها لنا العميل. لذا، يبدو الأمر كما لو أن طلب العميل كان ببساطة:
ولهذا السبب، استجابةً لزرنا [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]. نحصل من الخادم على صفحة الرد التالية:

وبالتالي نحصل على نفس النتيجة التي حصلنا عليها مع الطريقة 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:
استبدل الاستعلام GET باستعلام POST. لم تعد المعلمات موجودة في السطر الأول من الاستعلام. يمكن ملاحظة أنها أصبحت الآن موضوعة بعد الاستعلام HTTP بعد سطر فارغ. ترميزها مطابق للترميز الذي كانت عليه في الاستعلام GET. | |
عدد الأحرف "المرسلة"، c.a.d. عدد الأحرف التي سيتعين على خادم الويب قراءتها بعد استلام الرؤوس HTTP لاسترداد المستند الذي يرسله إليه العميل. المستند المعني هنا هو قائمة قيم النموذج. | |
يحدد نوع المستند الذي سيرسله العميل بعد الرؤوس HTTP. يشير النوع [application/x-www-form-urlencoded] إلى أنه مستند يحتوي على قيم النموذج. |
هناك طريقتان لنقل البيانات إلى خادم الويب: GET و POST. هل هناك طريقة أفضل من الأخرى؟ لقد رأينا أنه إذا تم إرسال قيم النموذج بواسطة المتصفح باستخدام الطريقة GET، فإن المتصفح يعرض في حقل Adresse الخاص به القيمة المطلوبة URL بالصيغة URL?param1=val1¶m2=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¶m2=val2&..". تُضاف هذه المعلمات إذن إلى تلك الموجودة بين العلامتين <form> و </form> والتي ستُحمل إلى الخادم باستخدام GET أو POST. ونظرًا لأنها جزء من عنوان URL الهدف، فسيتم الحصول عليها في المجموعة [Request.QueryString] سواء كنا نتعامل مع GET أو POST.
نكتب الآن تطبيق MVC ذو عرضين:
- الطريقة الأولى هي النموذج السابق. سنسميها [vue_formulaire].
- الطريقة الثانية هي صفحة معلومات تسرد القيم التي تم إدخالها في الصفحة الأولى. يتيح رابط العودة إلى النموذج. سنسمي هذه الطريقة [vue_confirmation].
يتم إرسال العرض [vue_formulaire] إلى المستخدم الذي يقوم بملئه والتحقق من صحته. قد يبدو كما يلي قبل التحقق من الصحة مباشرة:

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

5.4.2. وحدة التحكم في التطبيق
لقد رأينا في الفصل السابق أنه يمكننا أن نُعهد بدور وحدة التحكم في تطبيق MVC إلى الملف [global.asax] الذي تمر عبره جميع طلبات العملاء. لقد قدمنا بالفعل تطبيق MVC الذي تم إنشاؤه بهذه الطريقة، وسنتبع هنا نموذج التطوير الذي تم عرضه آنذاك. سيكون ملف [global.asax] كما يلي:
وهو يتكون من سطر واحد يشير إلى وحدة التحكم الموجودة في الملف [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¶m2=val2&... وهذا ما يتم هنا حيث نمرر المعلمة [action=validation] لإرشاد وحدة التحكم إلى الإجراء الذي يجب أن تتخذه. تجدر الإشارة إلى أن سلسلة المعلمات هذه لا يسبقها عنوان ويب. سيقوم المتصفح عندئذ بإرسال معلمات النموذج إلى العنوان الذي قدم له هذا النموذج. في المثال المقدم أعلاه، هذا العنوان هو [http://localhost/mvcform1]. سيقوم المتصفح إذن بإرسال طلب [POST /mvcform1?action=validation] إلى الجهاز [localhost].
تمت إضافة أزرار لتمكين المستخدم من إلغاء تحديد العناصر في القوائم [lstSimple] و [lstMultiple]:

وينتج عن ذلك الكود 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] هي كما يلي:
تستقبل هذه الوظيفة معلمةً هي كائن جافا سكريبت يمثل قائمة HTML. يحتوي هذا الكائن على خصائص وأساليب. إحدى خصائصه هي [selectedIndex] التي تكون قيمتها رقم الخيار الأول المحدد في القائمة HTML. إذا لم يكن هناك أي خيار، فإن قيمة هذه الخاصية تساوي -1. وبالمقابل، فإن تعيين قيمة لهذه الخاصية يعادل تحديد عنصر جديد في القائمة HTML، وإعطائها القيمة -1 يعادل عدم تحديد أي عنصر. وهذا ما يتم هنا.
وأخيرًا، نلاحظ أن كود العرض [formulaire.aspx] لا يرافقه وحدة تحكم [formulaire.aspx.vb]. في الواقع، لا يوجد أي جزء ديناميكي تم إنشاؤه بواسطة الخادم في المستند HTML، وبالتالي لا توجد حاجة لوحدة تحكم.
5.4.4. معالجة إجراء التحقق من الصحة
عندما يعالج وحدة التحكم إجراء "التحقق من الصحة"، يجب أن يولد صفحة تسرد القيم التي أدخلها المستخدم. وتقع مسؤولية القيام بهذه المهمة على عاتق الصفحة [validation.aspx]. وتظهر الصفحة بصريًا على النحو التالي:

ورمزها 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] فارغًا.
لنفترض أن النموذج الذي تم التحقق من صحته هو التالي:

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

لنلاحظ أولاً عنوان 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] للحقل المخفي |
الآن لننتقل إلى القوائم. لنفترض أن حالة النموذج عند التحقق من الصحة هي كما يلي:

- تم تحديد الخيار [choix1] في comboBox
- ولم يتم تحديد أي خيار في القائمتين الأخريين. وقد استخدمنا الأزرار [Raz] لتحقيق ذلك.
فيما يلي الصفحة التي تم إرجاعها بعد التحقق من الصحة:

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

التعديل المطلوب إجراؤه على الصفحة [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]. نحصل على الصفحة التالية (عرض جزئي):

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

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

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

نلاحظ أن:
- أن عنوان 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]
[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:
المتغير | الدور |
ستكون قيمتها "checked" إذا كان يجب تحديد زر الاختيار [oui]، وإلا فستكون قيمتها "" | |
نفس الشيء بالنسبة لزر الاختيار [non] | |
نفس الشيء بالنسبة لمربع الاختيار [C1] | |
نفس الشيء بالنسبة لمربع الاختيار [C2] | |
وينطبق الأمر نفسه على خانة الاختيار [C3] | |
النص المراد وضعه في الحقل [txtSaisie] | |
النص المراد وضعه في الحقل [txtMdp] | |
النص المراد وضعه في الحقل [areaSaisie] | |
النص HTML خيارات قائمة الاختيار [cmbValeurs] | |
النص HTML من خيارات قائمة الاختيار [lstSimple] | |
النص 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 التالي:
لذلك، هناك ثلاث معلومات يجب إنشاؤها لكل خيار:
- قيمة الخيار في السمة [value]
- نص الخيار بين العلامتين <option> و </option>
- الكلمة الرئيسية [selected] إذا كان يجب تحديد الخيار من القائمة
لإنشاء هذه المعلومات الثلاث لكل خيار، تتلقى الدالة [getOptions] ثلاث قيم:
- جدول قيم الخيارات في [valeurs]
- جدول نصوص الخيارات في [libelles]
- جدول القيم المطلوب تحديدها في [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]. ونحصل على النموذج المُهيأ مسبقًا:

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

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

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

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



