8. مكونات خادم ASP - 2
8.1. مقدمة
نواصل عملنا على واجهة المستخدم من خلال استكشاف:
- مكونات التحقق من صحة البيانات
- كيفية ربط البيانات بمكونات الخادم
- مكونات خادم HTML
8.2. مكونات التحقق من صحة البيانات
8.2.1. مقدمة
في التطبيقات القائمة على النماذج، من الضروري التحقق من صحة البيانات التي يتم إدخالها فيها. في مثال حساب الضرائب، كان لدينا النموذج التالي:

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

يوفر ASP.NET مكونات تسمى مكونات التحقق من الصحة تتيح لك التحقق مما يلي:
المكون | الدور |
يتحقق من أن الحقل ليس فارغًا | |
يقارن بين قيمتين | |
يتحقق من أن القيمة تقع بين حدين | |
يتحقق من أن الحقل يطابق تعبيرًا عاديًا | |
يسمح للمطور بتحديد قواعد التحقق الخاصة به — يمكن لهذا المكون أن يحل محل جميع المكونات الأخرى | |
يسمح لك بجمع رسائل الخطأ التي تم إنشاؤها بواسطة عناصر التحكم السابقة في مكان واحد على الصفحة |
سنقدم الآن كل مكون من هذه المكونات.
8.2.2. RequiredFieldValidator
نقوم بإنشاء الصفحة التالية [requiredfieldvalidator1.aspx]:
![]() |
رقم | الاسم | النوع | الخصائص | الدور |
1 | مربع نص | EnableViewState=true | حقل الإدخال | |
2 | RequiredFieldValidator | EnableViewState=false تمكين البرنامج النصي للعميل=صحيح ErrorMessage=الحقل [name] مطلوب | مكون التحقق من الصحة | |
3 | زر | EnableViewState=false أسباب التحقق من الصحة=صحيح | زر [submit] |
يُستخدم الحقل [RequiredFieldValidator1] لعرض رسالة خطأ إذا كان الحقل [txtName] فارغًا أو يحتوي على سلسلة من المسافات. خصائصه هي كما يلي:
الحقل الذي يجب التحقق من صحة قيمته بواسطة المكون. ماذا تعني قيمة المكون؟ إنها قيمة السمة [value] لعلامة HTML المقابلة. بالنسبة لـ [TextBox]، هذا هو محتوى حقل الإدخال؛ بالنسبة لـ [DropDownList]، هذه هي قيمة العنصر المحدد. | |
Boolean - عندما تكون القيمة true، تشير إلى أنه يجب أيضًا التحقق من صحة محتوى الحقل السابق على جانب العميل. في هذه الحالة، لن يتم إرسال النموذج بواسطة المتصفح إلا إذا كان النموذج خاليًا من الأخطاء. ومع ذلك، يتم إجراء فحوصات التحقق من الصحة أيضًا على الخادم في حالة عدم كون العميل متصفحًا، على سبيل المثال. | |
رسالة الخطأ التي يجب أن يعرضها المكون في حالة اكتشاف خطأ |
يتم إجراء التحقق من صحة البيانات على الصفحة فقط إذا كان الزر أو الرابط الذي أطلق [POST] للصفحة يحتوي على الخاصية [CausesValidation=true]. [true] هي القيمة الافتراضية لهذه الخاصية.
دعونا نقوم بتشغيل هذا التطبيق. أولاً، سنستخدم متصفح [Mozilla]:

فيما يلي كود HTML الذي يتلقاه [Mozilla]:
<html>
<head>
</head>
<body>
<form name="_ctl0" method="post" action="requiredfieldvalidator1.aspx" id="_ctl0">
<input type="hidden" name="__VIEWSTATE" value="dDwxNDI1MDc1NTU1Ozs+SGtdZvVxefDCDxnsqbDnqCaROsk=" />
<p>
Demande du dossier de candidature au DESS
</p>
<fieldset>
<legend>[--Identité--]</legend>
<table>
<tbody>
<tr>
<td>
Nom*</td>
<td>
<input name="txtNom" type="text" id="txtNom" />
</td>
</tr>
</tbody>
</table>
</fieldset>
<p>
<input type="submit" name="btnEnvoyer" value="Envoyer" onclick="if (typeof(Page_ClientValidate) == 'function') Page_ClientValidate(); " language="javascript" id="btnEnvoyer" />
</p>
</form>
</body>
</html>
يمكننا أن نرى أن الزر [btnEnvoyer] مرتبط بوظيفة JavaScript عبر سمة [onclick] الخاصة به. يمكننا أيضًا أن نرى أن الصفحة لا تحتوي على أي كود [JavaScript]. سيفشل الاختبار [typeof(Page_ClientValidate) == 'function']، ولن يتم استدعاء وظيفة JavaScript. سيتم بعد ذلك إرسال النموذج إلى الخادم، الذي سيقوم بإجراء عمليات التحقق من الصحة. دعونا نستخدم زر [Submit] دون إدخال اسم. استجابة الخادم هي كما يلي:

ماذا حدث؟ تم إرسال النموذج إلى الخادم. نفذ الخادم الكود لجميع مكونات التحقق من الصحة في الصفحة. هنا، يوجد مكون واحد فقط. إذا اكتشف مكون واحد على الأقل من مكونات التحقق من الصحة وجود خطأ، فإن الخادم يعيد النموذج كما تم إدخاله (في الواقع، بالنسبة للمكونات التي تحتوي على [EnableViewState=true]، فإنه يتضمن أيضًا رسالة خطأ لكل مكون من مكونات التحقق من الصحة اكتشف وجود خطأ). هذه الرسالة هي السمة [ErrorMessage] لمكون التحقق من الصحة. هذه هي الآلية التي نراها تعمل أعلاه. إذا أدخلنا شيئًا ما في حقل [name]، فلن تظهر رسالة الخطأ عند إرسال النموذج:

الآن، دعونا نستخدم Internet Explorer ونطلب عنوان URL [http://localhost/requiredfieldvalidator1.aspx]. نحصل على الصفحة التالية:

كود HTML الذي يتلقاه IE هو كما يلي:
<html>
<head>
</head>
<body>
<form name="_ctl0" method="post" action="requiredfieldvalidator1.aspx" language="javascript" onsubmit="ValidatorOnSubmit();" id="_ctl0">
<input type="hidden" name="__VIEWSTATE" value="dDwxNDI1MDc1NTU1Ozs+SGtdZvVxefDCDxnsqbDnqCaROsk=" />
<script language="javascript" src="/aspnet_client/system_web/1_1_4322/WebUIValidation.js"></script>
<p>
Demande du dossier de candidature au DESS
</p>
<fieldset>
<legend>[--Identité--]</legend>
<table>
<tbody>
<tr>
<td>
Nom*</td>
<td>
<input name="txtNom" type="text" id="txtNom" />
<span id="RequiredFieldValidator1" controltovalidate="txtNom" errormessage="Le champ [nom] est obligatoire" evaluationfunction="RequiredFieldValidatorEvaluateIsValid" initialvalue="" style="color:Red;visibility:hidden;">Le champ [nom] est obligatoire</span>
</td>
</tr>
</tbody>
</table>
</fieldset>
<p>
<input type="submit" name="btnEnvoyer" value="Envoyer" onclick="if (typeof(Page_ClientValidate) == 'function') Page_ClientValidate(); " language="javascript" id="btnEnvoyer" />
</p>
<script language="javascript">
<!--
var Page_Validators = new Array(document.all["RequiredFieldValidator1"]);
// -->
</script>
<script language="javascript">
<!--
var Page_ValidationActive = false;
if (typeof(clientInformation) != "undefined" && clientInformation.appName.indexOf("Explorer") != -1) {
if (typeof(Page_ValidationVer) == "undefined")
alert("Impossible de trouver la bibliothèque de scripts /aspnet_client/system_web/1_1_4322/WebUIValidation.js. Essayez de placer ce fichier manuellement ou effectuez une réinstallation en exécutant 'aspnet_regiis -c'.");
else if (Page_ValidationVer != "125")
alert("Cette page utilise une version incorrecte de WebUIValidation.js. La page requiert la version 125. La bibliothèque de scripts est " + Page_ValidationVer + ".");
else
ValidatorOnLoad();
}
function ValidatorOnSubmit() {
if (Page_ValidationActive) {
ValidatorCommonOnSubmit();
}
}
// -->
</script>
</form>
</body>
</html>
يمكننا أن نرى أن هذا الرمز أطول بكثير من الرمز الذي تلقته [Mozilla]. لن ندخل في التفاصيل. ينبع الاختلاف من حقيقة أن الخادم أدرج وظائف JavaScript في مستند HTML المرسل. لماذا يوجد رمزان HTML مختلفان في حين أن عنوان URL الذي طلبه كلا المتصفحين هو نفسه؟ لقد أشرنا سابقًا إلى أن تقنية ASP.NET تجعل الخادم يكيّف مستند HTML المرسل إلى العميل مع البيئة المحددة لذلك العميل. هناك العديد من المتصفحات في السوق، وليست جميعها تتمتع بنفس القدرات. على سبيل المثال، لا تستخدم متصفحات Microsoft و Netscape نفس نموذج الكائن للمستند الذي تتلقاه. وبالتالي، يختلف كود JavaScript المستخدم لمعالجة هذا المستند على جانب العميل بين المتصفحين. وبالمثل، أصدرت شركات المتصفحات إصدارات متتالية من متصفحاتها، مع تحسين قدراتها باستمرار. وبالتالي، قد لا يفهم IE3 مستند HTML يمكن لـ IE5 تحليله. ما سبق هو مثال على هذا التكييف من جانب الخادم للعميل. لسبب لم يتم استكشافه بعمق هنا، قرر خادم الويب أن العميل [Mozilla] يفتقر إلى القدرة على التعامل مع كود JavaScript الخاص بالتحقق من الصحة. لذلك، لم يتم تضمين هذا الكود في مستند HTML المرسل إليه، وتم إجراء التحقق من الصحة على جانب الخادم. بالنسبة لـ [IE6]، تم تضمين كود JavaScript هذا في مستند HTML المرسل، كما نرى. لرؤيته أثناء العمل، دعونا نجرب التجربة التالية:
- أوقف خادم الويب
- انقر على زر [إرسال] دون ملء حقل [الاسم]
نحصل على الصفحة الجديدة التالية:

إنه بالفعل المتصفح الذي عرض رسالة الخطأ. هذا لأن الخادم متوقف. يمكننا التحقق من ذلك عن طريق إدخال شيء ما في حقل [name] وإرساله. هذه المرة، يكون الرد كما يلي:

ماذا حدث؟ نفذ المتصفح كود التحقق من صحة JavaScript. حدد هذا الكود أن الصفحة صالحة. ثم أرسل المتصفح النموذج إلى خادم الويب، الذي كان متوقفًا. أدرك المتصفح ذلك وعرض الصفحة أعلاه. إذا أعدنا تشغيل الخادم، يعود كل شيء إلى طبيعته.
ما الذي يمكننا تعلمه من هذا المثال؟
- أهمية مفهوم مكون التحقق من الصحة، الذي يسمح بإعادة أي نموذج غير صحيح إلى العميل
- أهمية [VIEWSTATE]، التي تسمح بإرجاع النموذج تمامًا كما تم إدخاله
- قدرة الخادم على التكيف مع عميله. يتم تحديد العميل من خلال رأس HTTP [User-Agent:] الذي يرسله إلى الخادم. وبالتالي، فإن الخادم لا "يخمن" هوية الطرف الذي يتعامل معه. هذه القدرة على التكيف تهم المطور بشكل كبير، حيث لا يتعين عليه القلق بشأن نوع العميل الذي يستخدم تطبيقه.
8.2.3. CompareValidator
نقوم بإنشاء الصفحة التالية [comparevalidator1.aspx]:

رقم | الاسم | النوع | الخصائص | الدور |
1 | قائمة منسدلة | EnableViewState=true | قائمة منسدلة | |
2 | قائمة منسدلة | EnableViewState=true | قائمة منسدلة | |
3 | مُقارن الصحة | EnableViewState=false تمكين البرنامج النصي للعميل=صحيح رسالة الخطأ=اختيار غير صالح 1 القيمة المراد مقارنتها=؟ المشغل=غير متساوي النوع=سلسلة | مكون التحقق من الصحة | |
4 | مُقارن التحقق من الصحة | تمكين حالة العرض=كاذب تمكين البرنامج النصي للعميل=صحيح رسالة الخطأ=اختيار غير صحيح 2 عنصر التحكم المراد مقارنته=؟ المشغل=غير متساوي النوع=سلسلة | مكون التحقق من الصحة | |
5 | زر | EnableViewState=false أسباب التحقق من الصحة=صحيح | زر [submit] |
يُستخدم مكون [CompareValidator] لمقارنة قيمتين. العوامل المتاحة هي [Equal، NotEqual، LessThan، LessThanEqual، GreaterThan، GreaterThanEqual]. يتم تعيين القيمة الأولى بواسطة الخاصية [ControlToValidate]، والثانية بواسطة [ValueToCompare] إذا كان من المقرر مقارنة القيمة الأولى بثابت، أو بواسطة [ControlToCompare] إذا كان من المقرر مقارنتها بقيمة مكون آخر. الخصائص المهمة لمكون [CompareValidator] هي كما يلي:
الحقل الذي يجب التحقق من صحة محتواه بواسطة المكون | |
Boolean - عندما تكون القيمة true، تشير إلى أنه يجب أيضًا التحقق من صحة محتوى الحقل السابق على جانب العميل | |
رسالة الخطأ التي يجب أن يعرضها المكون في حالة اكتشاف خطأ | |
القيمة التي يجب مقارنة قيمة حقل [ControlToValidate] بها | |
المكون الذي يجب مقارنة قيمة حقل [ControlToValidate] بقيمته | |
عامل المقارنة بين القيمتين | |
نوع القيم المراد مقارنتها |
فيما يلي كود HTML لهذه الصفحة:
<html>
<head>
</head>
<body>
<form runat="server">
<p>
Demande du dossier de candidature au DESS
</p>
<fieldset>
<legend>[--Options du DESS pour lesquelles vous candidatez--]</legend>
<table>
<tbody>
<tr>
<td>
Option1*</td>
<td>
Option2</td>
</tr>
<tr>
<td>
<asp:DropDownList id="cmbChoix1" runat="server">
<asp:ListItem Value="?" Selected="True">?</asp:ListItem>
<asp:ListItem Value="Automatique">Automatique</asp:ListItem>
<asp:ListItem Value="Informatique">Informatique</asp:ListItem>
</asp:DropDownList>
</td>
<td>
<asp:DropDownList id="cmbChoix2" runat="server">
<asp:ListItem Value="?">?</asp:ListItem>
<asp:ListItem Value="Automatique">Automatique</asp:ListItem>
<asp:ListItem Value="Informatique">Informatique</asp:ListItem>
</asp:DropDownList>
</td>
</tr>
<tr>
<td>
<asp:CompareValidator id="CompareValidator1" runat="server" ErrorMessage="Choix 1 invalide" ControlToValidate="cmbChoix1" ValueToCompare="?" Operator="NotEqual"></asp:CompareValidator>
</td>
<td>
<asp:CompareValidator id="CompareValidator2" runat="server" ErrorMessage="Choix 2 invalide" ControlToValidate="cmbChoix2" Operator="NotEqual" ControlToCompare="cmbChoix1"></asp:CompareValidator>
</td>
</tr>
</tbody>
</table>
</fieldset>
<p>
<asp:Button id="btnEnvoyer" runat="server" Text="Envoyer"></asp:Button>
</p>
</form>
</body>
</html>
فيما يلي قيود التحقق من صحة الصفحة:
- يجب أن تكون القيمة المحددة في [cmbChoix1] مختلفة عن السلسلة "?". وهذا يعني الخصائص التالية لمكون [CompareValidator1]: Operator=NotEqual، ValueToCompare=؟، Type=string
- يجب أن تكون القيمة المحددة في [cmbChoix2] مختلفة عن القيمة المحددة في [cmbChoix1]. وهذا يعني الخصائص التالية لمكون [CompareValidator2]: Operator=NotEqual، ControlToCompare=cmbChoix1، Type=string
نقوم بتشغيل هذا التطبيق. فيما يلي مثال لصفحة تم استلامها أثناء التبادلات بين العميل والخادم:

إذا تم طلب نفس الصفحة بواسطة Internet Explorer 6، يتم تضمين كود JavaScript فيها مما يؤدي إلى سلوك مختلف قليلاً. يتم الإبلاغ عن أي أخطاء بمجرد قيام المستخدم بتغيير قيمة في إحدى القوائم المنسدلة. وهذا يحسن تجربة المستخدم.
8.2.4. CustomValidator ، RangeValidator
نقوم بإنشاء الصفحة التالية [customvalidator1.aspx]:

رقم | الاسم | النوع | الخصائص | الدور |
قائمة منسدلة | EnableViewState=true | قائمة منسدلة | ||
CompareValidator | EnableViewState=false تمكين البرنامج النصي للعميل=صحيح رسالة الخطأ=شهادة غير صالحة المشغل=غير متساوي القيمة المراد مقارنتها=؟ النوع=سلسلة | مكون التحقق من صحة عنصر التحكم [1] | ||
مربع نص | EnableViewState=false | حقل الإدخال | ||
المحقق المخصص | EnableViewState=false تمكين البرنامج النصي للعميل=صحيح ErrorMessage=مواصفات الدرجة غير صالحة ClientValidationFunction=chkOtherDegree | مكون التحقق من صحة الحقل [3] | ||
مربع نص | EnableViewState=false | حقل الإدخال | ||
RangeValidator | EnableViewState=false EnableClientScript=true ErrorMessage=يجب أن تكون سنة التخرج ضمن النطاق [1990,2004] القيمة الدنيا=1990 القيمة_القصوى=2004 النوع=عدد صحيح عنصر التحقق من صحة الحقل=txtAnDiplome | مكون التحقق من صحة الحقل [5] | ||
RequiredFieldValidator | EnableViewState=false تمكين البرنامج النصي للعميل=صحيح ErrorMessage=سنة التخرج مطلوبة عنصر التحقق من صحة الحقل=txtAnDiplome | مكون التحقق من صحة الحقل [5] | ||
زر | EnableViewState=false أسباب التحقق من الصحة=صحيح | زر [submit] |
يُستخدم حقل [RangeValidator] للتحقق من أن قيمة عنصر التحكم تقع بين حدين [MinValue] و [MaxValue]. وخصائصه هي كما يلي:
الحقل الذي يجب التحقق من صحة قيمته بواسطة المكون | |
Boolean - عندما تكون القيمة "true"، تشير إلى أنه يجب أيضًا التحقق من صحة محتوى الحقل السابق على جانب العميل | |
رسالة الخطأ التي يجب أن يعرضها المكون في حالة اكتشاف خطأ | |
القيمة الدنيا للحقل المراد التحقق من صحته | |
القيمة القصوى للحقل المراد التحقق منه | |
نوع قيمة الحقل المراد التحقق من صحتها |
يتيح لك حقل [CustomValidator] إجراء عمليات التحقق من الصحة التي لا يمكن إجراؤها بواسطة مكونات التحقق من الصحة التي يوفرها ASP.NET. يتم إجراء هذا التحقق من الصحة بواسطة دالة يكتبها المطور. يتم تنفيذ هذه الدالة على جانب الخادم. ونظرًا لأن التحقق من الصحة يمكن إجراؤه أيضًا على جانب العميل، فقد يحتاج المطور إلى تطوير دالة JavaScript لإدراجها في مستند HTML. وفيما يلي خصائصه:
الحقل الذي يجب التحقق من صحة قيمته بواسطة المكون | |
Boolean - عندما تكون القيمة "true"، تشير إلى أنه يجب أيضًا التحقق من صحة محتوى الحقل السابق على جانب العميل | |
رسالة الخطأ التي يجب أن يعرضها المكون في حالة اكتشاف خطأ | |
الوظيفة التي سيتم تنفيذها على جانب العميل |
فيما يلي كود قالب الصفحة:
<%@ Page Language="VB" %>
<script runat="server">
...
</script>
<html>
<head>
</head>
<body>
<form runat="server">
<p align="left">
Demande du dossier de candidature au DESS
</p>
<fieldset>
<legend>[--Votre dernier diplôme--]</legend>
<table>
<tbody>
<tr>
<td>
Diplôme*</td>
<td>
<asp:DropDownList id="cmbDiplomes" runat="server">
<asp:ListItem Value="?">?</asp:ListItem>
<asp:ListItem Value="[Autre]">[Autre]</asp:ListItem>
<asp:ListItem Value="Maîtrise">Maîtrise</asp:ListItem>
<asp:ListItem Value="DESS">DESS</asp:ListItem>
<asp:ListItem Value="DEA">DEA</asp:ListItem>
</asp:DropDownList>
</td>
<td>
Si [Autre], précisez</td>
<td>
<asp:TextBox id="txtAutreDiplome" runat="server" EnableViewState="False"></asp:TextBox>
</td>
</tr>
<tr>
<td>
</td>
<td>
<p>
<asp:CompareValidator id="CompareValidator2" runat="server" ErrorMessage="Diplôme invalide" ControlToValidate="cmbDiplomes" ValueToCompare="?" Operator="NotEqual" ></asp:CompareValidator>
</p>
</td>
<td>
</td>
<td>
<asp:CustomValidator id="CustomValidator1" runat="server" ErrorMessage="Précision diplôme invalide" OnServerValidate="CustomValidator1_ServerValidate_1" EnableViewState="False" ClientValidationFunction="chckAutreDiplome"></asp:CustomValidator>
</td>
</tr>
<tr>
<td>
Année d'obtention*</td>
<td colspan="3">
<asp:TextBox id="txtAnDiplome" runat="server" Columns="4"></asp:TextBox>
<asp:RangeValidator id="RangeValidator1" runat="server" ErrorMessage="Année diplôme doit être dans l'intervalle [1990,2004]" ControlToValidate="txtAnDiplome" MinimumValue="1990" MaximumValue="2004" Type="Integer"></asp:RangeValidator>
<asp:RequiredFieldValidator id="RequiredFieldValidator2" runat="server" ErrorMessage="Année diplôme requise" ControlToValidate="txtAnDiplome"></asp:RequiredFieldValidator>
</td>
</tr>
</tbody>
</table>
</fieldset>
<p>
<asp:Button id="btnEnvoyer" runat="server" Text="Envoyer"></asp:Button>
</p>
</form>
</body>
</html>
تسمح لك السمة [OnServerValidate] لمكون [CustomValidator] بتحديد الدالة المسؤولة عن التحقق من الصحة من جانب الخادم. في المثال أعلاه، يستدعي مكون [CustomValidator1] الإجراء [CustomValidator1_ServerValidate_1] التالي:
<%@ Page Language="VB" %>
<script runat="server">
Sub CustomValidator1_ServerValidate_1(sender As Object, e As ServerValidateEventArgs)
' field [txtAutreDiplome] must be non-empty if [cmbDiplomes]=[other]
e.isvalid=not (cmbDiplomes.selecteditem.text="[Autre]" and txtAutreDiplome.text.trim="") _
and not (cmbDiplomes.selecteditem.text<>"[Autre]" and cmbDiplomes.selecteditem.text<>"?" and txtAutreDiplome.text.trim<>"")
End Sub
</script>
....
تتلقى دالة التحقق من الصحة المرتبطة بمكون [CustomValidator] معلمتين:
- sender: الكائن الذي أطلق الحدث
- e: الحدث. يجب أن تقوم الإجراء بتعيين الخاصية [e.IsValid] إلى true إذا كانت البيانات التي تم التحقق من صحتها صحيحة، وإلى false في حالة عدم صحتها.
هنا، يتم إجراء الفحوصات التالية:
- لا يمكن أن تحتوي القائمة المنسدلة [cmbDiplomes] على [?] كقيمة لها. يتم التحقق من ذلك بواسطة مكون [CompareValidator2]
- يختار المستخدم درجة علمية من القائمة المنسدلة [cmbDiplomes]. إذا لم تكن الدرجة العلمية موجودة في القائمة، فيمكنه اختيار الخيار [Other] من القائمة. يجب عليه بعد ذلك إدخال الدرجة العلمية في حقل الإدخال [txtAutreDiplome]. إذا تم اختيار [Other] في [cmbDiplomes]، فيجب ألا يكون حقل [txtAutreDiplome] فارغًا. إذا لم يتم تحديد [Other] أو [?] في [cmbDiplomes]، فيجب أن يكون حقل [txtAutreDiplome] فارغًا. يتم التحقق من ذلك بواسطة الدالة المرتبطة بمكون [CustomValidator1].
- يجب أن تكون سنة الحصول على الدرجة العلمية ضمن النطاق [1900-2004]. يتم التحقق من ذلك بواسطة [RangeValidator1]. ومع ذلك، إذا ترك المستخدم الحقل فارغًا، فلن يتم استخدام وظيفة التحقق من صحة [RangeValidator1]. لذلك، نضيف مكون [RequiredFieldValidator2] إلى [ ] للتحقق من وجود محتوى. هذه قاعدة عامة. لا يتم التحقق من محتوى الحقل إذا كان فارغًا. الحالة الوحيدة التي يتم فيها التحقق هي عندما يكون مرتبطًا بمكون [RequiredFieldValidator].
فيما يلي مثال على التنفيذ في متصفح [Mozilla]:

إذا استخدمنا متصفح [IE6]، فيمكننا إضافة وظيفة التحقق من صحة من جانب العميل لمكون [CustomValidator1]. للقيام بذلك، يحتوي هذا المكون على الخصائص التالية:
- EnableClientScript=true
- ClientValidationFunction=chkAutreDiplome
وظيفة [chkAutreDiplome] هي كما يلي:
<head>
<meta http-equiv="pragma" content="no-cache" />
<script language="javascript">
function chkAutreDiplome(source,args){
// vérifie la validité du champ txtAutreDiplome
with(document.frmCandidature){
diplome=cmbDiplomes.options[cmbDiplomes.selectedIndex].text;
args.IsValid= !(diplome=="[Autre]" && txtAutreDiplome.value=="")
&& ! (diplome!="[Autre]" && diplome!="?" && txtAutreDiplome.value!="");
}
}
</script>
</head>
تستقبل الدالة [chkAutreDiplome] نفس المعلمتين اللتين تستقبلهما دالة الخادم [CustomValidator1_ServerValidate_1]:
- source: الكائن الذي أطلق الحدث
- args: الحدث. يحتوي هذا على سمة [IsValid] التي يجب أن تضبطها الدالة على true إذا كانت البيانات التي تم التحقق من صحتها صحيحة. ستؤدي القيمة false إلى عرض رسالة الخطأ المرتبطة في موقع مكون التحقق من الصحة، ولن يتم إرسال النموذج إلى الخادم.
8.2.5. RegularExpressionValidator
نقوم بإنشاء الصفحة التالية [regularexpressionvalidator1.aspx]:

رقم | الاسم | النوع | الخصائص | الدور |
مربع نص | EnableViewState=true | حقل الإدخال | ||
RequiredFieldValidator | ControlToValidate=txtMel Display=Dynamic | مكون التحقق من صحة عنصر التحكم [1] | ||
مُثبت صحة التعبير العادي | عنصر التحكم المراد التحقق من صحته=txtMel Display=Dynamic | مكون التحقق من صحة عنصر التحكم [1] | ||
زر | EnableViewState=false CausesValidation=true | زر [submit] |
هنا، نريد التحقق من صحة تنسيق عنوان البريد الإلكتروني. نقوم بذلك باستخدام مكون [RegularExpressionValidator]، الذي يسمح لنا بالتحقق من صحة حقل باستخدام تعبير عادي. تذكر أن التعبير العادي هو نمط من الأحرف. لذلك، نقوم بمقارنة محتوى الحقل بالنمط. ونظرًا لأن محتوى الحقل لا يتم التحقق منه إذا كان فارغًا، فإننا نحتاج أيضًا إلى مكون [RequiredFieldValidator] للتحقق من أن عنوان البريد الإلكتروني ليس فارغًا. تحتوي فئة [RegularExpressionValidator] على خصائص مشابهة لتلك الموجودة في فئات المكونات التي تمت تغطيتها بالفعل:
الحقل الذي يجب التحقق من صحة قيمته بواسطة المكون | |
boolean - عندما تكون القيمة true، تشير إلى أنه يجب أيضًا التحقق من صحة محتوى الحقل السابق على جانب العميل | |
رسالة الخطأ التي يجب أن يعرضها المكون في حالة اكتشاف خطأ | |
التعبير العادي الذي سيتم مقارنة محتوى [ControlToValidate] به | |
وضع العرض: ثابت: يظل الحقل موجودًا دائمًا حتى إذا لم يعرض رسالة خطأ؛ ديناميكي: يظهر الحقل فقط في حالة وجود رسالة خطأ؛ لا شيء: لا يتم عرض رسالة الخطأ. هذا الحقل موجود أيضًا للمكونات الأخرى ولكن لم يتم استخدامه حتى الآن. |
قد يكون نمط التعبير العادي لعنوان البريد الإلكتروني كما يلي: \s*[\w-]+(\.[\w-]+)*@[\w-]+(\.[\w-]+)+\s*
يكون عنوان البريد الإلكتروني بالصيغة [champ1.champ2....@champA.champB...]. يجب أن يكون هناك حقل واحد على الأقل قبل علامة @ وحقلان على الأقل بعدها. تتكون هذه الحقول من أحرف أبجدية رقمية وعلامة -. يُشار إلى الحرف الأبجدي الرقمي بالرمز \w. التسلسل [\w-] يعني الحرف \w أو الحرف -. تعني علامة + بعد التسلسل S أنه يمكن تكراره مرة واحدة أو أكثر؛ وتعني علامة * أنه يمكن تكراره صفر مرة أو أكثر؛ وتعني علامة ? أنه يمكن تكراره صفر أو مرة واحدة.
يتوافق حقل في عنوان البريد الإلكتروني مع النمط [\w-]+. حقيقة أنه يجب أن يكون هناك حقل واحد على الأقل قبل علامة @ وحقلان على الأقل بعدها، مفصولان بعلامة .، تتوافق مع النمط: [\w-]+(\.[\w-]+)*@[\w-]+(\.[\w-]+)+. يمكننا السماح للمستخدم بتضمين مسافات قبل العنوان وبعده. سيتم إزالة هذه المسافات أثناء المعالجة. يتم تمثيل تسلسل المسافات، الذي قد يكون فارغًا، بالنمط \s*. ومن ثم، فإن التعبير العادي لعنوان البريد الإلكتروني هو: \s*[\w-]+(\.[\w-]+)*@[\w-]+(\.[\w-]+)+\s*.
يصبح كود تخطيط الصفحة كما يلي:
<html>
<head>
</head>
<body>
<form runat="server">
<p align="left">
Demande du dossier de candidature au DESS
</p>
<fieldset>
<legend>[--Votre adresse électronique où sera envoyé le dossier de candidature--]</legend>
<table>
<tbody>
<tr>
<td>
<asp:TextBox id="txtMel" runat="server" Columns="60"></asp:TextBox>
</td>
</tr>
<tr>
<td>
<p>
<asp:RequiredFieldValidator id="RequiredFieldValidator3" runat="server" Display="Dynamic" ControlToValidate="txtMel" ErrorMessage="Votre adresse électronique est requise"></asp:RequiredFieldValidator>
</p>
<p>
<asp:RegularExpressionValidator id="RegularExpressionValidator1" runat="server" Display="Dynamic" ControlToValidate="txtMel" ErrorMessage="Votre adresse électronique n'a pas un format valide" ValidationExpression="\s*[\w-]+(\.[\w-]+)*@[\w-]+(\.[\w-]+)+\s*"></asp:RegularExpressionValidator>
</p>
</td>
</tr>
</tbody>
</table>
</fieldset>
<p>
<asp:Button id="btnEnvoyer" runat="server" Text="Envoyer"></asp:Button>
</p>
</form>
</body>
</html>
8.2.6. ملخص التحقق من الصحة
لأسباب جمالية، قد ترغب في تجميع رسائل الخطأ في مكان واحد، كما في المثال التالي [summaryvalidator1.aspx]، حيث قمنا بدمج جميع الأمثلة السابقة في صفحة واحدة:

تحتوي جميع عناصر التحكم في التحقق من الصحة على الخصائص التالية:
- [Display=Dynamic]، والتي تضمن ألا تشغل عناصر التحكم مساحة على الصفحة إذا كانت رسالة الخطأ الخاصة بها فارغة
- [EnableClientScript=false] لتعطيل جميع عمليات التحقق من الصحة من جانب العميل
- [Text=*]. ستكون هذه هي الرسالة التي يتم عرضها في حالة حدوث خطأ، بينما يتم عرض محتوى السمة [ErrorMessage] بواسطة عنصر التحكم [ValidationSummary] الموضح أدناه.
يتم وضع هذه المجموعة من عناصر التحكم في مكون [Panel] يسمى [vueFormulaire]. في مكون [Panel] آخر يسمى [vueErreurs]، نضع عنصر تحكم [ValidationSummary]:

لا. | الاسم | النوع | الخصائص | الدور |
1 | ملخص التحقق | نص العنوان=حدثت الأخطاء التالية، تمكين البرنامج النصي للعميل=كاذب، إظهار الملخص=صحيح | يعرض الأخطاء من جميع عناصر التحقق من الصحة في الصفحة | |
2 | زر الارتباط | ValidationCauses=false | رابط للعودة إلى النموذج |
بالنسبة لرابط [lnkErrorsToForm]، لا توجد حاجة لتمكين التحقق من الصحة لأن هذا الرابط لا يرسل أي قيم للتحقق منها.
عندما تكون جميع البيانات صالحة، يتم عرض طريقة العرض [info] التالية للمستخدم:

1
رقم | الاسم | نوع | الخصائص | الدور |
1 | تسمية | رسالة معلومات للمستخدم |
رمز HTML لهذه الصفحة هو كما يلي:
<html>
<head>
</head>
<body>
<form runat="server">
<p align="left">
Demande du dossier de candidature au DESS
</p>
<p>
<hr />
<asp:panel id="vueErreurs" runat="server">
<p align="left">
<asp:ValidationSummary id="ValidationSummary1" runat="server" ShowMessageBox="True" BorderColor="#C04000" BorderWidth="1px" BackColor="#FFFFC0" HeaderText="Les erreurs suivantes se sont produites"></asp:ValidationSummary>
</p>
<p>
<asp:LinkButton id="lnkErreursToFormulaire" onclick="lnkErreursToFormulaire_Click" runat="server" CausesValidation="False">Retour au formulaire</asp:LinkButton>
</p>
</asp:panel>
<asp:panel id="vueFormulaire" runat="server">
....
<asp:Button id="btnEnvoyer" onclick="btnEnvoyer_Click" runat="server" Text="Envoyer"></asp:Button>
</p>
</asp:panel>
<asp:panel id="vueInfos" runat="server">
<asp:Label id="lblInfo" runat="server"></asp:Label>
</asp:panel>
</form>
</body>
</html>
فيما يلي بعض الأمثلة على النتائج التي تم الحصول عليها. نقوم بإرسال عرض [form] دون إدخال أي قيم:

يعطينا زر [Submit] الاستجابة التالية:

تم عرض طريقة عرض [errors]. إذا استخدمنا الرابط للعودة إلى النموذج، فسنجده في الحالة التالية:

هذه هي طريقة عرض [form]. لاحظ الحرف [*] بجانب البيانات غير الصحيحة. هذا هو حقل [Text] لعناصر التحكم في التحقق من الصحة التي تم عرضها. إذا قمنا بملء الحقول بشكل صحيح، فسنحصل على طريقة عرض [info]:

رمز عنصر التحكم في الصفحة هو كما يلي:
<%@ Page Language="VB" %>
<script runat="server">
' procedure executed when the page is loaded
Sub page_Load(sender As Object, e As EventArgs)
' on the 1st request, we present the [form] view
if not ispostback then
afficheVues(true,false,false)
end if
end sub
sub afficheVues(byval formulaireVisible as boolean, _
erreursVisible as boolean, infosVisible as boolean)
' set of views
vueFormulaire.visible=formulaireVisible
vueErreurs.visible=erreursVisible
vueInfos.visible=infosVisible
end sub
Sub CustomValidator1_ServerValidate(sender As Object, e As ServerValidateEventArgs)
...
End Sub
Sub CustomValidator2_ServerValidate(sender As Object, e As ServerValidateEventArgs)
...
End Sub
Sub CustomValidator1_ServerValidate_1(sender As Object, e As ServerValidateEventArgs)
...
End Sub
Sub lnkErreursToFormulaire_Click(sender As Object, e As EventArgs)
' displays the form view
afficheVues(true,false,false)
' redo validity checks
Page.validate
End Sub
Sub btnEnvoyer_Click(sender As Object, e As EventArgs)
' is the page valid?
if not Page.IsValid then
' the [errors] view is displayed
afficheVues(false,true,false)
else
' otherwise the view [infos]
lblInfo.Text="Le dossier de candidature au DESS IAIE a été envoyé à l'adresse ["+ _
txtMel.Text + "]. Nous vous en souhaitons bonne réception.<br><br>Le secrétariat du DESS."
afficheVues(false,false,true)
end if
end sub
</script>
<html>
...
</html>
- في الإجراء [Page_Load]، الذي يتم تشغيله عند كل طلب من العميل، نقوم بعرض طريقة العرض [form]، بينما يتم إخفاء الطرق الأخرى. ويتم ذلك فقط عند الطلب الأول. يستدعي الإجراء إجراءً مساعدًا [displayViews]، نمرر إليه ثلاث قيم منطقية لتحديد ما إذا كان سيتم عرض طرق العرض الثلاث أم لا.
- عند استدعاء الإجراء [btnEnvoyer_Click]، يكون التحقق من صحة البيانات قد تم بالفعل. يحتوي الزر [btnEnvoyer] على الخاصية [CausesValidation=true]، التي تطلق عملية التحقق من صحة البيانات هذه. تم تنفيذ جميع عناصر التحكم في التحقق من الصحة، وتم تعيين خاصية [IsValid] الخاصة بها. تشير هذه الخاصية إلى ما إذا كانت البيانات التي تم التحقق من صحتها بواسطة عنصر التحكم صالحة أم لا. علاوة على ذلك، تم أيضًا تعيين الخاصية [IsValid] للصفحة نفسها. تكون [true] فقط إذا كانت الخاصية [IsValid] لجميع عناصر التحكم في التحقق من الصحة على الصفحة لها القيمة [true]. وبالتالي، يبدأ الإجراء [btnEnvoyer_Click] بالتحقق مما إذا كانت الصفحة صالحة أم لا. إذا كانت غير صالحة، يتم عرض طريقة العرض [errors]. تحتوي طريقة العرض هذه على عنصر التحكم [ValidationSummary]، الذي يسرد سمات [ErrorMessage] لجميع عناصر التحكم (انظر لقطة الشاشة أعلاه). إذا كانت الصفحة صالحة، يتم عرض طريقة العرض [info] مع رسالة إعلامية.
- الإجراء [lnkErrorsToForm_Click] مسؤول عن عرض طريقة العرض [form] في الحالة التي تم التحقق من صحتها فيها. نظرًا لأن جميع حقول الإدخال في طريقة العرض [form] لها الخاصية [EnableViewState=true]، يتم إعادة إنشاء حالتها تلقائيًا. ومن الغريب أن حالة مكونات التحقق من الصحة لا يتم استعادتها. قد يتوقع المرء، عند العودة إلى عرض [errors]، أن يرى عناصر التحكم غير الصالحة تعرض حقل [Text] الخاص بها. لكن هذا ليس هو الحال. لذلك، قمنا بفرض التحقق من صحة البيانات باستخدام طريقة [Page.Validate] الخاصة بالصفحة. يجب القيام بذلك بمجرد إظهار لوحة [formView]. وبالتالي، يكون هناك إجمالي عمليتين للتحقق من الصحة. يجب تجنب ذلك في الممارسة العملية. هنا، سمح لنا المثال بتقديم مفاهيم جديدة تتعلق بالتحقق من صحة الصفحة.
8.3. مكونات ListControl وربط البيانات
يتيح لك عدد من مكونات الخادم التي تمت تغطيتها عرض قائمة بالقيم (DropDownList، ListBox). بينما تتيح لك المكونات الأخرى التي لم نتناولها بعد عرض قوائم متعددة بالقيم في جداول HTML. بالنسبة لجميع هذه المكونات، من الممكن برمجياً ربط القيم الموجودة في القوائم بالمكون المقابل واحداً تلو الآخر. من الممكن أيضاً ربط كائنات أكثر تعقيداً بهذه المكونات، مثل كائنات من النوع [Array] و[ArrayList] و[DataSet] و[HashTable]، وما إلى ذلك، مما يبسط الكود الذي يربط البيانات بالمكون. يُسمى هذا الربط ربط البيانات.
يمكن ربط جميع المكونات المشتقة من فئة [ListControl] بقائمة بيانات. وتشمل هذه المكونات [DropDownList] و[ListBox] و[CheckButtonList] و[RadioButtonList]. يمكن ربط كل من هذه المكونات بمصدر بيانات. ويمكن أن يتخذ ذلك أشكالًا مختلفة: [Array]، [ArrayList]، [DataTable]، [DataSet]، [HashTable]، ... وعمومًا كائنًا ينفذ إحدى واجهات IEnumerable أو ICollection أو IListSource. وسنقدم هنا عددًا قليلاً منها فقط. كائن [DataSet] هو تمثيل لقاعدة بيانات علائقية. وبالتالي فهو مجموعة من الجداول المرتبطة بعلاقات. يمثل كائن [DataTable] مثل هذا الجدول. يحدد مصدر البيانات خصائص [Text] و [Value] لكل [Item] في كائن [ListControl]. إذا كان T هو قيمة [Text] و V هو قيمة [Value]، فإن علامة HTML التي يتم إنشاؤها لكل عنصر من عناصر [ListControl] تكون كما يلي:
<option value="V">T</option> | |
<input type="checkbox" value="V">T | |
<input type="radio" value="V">T |
يتم ربط مكون [ListControl] بمصدر بيانات باستخدام الخصائص التالية:
مصدر بيانات [Array]، [ArrayList]، [DataTable]، [DataSet]، [HashTable]، ... | |
إذا كان مصدر البيانات هو [DataSet]، فإنه يمثل اسم الجدول الذي سيتم استخدامه كمصدر للبيانات. يكون مصدر البيانات الفعلي عندئذٍ هو الجدول. | |
إذا كان مصدر البيانات عبارة عن جدول ([DataTable]، [DataSet])، فإنه يمثل اسم عمود الجدول الذي سيوفر القيم لحقل [Text] لعناصر [ListControl] | |
إذا كان مصدر البيانات عبارة عن جدول ([DataTable]، [DataSet])، فإنه يمثل اسم عمود الجدول الذي سيوفر القيم لحقل [Value] لعناصر [ListControl] |
لا يؤدي ربط مكون [ListControl] بمصدر بيانات إلى تهيئة المكون بالقيم من مصدر البيانات. تقوم عملية [ListControl].DataBind بذلك.
اعتمادًا على طبيعة مصدر البيانات، سيتم ربطه بمكون [ListControl] بطريقة مختلفة:
[ListControl].DataSource=A سيحتوي حقل [Text] و[Value] لعناصر [ListControl] على قيم العناصر الموجودة في A | |
[ListControl].DataSource=AL ستحتوي الحقول [Text] و [Value] لعناصر [ListControl] على قيم العناصر الموجودة في AL | |
[ListControl].DataSource = DT، [ListControl].DataTextField = "col1"، [ListControl].DataValueField = "col2" حيث col1 و col2 هما عمودان في جدول DT. ستحتوي الحقول [Text] و [Value] لعناصر [ListControl] على قيم العمودين col1 و col2 في جدول DT | |
[ListControl].DataSource=DS، [ListControl].DataSource="table" حيث "table" هو اسم أحد الجداول في DS. [ListControl].DataTextField="col1"، [ListControl].DatavalueField ="col2" حيث col1 و col2 هما عمودان في جدول "table". ستحتوي الحقول [Text] و [Value] لعناصر [ListControl] على قيم العمودين col1 و col2 في جدول "table" | |
[ListControl].DataSource = HT، [ListControl].DataTextField = "key"، [ListControl].DataValueField = "value"، حيث [key] و [value] هما مفتاحا وقيمتا HT، على التوالي. |
نطبق هذه المعلومات على المثال التالي [databind1.aspx]:
![]() |
لدينا هنا خمسة ربطات بيانات، كل منها تحتوي على أربعة عناصر تحكم من الأنواع [DropDownList] و [ListBox] و [CheckBoxList] و [RadioButtonList]. تختلف الربطات الخمس التي تم فحصها في مصادر بياناتها:
الربط | مصدر البيانات |
مصفوفة | |
قائمة مصفوفة | |
جدول البيانات | |
مجموعة البيانات | |
جدول التجزئة |
8.3.1. رمز عرض المكون
رمز العرض الخاص بعناصر التحكم في الربط 1 هو كما يلي:
<td>
<asp:DropDownList id="DropDownList1" runat="server"></asp:DropDownList>
</td>
<td>
<asp:ListBox id="ListBox1" runat="server" SelectionMode="Multiple"></asp:ListBox>
</td>
<td>
<asp:CheckBoxList id="CheckBoxList1" runat="server"></asp:CheckBoxList>
</td>
<td>
<asp:RadioButtonList id="RadioButtonList1" runat="server"></asp:RadioButtonList>
</td>
الربط للربطات من 2 إلى 5 متطابق باستثناء رقم الربط.
8.3.2. الربط بمصدر بيانات صفيف
يتم ربط عناصر التحكم الأربعة [ListBox] أعلاه على النحو التالي في الإجراء [Page_Load] لرمز عنصر التحكم:
' global data
dim textes() as string={"un","deux","trois","quatre"}
dim valeurs() as string={"1","2","3","4"}
dim myDataListe as new ArrayList
dim myDataTable as new DataTable("table1")
dim myDataSet as new DataSet
dim myHashTable as new HashTable
' procedure executed when the page is loaded
Sub page_Load(sender As Object, e As EventArgs)
if not IsPostBack then
' create the data sources to be linked to the components
createDataSources
' link to an array [Array]
bindToArray
' link to a list [ArrayList]
bindToArrayList
' link to a table [DataTable]
bindToDataTable
' link to a data group [DataSet]
bindToDataSet
' link to a dictionary [HashTable]
bindToHashTable
end if
End Sub
sub createDataSources
' creates data sources to be linked to components
' arraylist
dim i as integer
for i=0 to textes.length-1
myDataListe.add(textes(i))
next
' datatable
' we define its two columns
myDataTable.Columns.Add("id",Type.GetType("System.Int32"))
myDataTable.Columns.Add("texte",Type.GetType("System.String"))
' fill the table
dim ligne as DataRow
for i=0 to textes.length-1
ligne=myDataTable.NewRow
ligne("id")=i
ligne("texte")=textes(i)
myDataTable.Rows.Add(ligne)
next
' dataset - a single table
myDataSet.Tables.Add(myDataTable)
' hashtable
for i=0 to textes.length-1
myHashTable.add(valeurs(i),textes(i))
next
end sub
' panel connection
sub bindToArray
' association with components
with DropDownList1
.DataSource=textes
.DataBind
end with
with ListBox1
.DataSource=textes
.DataBind
end with
with CheckBoxList1
.DataSource=textes
.DataBind
end with
with RadioButtonList1
.DataSource=textes
.DataBind
end with
' item selection
ListBox1.Items(1).Selected=true
ListBox1.Items(3).Selected=true
CheckBoxList1.Items(0).Selected=true
CheckBoxList1.Items(3).Selected=true
DropDownList1.SelectedIndex=2
RadioButtonList1.SelectedIndex=1
end sub
sub bindToArrayList
....
end sub
sub bindToDataTable
...
end sub
sub bindToDataSet
...
end sub
يتم ربط عناصر التحكم بالبيانات هنا فقط عند الطلب الأول. بعد ذلك، ستحتفظ عناصر التحكم بعناصرها عبر آلية [VIEWSTATE]. يتم تنفيذ الربط في الإجراء [bindToArray]. نظرًا لأن مصدر البيانات من النوع [Array]، يتم تهيئة حقل [DataSource] فقط من مكونات [ListControl]. يتم ملء عنصر التحكم بالقيم من مصدر البيانات المرتبط باستخدام طريقة [ListControl].DataBind. عندها فقط تحتوي كائنات [ListControl] على عناصر. يمكنك بعد ذلك تحديد بعضها.
8.3.3. الربط بمصدر بيانات ArrayList
يتم تهيئة مصدر البيانات [myDataList] في الإجراء [createDataSources]:
' global data
dim textes() as string={"un","deux","trois","quatre"}
dim myDataListe as new ArrayList
..
' procedure executed when the page is loaded
Sub page_Load(sender As Object, e As EventArgs)
if not IsPostBack then
' create the data sources to be linked to the components
createDataSources
...
end if
End Sub
sub createDataSources
' creates data sources to be linked to components
' arraylist
dim i as integer
for i=0 to textes.length-1
myDataListe.add(textes(i))
next
...
end sub
يتم ربط عناصر التحكم الأربعة [ListBox] في الربط 2 على النحو التالي في الإجراء [bindToArrayList] في كود عنصر التحكم:
' liaison arraylist
sub bindToArrayList
' l'association aux composants
with DropDownList2
.DataSource=myDataListe
.DataBind
end with
with ListBox2
.DataSource=myDataListe
.DataBind
end with
with CheckBoxList2
.DataSource=myDataListe
.DataBind
end with
with RadioButtonList2
.DataSource=myDataListe
.DataBind
end with
' la sélection des éléments
ListBox2.Items(1).Selected=true
ListBox2.Items(3).Selected=true
CheckBoxList2.Items(0).Selected=true
CheckBoxList2.Items(3).Selected=true
DropDownList2.SelectedIndex=2
RadioButtonList2.SelectedIndex=1
end sub
نظرًا لأن مصدر البيانات من النوع [ArrayList]، يتم تهيئة حقل [DataSource] فقط لمكونات [ListControl].
8.3.4. مصدر البيانات من النوع DataTable
يتم تهيئة مصدر البيانات [myDataTable] في الإجراء [createDataSources]:
' global data
dim textes() as string={"un","deux","trois","quatre"}
dim myDataTable as new DataTable("table1")
...
' procedure executed when the page is loaded
Sub page_Load(sender As Object, e As EventArgs)
if not IsPostBack then
' create the data sources to be linked to the components
createDataSources
...
end if
End Sub
sub createDataSources
' creates data sources to be linked to components
...
' datatable
' we define its two columns
myDataTable.Columns.Add("id",Type.GetType("System.Int32"))
myDataTable.Columns.Add("texte",Type.GetType("System.String"))
' fill the table
dim ligne as DataRow
for i=0 to textes.length-1
ligne=myDataTable.NewRow
ligne("id")=i
ligne("texte")=textes(i)
myDataTable.Rows.Add(ligne)
next
...
end sub
نبدأ بإنشاء كائن [DataTable] به عمودان: [id] و [text]. سيملأ العمود [id] حقل [Value] لعناصر [ListControl]، وسيملأ العمود [text] حقول [Text] الخاصة بها. يتم إنشاء [DataTable] ذي العمودين على النحو التالي:
myDataTable.Columns.Add("id",Type.GetType("System.Int32"))
myDataTable.Columns.Add("texte",Type.GetType("System.String"))
وبذلك ننشئ جدولًا مكونًا من عمودين:
- الأول، المسمى "id"، هو من النوع integer
- والثاني، المسمى "text"، هو من النوع string
الآن بعد إنشاء بنية الجدول، يمكننا ملؤه بالكود التالي:
dim ligne as DataRow
for i=0 to textes.length-1
ligne=myDataTable.NewRow
ligne("id")=i
ligne("texte")=textes(i)
myDataTable.Rows.Add(ligne)
next
سيحتوي العمود [id] على أعداد صحيحة [0,1,..,n]، بينما سيحتوي العمود [text] على القيم من المصفوفة [data]. وبمجرد الانتهاء من ذلك، يتم ملء الجدول [dataList]. يتم تنفيذ ربط عناصر التحكم الأربعة [ListBox] في الربط 3 على النحو التالي في الإجراء [bindToDataTable] لرمز عنصر التحكم:
sub bindToDataTable
' l'association aux composants
with DropDownList3
.DataSource=myDataTable
.DataValueField="id"
.DataTextField="texte"
.DataBind
end with
with ListBox3
.DataSource=myDataTable
.DataValueField="id"
.DataTextField="texte"
.DataBind
end with
with CheckBoxList3
.DataSource=myDataTable
.DataValueField="id"
.DataTextField="texte"
.DataBind
end with
with RadioButtonList3
.DataSource=myDataTable
.DataValueField="id"
.DataTextField="texte"
.DataBind
end with
' la sélection des éléments
ListBox3.Items(1).Selected=true
ListBox3.Items(3).Selected=true
CheckBoxList3.Items(0).Selected=true
CheckBoxList3.Items(3).Selected=true
DropDownList3.SelectedIndex=2
RadioButtonList3.SelectedIndex=1
end sub
يتم ربط كل مكون [ListControl] بمصدر البيانات [myDataTable] عن طريق تعيين ما يلي لكل مكون:
الجدول [myDataTable] هو مصدر البيانات. سيملأ العمود [id] في هذا الجدول حقول [Value] لعناصر المكون، بينما سيملأ العمود [text] حقول [Text] الخاصة بها.
8.3.5. مصدر البيانات من نوع DataSet
يتم تهيئة مصدر البيانات [myDataSet] في الإجراء [createDataSources]:
' global data
dim myDataTable as new DataTable("table1")
dim myDataSet as new DataSet
...
' procedure executed when the page is loaded
Sub page_Load(sender As Object, e As EventArgs)
if not IsPostBack then
' create the data sources to be linked to the components
createDataSources
...
end if
End Sub
sub createDataSources
' creates data sources to be linked to components
' dataset - a single table
myDataSet.Tables.Add(myDataTable)
...
end sub
يمثل كائن [DataSet] مجموعة من جداول [DataTable]. نضيف [myDataTable] الذي تم إنشاؤه مسبقًا إلى [DataSet]. يتم ربط عناصر التحكم الأربعة [ListBox] في الربط 4 على النحو التالي في الإجراء [bindToDataSet] لرمز عنصر التحكم:
sub bindToDataSet
' l'association aux composants
with DropDownList4
.DataSource=myDataSet
.DataMember="table1"
.DataValueField="id"
.DataTextField="texte"
.DataBind
end with
with ListBox4
.DataSource=myDataSet
.DataMember="table1"
.DataValueField="id"
.DataTextField="texte"
.DataBind
end with
with CheckBoxList4
.DataSource=myDataSet
.DataMember="table1"
.DataValueField="id"
.DataTextField="texte"
.DataBind
end with
with RadioButtonList4
.DataSource=myDataSet
.DataMember="table1"
.DataValueField="id"
.DataTextField="texte"
.DataBind
end with
' la sélection des éléments
ListBox4.Items(1).Selected=true
ListBox4.Items(3).Selected=true
CheckBoxList4.Items(0).Selected=true
CheckBoxList4.Items(3).Selected=true
DropDownList4.SelectedIndex=2
RadioButtonList4.SelectedIndex=1
end sub
يتم ربط كل مكون [ListControl] بمصدر البيانات على النحو التالي:
مجموعة البيانات [myDataSet] هي مصدر البيانات. ونظرًا لأنها قد تحتوي على جداول متعددة، فإننا نحدد اسم الجدول المراد استخدامه في [DataMember]. وسيقوم عمود [id] في هذا الجدول بتعبئة حقول [Value] لعناصر المكون، بينما سيقوم عمود [text] بتعبئة حقول [Text] الخاصة بها.
8.3.6. مصدر بيانات HashTable
يتم تهيئة مصدر البيانات [myHashTable] في الإجراء [createDataSources]:
' global data
dim textes() as string={"un","deux","trois","quatre"}
dim valeurs() as string={"1","2","3","4"}
dim myHashTable as new HashTable
...
' procedure executed when the page is loaded
Sub page_Load(sender As Object, e As EventArgs)
if not IsPostBack then
' create the data sources to be linked to the components
createDataSources
...
end if
End Sub
sub createDataSources
' creates data sources to be linked to components
...
' hashtable
for i=0 to textes.length-1
myHashTable.add(valeurs(i),textes(i))
next
end sub
يمكن النظر إلى القاموس [myHashTable] على أنه جدول مكون من عمودين يسميان "key" و"value". يمثل العمود [key] مفاتيح القاموس، ويمثل العمود [value] القيم المرتبطة بها. هنا، يتكون العمود [key] من محتويات المصفوفة [values]، ويتكون العمود [value] من محتويات المصفوفة [texts]. يتم ربط هذا المصدر بالعناصر التحكمية في الإجراء [bindToHashTable]:
sub bindToHashTable
' l'association aux composants
with DropDownList5
.DataSource=myHashTable
.DataValueField="key"
.DataTextField="value"
.DataBind
end with
with ListBox5
.DataSource=myHashTable
.DataValueField="key"
.DataTextField="value"
.DataBind
end with
with CheckBoxList5
.DataSource=myHashTable
.DataValueField="key"
.DataTextField="value"
.DataBind
end with
with RadioButtonList5
.DataSource=myHashTable
.DataValueField="key"
.DataTextField="value"
.DataBind
end with
' la sélection des éléments
ListBox5.Items(1).Selected=true
ListBox5.Items(3).Selected=true
CheckBoxList5.Items(0).Selected=true
CheckBoxList5.Items(3).Selected=true
DropDownList5.SelectedIndex=2
RadioButtonList5.SelectedIndex=1
end sub
بالنسبة لكل مكون، يتم إنشاء الارتباط باستخدام التعليمات التالية:
مصدر البيانات هو القاموس [myHashTable]. يتم توفير قيم عناصر التحكم من خلال عمود [key] في القاموس، والنص من خلال عمود [value]. يتم إدراج عناصر القاموس في عناصر التحكم بترتيب المفاتيح، والذي يكون عشوائيًا في البداية.
8.3.7. توجيهات استيراد مساحة الاسم
يتم استيراد عدد من مساحات الأسماء تلقائيًا إلى صفحة ASP.NET. لا ينطبق هذا على "System.Data"، حيث توجد فئتا [DataTable] و[DataSet]. لذلك، يجب استيراد هذه الفئة. ويتم ذلك على النحو التالي:
<%@ Page Language="VB" %>
<%@ import Namespace="System.Data" %>
<script runat="server">
...
</script>
<html>
...
</html>
8.4. مكون DataGrid وربط البيانات
يتيح لك مكون [DataGrid] عرض البيانات في شكل جدول، ولكنه يتجاوز مجرد العرض البسيط:
- فهو يوفر القدرة على تكوين "العرض المرئي" للجدول بدقة
- ويسمح لك بتحديث مصدر البيانات
يعد مكون [DataGrid] قويًا ومعقدًا في الوقت نفسه. سنقوم بعرضه خطوة بخطوة.
8.4.1. عرض مصدر بيانات من نوع Array أو ArrayList أو DataTable أو DataSet
يتيح لك مكون [DataGrid] عرض مصادر البيانات من النوع [Array] و[ArrayList] و[DataTable] و[DataSet] في جدول HTML. بالنسبة لهذه الأنواع الأربعة من البيانات، ما عليك سوى ربط المصدر بخاصية [DataSource] لمكون [DataGrid]:
مصدر بيانات [Array]، [ArrayList]، [DataTable]، [DataSet]، ... | |
إذا كان مصدر البيانات هو [DataSet]، فإنه يمثل اسم الجدول الذي سيتم استخدامه كمصدر للبيانات. يكون مصدر البيانات الفعلي عندئذٍ هو جدول. إذا تُرك هذا الحقل فارغًا، فسيتم عرض جميع الجداول الموجودة في [DataSet]. |
نقدم الآن صفحة [datagrid1.aspx]، التي تعرض [DataGrid] مرتبطًا بأربعة مصادر بيانات مختلفة:

تحتوي الصفحة على أربعة مكونات [DataGrid] تم إنشاؤها باستخدام [WebMatrix] على النحو التالي. نضع المكون في مكانه في علامة التبويب [Design]:

ثم يتم رسم جدول HTML عام. يمكن تعريف خصائص [DataGrid] في وقت التصميم. وهذا ما نقوم به هنا لخصائص التنسيق الخاصة به. للقيام بذلك، نختار [DataGrid] المراد تكوينه. تظهر خصائصه في نافذة في أسفل اليمين:

سنستخدم الرابطين أعلاه. يوفر رابط [Property Generator] الوصول إلى الخصائص الرئيسية لـ [DataGrid]:

نقوم بإلغاء تحديد خيار [Show Header] للمكونات الأربعة [DataGrid] ونحفظ الصفحة. يتيح لك الرابط الآخر، [Auto Format]، الاختيار من بين عدة أنماط لجدول HTML الذي سيتم عرضه:

نختار [color i] لـ [DataGrid] #i. تنعكس خيارات التصميم هذه في كود عرض الصفحة:
<html>
<head>
</head>
<body>
<form runat="server">
<p>
Liaison de données avec un DataGrid
</p>
<hr />
<p>
<table>
<tbody>
</tbody>
</table>
<table border="1">
<tbody>
<tr>
<td>
Array</td>
<td>
ArrayList</td>
<td>
DataTable</td>
<td>
DataSet</td>
</tr>
<tr>
<td>
<asp:DataGrid id="DataGrid1" runat="server" ShowHeader="False" CellPadding="4" BackColor="White" BorderColor="#CC9966" BorderWidth="1px" BorderStyle="None">
<FooterStyle forecolor="#330099" backcolor="#FFFFCC"></FooterStyle>
<HeaderStyle font-bold="True" forecolor="#FFFFCC" backcolor="#990000"></HeaderStyle>
<PagerStyle horizontalalign="Center" forecolor="#330099" backcolor="#FFFFCC"></PagerStyle>
<SelectedItemStyle font-bold="True" forecolor="#663399" backcolor="#FFCC66"></SelectedItemStyle>
<ItemStyle forecolor="#330099" backcolor="White"></ItemStyle>
</asp:DataGrid>
</td>
<td>
<asp:DataGrid id="DataGrid2" runat="server" ShowHeader="False" CellPadding="4" BackColor="White" BorderColor="#3366CC" BorderWidth="1px" BorderStyle="None">
<FooterStyle forecolor="#003399" backcolor="#99CCCC"></FooterStyle>
<HeaderStyle font-bold="True" forecolor="#CCCCFF" backcolor="#003399"></HeaderStyle>
<PagerStyle horizontalalign="Left" forecolor="#003399" backcolor="#99CCCC" mode="NumericPages"></PagerStyle>
<SelectedItemStyle font-bold="True" forecolor="#CCFF99" backcolor="#009999"></SelectedItemStyle>
<ItemStyle forecolor="#003399" backcolor="White"></ItemStyle>
</asp:DataGrid>
</td>
<td>
<asp:DataGrid id="DataGrid3" runat="server" ShowHeader="False" CellPadding="3" BackColor="#DEBA84" BorderColor="#DEBA84" BorderWidth="1px" BorderStyle="None" CellSpacing="2">
<FooterStyle forecolor="#8C4510" backcolor="#F7DFB5"></FooterStyle>
<HeaderStyle font-bold="True" forecolor="White" backcolor="#A55129"></HeaderStyle>
<PagerStyle horizontalalign="Center" forecolor="#8C4510" mode="NumericPages"></PagerStyle>
<SelectedItemStyle font-bold="True" forecolor="White" backcolor="#738A9C"></SelectedItemStyle>
<ItemStyle forecolor="#8C4510" backcolor="#FFF7E7"></ItemStyle>
</asp:DataGrid>
</td>
<td>
<asp:DataGrid id="DataGrid4" runat="server" ShowHeader="False" CellPadding="3" BackColor="White" BorderColor="#E7E7FF" BorderWidth="1px" BorderStyle="None" GridLines="Horizontal">
<FooterStyle forecolor="#4A3C8C" backcolor="#B5C7DE"></FooterStyle>
<HeaderStyle font-bold="True" forecolor="#F7F7F7" backcolor="#4A3C8C"></HeaderStyle>
<PagerStyle horizontalalign="Right" forecolor="#4A3C8C" backcolor="#E7E7FF" mode="NumericPages"></PagerStyle>
<SelectedItemStyle font-bold="True" forecolor="#F7F7F7" backcolor="#738A9C"></SelectedItemStyle>
<AlternatingItemStyle backcolor="#F7F7F7"></AlternatingItemStyle>
<ItemStyle forecolor="#4A3C8C" backcolor="#E7E7FF"></ItemStyle>
</asp:DataGrid>
</td>
</tr>
</tbody>
</table>
</p>
<asp:Button id="Button1" runat="server" Text="Envoyer"></asp:Button>
</form>
</body>
</html>
في وضع التصميم، قمنا فقط بتعيين خصائص التنسيق. وفي كود عنصر التحكم، نقوم بربط البيانات بالمكونات الأربعة:
<%@ Page Language="VB" %>
<%@ import Namespace="system.data" %>
<script runat="server">
' global data
dim textes1() as string={"un","deux","trois","quatre"}
dim textes2() as string={"one","two","three","for"}
dim valeurs() as string={"1","2","3","4"}
dim myDataListe as new ArrayList
dim myDataTable as new DataTable("table1")
dim myDataSet as new DataSet
' procedure executed when the page is loaded
Sub page_Load(sender As Object, e As EventArgs)
if not IsPostBack then
' create the data sources to be linked to the components
createDataSources
' link to an array [Array]
bindToArray
' link to a list [ArrayList]
bindToArrayList
' link to a table [DataTable]
bindToDataTable
' link to a data group [DataSet]
bindToDataSet
end if
End Sub
sub createDataSources
' creates data sources to be linked to components
' arraylist
dim i as integer
for i=0 to textes1.length-1
myDataListe.add(textes1(i))
next
' datatable
' we define its two columns
myDataTable.Columns.Add("id",Type.GetType("System.Int32"))
myDataTable.Columns.Add("texte1",Type.GetType("System.String"))
myDataTable.Columns.Add("texte2",Type.GetType("System.String"))
' fill the table
dim ligne as DataRow
for i=0 to textes1.length-1
ligne=myDataTable.NewRow
ligne("id")=valeurs(i)
ligne("texte1")=textes1(i)
ligne("texte2")=textes2(i)
myDataTable.Rows.Add(ligne)
next
' dataset - a single table
myDataSet.Tables.Add(myDataTable)
end sub
' panel connection
sub bindToArray
with DataGrid1
.DataSource=textes1
.DataBind
end with
end sub
' arraylist link
sub bindToArrayList
with DataGrid2
.DataSource=myDataListe
.DataBind
end with
end sub
' datatable link
sub bindToDataTable
with DataGrid3
.DataSource=myDataTable
.DataBind
end with
end sub
' dataset link
sub bindToDataSet
with DataGrid4
.DataSource=myDataSet
.DataBind
end with
end sub
</script>
<html>
...
</html>
يشبه هذا الكود إلى حد كبير الكود الموجود في المثال السابق، لذا لن نعلق عليه بشكل خاص. لكن لاحظ كيف يتم ربط البيانات. بالنسبة لكل عنصر من العناصر الأربعة، يكفي استخدام التسلسل التالي:
حيث يكون [مصدر البيانات] من النوع [Array] أو [ArrayList] أو [DataTable] أو [DataSet]. وبالتالي، يمكننا أن نرى أن هذه أداة قوية لعرض البيانات في الجداول:
- يتم إنشاء التخطيط باستخدام [WebMatrix] أو أي بيئة تطوير متكاملة (IDE) أخرى خلال مرحلة التصميم
- يتم ربط البيانات في الكود. باستخدام [WebMatrix]، يمكن القيام بذلك في وقت التصميم إذا كان مصدر البيانات قاعدة بيانات SQL Server أو قاعدة بيانات Access. في هذه الحالة، يتم وضع مكون [SqlDataSource] أو [AccessDataSource] في النموذج. يمكن ربط هذا المكون في وقت التصميم بمصدر البيانات الفعلي، سواء كان قاعدة بيانات SQL Server أو قاعدة بيانات Access، حسب الاقتضاء. إذا قمت بتعيين كائن [SqlDataSource] أو [AccessDataSource] مرتبط بمصدر فعلي إلى خاصية [DataSource] لمكون [DataGrid]، فستظهر البيانات الفعلية في مكون [DataGrid] في وضع التصميم.
8.5. ViewState لمكونات قائمة البيانات
نهدف هنا إلى تسليط الضوء على آلية [VIEWSTATE] لمكونات قائمة البيانات. قد تتردد بين طريقتين للحفاظ على حالة مكون قائمة البيانات بين طلبين من العميل:
- تعيين سمة [VIEWSTATE] الخاصة به على true
- تعيين سمة [VIEWSTATE] الخاصة به على false وتخزين مصدر البيانات الخاص به في الجلسة بحيث يمكن ربط المكون بهذا المصدر أثناء الطلب التالي.
يوضح المثال التالي جوانب معينة من آلية [VIEWSTATE] لحاويات البيانات. عند الطلب الأول للعميل، يعرض التطبيق العرض التالي:
![]() |
رقم | الاسم | النوع | الخصائص | الدور |
1 | DataGrid | EnableViewState=true | يعرض مصدر بيانات S | |
2 | DataGrid | EnableViewState=true | يعرض مصدر البيانات S نفسه مثل [DataGrid1] | |
3 | زر | EnableViewState=false | زر [submit] |
يتم الحفاظ على مكون [DataGrid1] بواسطة آلية [VIEWSTATE]. نريد تحديد ما إذا كانت هذه الآلية، التي تعيد إنشاء عرض [DataGrid1] مع كل طلب، تعيد أيضًا إنشاء مصدر البيانات الخاص به. للقيام بذلك، يتم ربط مصدر البيانات بمكون [DataGrid2]. يتم إنشاؤه مع كل طلب عبر ربط صريح بمصدر البيانات الخاص بـ [DataGrid1]. كما يتم تعيين سمة [EnableViewState] الخاصة به على [true].
فيما يلي كود العرض [main.aspx] للتطبيق:
<%@ page src="main.aspx.vb" inherits="main" autoeventwireup="false" %>
<HTML>
<HEAD>
<title></title>
</HEAD>
<body>
<form runat="server">
<table>
<tr>
<td align="center">DataGrid 1</td>
<td align="center">
DataGrid 2</td>
</tr>
<tr>
<td>
<asp:DataGrid id="DataGrid1" runat="server" ...>
<SelectedItemStyle ...></SelectedItemStyle>
....
</asp:DataGrid></td>
<td>
<asp:DataGrid id="Datagrid2" runat="server" ...>
....
</asp:DataGrid></td>
</tr>
</table>
<asp:Button id="Button1" runat="server" Text="Envoyer"></asp:Button>
</form>
</body>
</HTML>
وحدة التحكم [main.aspx.vb] هي كما يلي:
Imports System.Data
Public Class main
Inherits System.Web.UI.Page
Protected WithEvents DataGrid1 As System.Web.UI.WebControls.DataGrid
Protected WithEvents Datagrid2 As System.Web.UI.WebControls.DataGrid
Protected WithEvents Button1 As System.Web.UI.WebControls.Button
Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
' on the 1st query, the data source is defined and linked to the 1st datagrid
If Not IsPostBack Then
'define data source
With DataGrid1
.DataSource = createDataSource()
.DataBind()
End With
End If
' for each query, datagrid2 is linked to the source of the 1st datagrid
With Datagrid2
.DataSource = DataGrid1.DataSource
.DataBind()
End With
End Sub
Private Function createDataSource() As DataTable
' initialize the data source
Dim thèmes As New DataTable
' columns
With thèmes.Columns
.Add("id", GetType(System.Int32))
.Add("thème", GetType(System.String))
.Add("description", GetType(System.String))
End With
' column id will be primary key
thèmes.Constraints.Add("cléprimaire", thèmes.Columns("id"), True)
' lines
Dim ligne As DataRow
For i As Integer = 0 To 4
ligne = thèmes.NewRow
ligne.Item("id") = i.ToString
ligne.Item("thème") = "thème" + i.ToString
ligne.Item("description") = "description du thème " + i.ToString
thèmes.Rows.Add(ligne)
Next
Return thèmes
End Function
Private Sub InitializeComponent()
End Sub
End Class
تقوم طريقة [createDataSource] بإنشاء مصدر بيانات S من النوع [DataTable]. لن نتطرق إلى كودها، لأنها ليست محور هذا المثال. هذه هي الطريقة المستخدمة لإنشاء مكوني [DataGrid] اللذين يهماننا:
- يتم ربط مكون [DataGrid1] بالجدول S مرة واحدة، أثناء الاستعلام الأول. ولا يتم ربطه بعد ذلك.
- يتم ربط مكون [DataGrid2] بمصدر [DataGrid1.DataSource] مع كل استعلام جديد.
أثناء الاستعلام الأول، نحصل على العرض التالي:

من المنطقي تمامًا أن يعرض كلا المكونين مصدر البيانات الذي تم ربطهما به. نستخدم الزر [Submit] لتشغيل [PostBack] إلى الخادم. تكون النتيجة كما يلي:

نلاحظ أن مكون [DataGrid1] قد احتفظ بقيمته، ولكن مكون [DataGrid2] لم يحتفظ بها. التفسير:
- حتى قبل بدء إجراء [Page_Load]، استرجع كائنا [DataGrid1] و[DataGrid2] القيم التي كانت لديهما أثناء الطلب السابق، وذلك بفضل آلية [viewstate]. في الواقع، تم تعيين خاصية [EnableViewState] لكليهما على [true].
- يتم تشغيل الإجراء [Page_Load]. ونظرًا لأن هذه عملية [PostBack]، لا يتم تعديل المكون [DataGrid1] بواسطة [Page_Load] (انظر الكود). وبالتالي، فإنه يحتفظ بالقيمة التي تم استردادها عبر [viewstate]. وهذا ما تظهره الشاشة أعلاه.
- من ناحية أخرى، فإن مكون [DataGrid2] مرتبط عبر [DataBind] بمصدر البيانات [DataGrid1.DataSource]. وبالتالي، يتم إعادة بنائه، وتُفقد القيمة التي كان قد استردها للتو عبر [viewstate]. ولذلك، كان من الأفضل هنا تعيين خاصية [EnableViewState] الخاصة به على [false] لتجنب إدارة الحالة غير الضرورية. تُظهر الشاشة أعلاه أن [DataGrid2] قد تم ربطه بمصدر فارغ. وبما أن هذا المصدر هو [DataGrid1.DataSource]، يمكننا أن نستنتج أنه في حين أن آلية [viewstate] تعيد عرض مكون [DataGrid1] بنجاح، فإنها لا تعيد خصائصه مثل [DataSource].
ما الذي يمكننا استنتاجه من هذا المثال؟ يجب تجنب تعيين خاصية [EnableViewState] لحاوية البيانات على [true] إذا كانت تحتاج إلى الربط (DataBind) بمصدر بيانات في كل طلب. ومع ذلك، هناك حالات معينة حيث، حتى في هذا السيناريو، يجب أن تظل خاصية [EnableViewState] للحاوية مضبوطة على [true]؛ وإلا، فلن يتم تشغيل الأحداث التي ترغب في معالجتها. سنرى مثالاً على ذلك لاحقًا.
في كثير من الأحيان، يتغير مصدر بيانات حاوية البيانات خلال الطلبات. لذلك، يجب ربط الحاوية بمصدر البيانات في كل طلب. من الشائع أن يكون نطاق مصدر البيانات محددًا بالجلسة حتى تتمكن الطلبات من الوصول إليه. يوضح المثال الثاني هذه الآلية. يوفر التطبيق عرضًا واحدًا فقط:
![]() |
لا. | name | النوع | الخصائص | الدور |
1 | DataGrid | EnableViewState=true | يعرض مصدر بيانات S | |
2 | DataGrid | EnableViewState=false | يعرض مصدر البيانات S نفسه مثل [DataGrid1] | |
3 | زر | EnableViewState=false | زر [submit] | |
4 | تسمية | EnableViewState=false | نص المعلومات |
يتم ربط مكون [DataGrid1] بالبيانات فقط أثناء الطلب الأول. وسيحتفظ بقيمته عبر الطلبات بفضل آلية [viewstate]. يتم ربط مكون [DataGrid2] بمصدر بيانات مع كل طلب، حيث تتم إضافة عنصر إليه مع كل طلب جديد. لذلك، يجب ربط مكون [DataGrid2] (DataBind) مع كل طلب. لذلك قمنا بتعيين سمة [EnableViewState] الخاصة به على [false] كما أوصينا سابقًا. وبالتالي، أثناء الطلب الثاني (باستخدام الزر [Submit])، نحصل على الاستجابة التالية:

احتفظ مكون [DataGrid1] بقيمته الأولية. يحتوي مكون [DataGrid2] على عنصر إضافي. تمثل القيم الثلاث [1,2,2] رقم الاستعلام. يمكننا ملاحظة أن إحدى القيم غير صحيحة. سنحاول فهم السبب.
فيما يلي كود العرض الخاص بالتطبيق [main.aspx]:
<%@ Page src="main.aspx.vb" inherits="main" autoeventwireup="false" Language="vb" %>
<HTML>
<HEAD>
<title></title>
</HEAD>
<body>
<form runat="server">
<table>
<tr>
<td align="center" bgColor="#ccffcc">DataGrid 1</td>
<td align="center" bgColor="#ffff99">DataGrid 2</td>
</tr>
<tr>
<td vAlign="top">
<asp:DataGrid id="DataGrid1" runat="server" ...>
...
</asp:DataGrid>
</td>
<td vAlign="top">
<asp:DataGrid id="Datagrid2" runat="server" ... EnableViewState="False">
....
</asp:DataGrid>
</td>
</tr>
</table>
<P>Numéro de requête :
<asp:Label id="lblInfo1" runat="server" EnableViewState="False"></asp:Label>,
<asp:Label id="lblInfo2" runat="server" EnableViewState="False"></asp:Label>,
<asp:Label id="lblInfo3" runat="server" EnableViewState="False"></asp:Label></P>
<P>
<asp:Button id="Button1" runat="server" Text="Envoyer" EnableViewState="False"></asp:Button></P>
</form>
</body>
</HTML>
رمز وحدة التحكم [main.aspx.vb] هو كما يلي:
Imports System.Data
Imports System
Public Class main
Inherits System.Web.UI.Page
Protected WithEvents DataGrid1 As System.Web.UI.WebControls.DataGrid
Protected WithEvents Datagrid2 As System.Web.UI.WebControls.DataGrid
Protected WithEvents Button1 As System.Web.UI.WebControls.Button
Protected WithEvents lblInfo1 As System.Web.UI.WebControls.Label
Protected WithEvents lblInfo2 As System.Web.UI.WebControls.Label
Protected WithEvents lblInfo3 As System.Web.UI.WebControls.Label
Dim dtThèmes As DataTable
Dim numRequête1 As Integer
Dim numRequête2 As Integer
Dim numRequête3 As New entier
Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
' on the 1st query, the data source is defined and linked to the 1st datagrid
If Not IsPostBack Then
'define data source
dtThèmes = createDataSource()
With DataGrid1
.DataSource = dtThèmes
.DataBind()
End With
' store information in the session
Session("source") = dtThèmes
numRequête1 = 0 : Session("numRequête1") = numRequête1
numRequête2 = 0 : Session("numRequête2") = numRequête2
numRequête3.valeur = 0 : Session("numRequête3") = numRequête3
End If
' a new theme is added to each query
dtThèmes = CType(Session("source"), DataTable)
Dim nbThèmes = dtThèmes.Rows.Count
Dim ligne As DataRow = dtThèmes.NewRow
With ligne
.Item("id") = nbThèmes.ToString
.Item("thème") = "thème" + nbThèmes.ToString
.Item("description") = "description du thème " + nbThèmes.ToString
End With
dtThèmes.Rows.Add(ligne)
'links datagrid2 with the data source
With Datagrid2
.DataSource = dtThèmes
.DataBind()
End With
' info no. of requests
numRequête1 = CType(Session("numRequête1"), Integer)
numRequête1 += 1
lblInfo1.Text = numRequête1.ToString
numRequête2 = CType(Session("numRequête2"), Integer)
numRequête2 += 1
lblInfo2.Text = numRequête2.ToString
numRequête3 = CType(Session("numRequête3"), entier)
numRequête3.valeur += 1
lblInfo3.Text = numRequête3.valeur.ToString
' store some information in the session
Session("numRequête2") = numRequête2
End Sub
Private Function createDataSource() As DataTable
....
End Function
End Class
Public Class entier
Private _valeur As Integer
Public Property valeur() As Integer
Get
Return _valeur
End Get
Set(ByVal Value As Integer)
_valeur = Value
End Set
End Property
End Class
لم نقم بإعادة إنتاج الكود الخاص بالطريقة [createDataSource]. فهو مطابق لما هو موجود في التطبيق السابق، باستثناء أن الكود المصدري يتضمن ثلاثة أسطر فقط. دعونا أولاً نلقي نظرة على كيفية إدارة مصدر البيانات والحاويتين:
Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
' on the 1st query, the data source is defined and linked to the 1st datagrid
If Not IsPostBack Then
'define data source
dtThèmes = createDataSource()
With DataGrid1
.DataSource = dtThèmes
.DataBind()
End With
' store information in the session
Session("source") = dtThèmes
...
End If
' a new theme is added to each query
dtThèmes = CType(Session("source"), DataTable)
Dim nbThèmes = dtThèmes.Rows.Count
Dim ligne As DataRow = dtThèmes.NewRow
With ligne
.Item("id") = nbThèmes.ToString
.Item("thème") = "thème" + nbThèmes.ToString
.Item("description") = "description du thème " + nbThèmes.ToString
End With
dtThèmes.Rows.Add(ligne)
'links datagrid2 with the data source
With Datagrid2
.DataSource = dtThèmes
.DataBind()
End With
...
End Sub
يتم ربط المكون [DataGrid1] بمصدر البيانات S فقط أثناء الاستعلام الأول (ليس IsPostBack). ثم يتم وضعه في الجلسة. ولن يتم وضعه هناك مرة أخرى بعد ذلك. يتم استرداد مصدر البيانات S الموضوع في الجلسة مع كل طلب، ويتم إضافة صف جديد إليه. يتم ربط المكون [DataGrid2] بشكل صريح بمصدر S مع كل طلب. وهذا هو السبب في أن محتواه يزداد بصف واحد مع كل طلب. لاحظ أنه بعد تعديل محتوى المصدر S، لا يتم وضعه صراحةً مرة أخرى في الجلسة عبر عملية:
لماذا؟ عند بدء الاستعلام، تحتوي الجلسة على كائن Session("source") من النوع [DataTable]، وهو مصدر البيانات كما كان خلال الاستعلام الأخير. لنسمي كائن Session("source") بـ S. عندما نكتب:
dtThèmes = CType(Session("source"), DataTable)
[dtThèmes] و [S] هما مرجعان لنفس كائن [DataTable]. وبالتالي، عندما يضيف الكود في [Page_Load] عنصرًا إلى الجدول المشار إليه بواسطة [dtThèmes]، فإنه يضيفه في الوقت نفسه إلى الجدول المشار إليه بواسطة [S]. في نهاية تنفيذ الصفحة، سيتم حفظ جميع الكائنات الموجودة في الجلسة، بما في ذلك كائن Session("source")، أي S، أي [dtThemes]. وبالتالي، فإن المحتوى الجديد لمصدر البيانات هو الذي يتم حفظه بالفعل. لم تكن هناك حاجة لكتابة:
لإجراء هذا الحفظ، لأن Session("source") يساوي بالفعل [dtThèmes]. لم يعد هذا صحيحًا عندما لا تكون البيانات الموضوعة في الجلسة كائنات، مثل الهياكل [Integer، Float، ...]. ويتضح ذلك من خلال إدارة عداد الاستعلامات:
Dim numRequête1 As Integer
Dim numRequête2 As Integer
Dim numRequête3 As New entier
Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
' on the 1st query, the data source is defined and linked to the 1st datagrid
....
' store information in the session
Session("source") = dtThèmes
numRequête1 = 0 : Session("numRequête1") = numRequête1
numRequête2 = 0 : Session("numRequête2") = numRequête2
numRequête3.valeur = 0 : Session("numRequête3") = numRequête3
End If
' a new theme is added to each query
....
' info no. of requests
numRequête1 = CType(Session("numRequête1"), Integer)
numRequête1 += 1
lblInfo1.Text = numRequête1.ToString
numRequête2 = CType(Session("numRequête2"), Integer)
numRequête2 += 1
lblInfo2.Text = numRequête2.ToString
numRequête3 = CType(Session("numRequête3"), entier)
numRequête3.valeur += 1
lblInfo3.Text = numRequête3.valeur.ToString
' store some information in the session
Session("numRequête2") = numRequête2
End Sub
Private Function createDataSource() As DataTable
....
End Function
Private Sub InitializeComponent()
End Sub
End Class
Public Class entier
Private _valeur As Integer
Public Property valeur() As Integer
Get
Return _valeur
End Get
Set(ByVal Value As Integer)
_valeur = Value
End Set
End Property
نقوم بتخزين عدادات الطلبات في ثلاثة عناصر:
- numRequest1 و numRequest2 من النوع [Integer] - [Integer] ليس فئة بل بنية
- numRequest3 من النوع [integer] - [integer] هي فئة محددة لهذا الغرض
عندما نكتب:
numRequête1 = CType(Session("numRequête1"), Integer)
..
numRequête2 = CType(Session("numRequête2"), Integer)
..
numRequête3 = CType(Session("numRequête3"), entier)
..
- يتم نسخ البنية [Session("numRequest1")] إلى [numRequest1]. وبالتالي، عند تعديل العنصر [numRequest1]، لا يتم تعديل العنصر [Session("numRequest1")] نفسه
- وينطبق الأمر نفسه على [Session("numRequest2")] و [numRequest2]
- العنصران [Session("numRequête3")] و [numRequête3] كلاهما إشارات إلى نفس الكائن من النوع [integer]. يمكن تعديل الكائن المشار إليه بواسطة أي من الإشارتين.
من هذا، يمكننا أن نستنتج أنه ليس من الضروري كتابة:
لتخزين القيمة الجديدة لـ [numRequest3] في الجلسة. بدلاً من ذلك، يجب كتابة:
لتخزين القيم الجديدة للبنيتين [numRequête1] و [numRequête2]. نقوم بذلك فقط بالنسبة لـ [numRequête2]، وهو ما يفسر سبب عدم صحة العداد [numRequête1] في لقطة الشاشة التي تم الحصول عليها بعد الاستعلام الثاني.
لذلك، يجب ملاحظة أنه بمجرد إضافة البيانات إلى الجلسة، لا يلزم إضافتها مرارًا وتكرارًا إذا كانت ممثلة بكائن. وفي الحالات الأخرى، يجب إضافتها إذا تم تعديلها.
8.6. عرض قائمة بالبيانات باستخدام DataGrid مقسمة إلى صفحات ومرتبة
يتيح لك مكون [DataGrid] عرض محتويات [DataSet]. حتى الآن، كنا نبني [DataSets] "يدويًا" دائمًا. هذه المرة، نستخدم [DataSet] من قاعدة بيانات. نحن نبني تطبيق MVC التالي:
![]() |
سيتم دمج العروض الثلاثة في كود العرض الخاص بوحدة التحكم [main.aspx] كحاويات. لذلك، يحتوي هذا التطبيق على صفحة واحدة، [main.aspx].
8.6.1. فئات الأعمال
توفر فئة [products] الوصول إلى قاعدة بيانات ACCESS التالية:

فيما يلي كود فئة [products]:
Imports System
Imports System.Data
Imports System.Data.OleDb
Imports System.Xml
Namespace st.istia.univangers.fr
Public Class produits
Private chaineConnexionOLEDB As String
Public Sub New(ByVal chaineConnexionOLEDB As String)
' save the connection string
Me.chaineConnexionOLEDB = chaineConnexionOLEDB
End Sub
Public Function getDataSet(ByVal commande As String) As DataSet
' create a DataAdapter object to read data from source OLEDB
Dim adaptateur As New OleDbDataAdapter(commande, chaineConnexionOLEDB)
' create a memory image of the select result
Dim contenu As New DataSet
Try
adaptateur.Fill(contenu)
Catch e As Exception
Throw New Exception("Erreur d'accès à la base de données (" + e.Message + ")")
End Try
' we return the result
Return contenu
End Function
End Class
End Namespace
سيتم إدارة قاعدة بيانات ACCESS عبر برنامج تشغيل OLEDB. نزود منشئ فئة [products] بسلسلة الاتصال وبرنامج تشغيل OLEDB وقاعدة البيانات المراد إدارتها. تحتوي فئة [products] على طريقة [getDataSet] التي تُرجع [DataSet] تم الحصول عليها عن طريق تنفيذ استعلام SQL [select] الذي يتم تمرير نصه كمعلمة. أثناء الطريقة، تتم عدة عمليات: إنشاء الاتصال بقاعدة البيانات، وتنفيذ استعلام [select]، وإغلاق الاتصال. كل هذا يمكن أن يولد استثناءً، يتم التعامل معه هنا. قد يبدو برنامج الاختبار كما يلي:
Option Explicit On
Option Strict On
' namespaces
Imports System
Imports System.Data
Imports Microsoft.VisualBasic
Namespace st.istia.univangers.fr
' test pg
Module testproduits
Sub Main(ByVal arguments() As String)
' displays the contents of a product table
' the table is in a ACCESS database whose pg receives the file name
Const syntaxe1 As String = "pg bdACCESS"
' checking program parameters
If arguments.Length <> 1 Then
' error msg
Console.Error.WriteLine(syntaxe1)
' end
Environment.Exit(1)
End If
' prepare the connection chain
Dim chaineConnexion As String = "Provider=Microsoft.Jet.OLEDB.4.0; Ole DB Services=-4; Data Source=" + arguments(0)
' creation of a product object
Dim objProduits As produits = New produits(chaineConnexion)
' retrieve the product table from a dataset
Dim contenu As DataSet
Try
contenu = objProduits.getDataSet("select id,nom,prix from liste")
Catch ex As Exception
Console.Error.WriteLine(("L'erreur suivante s'est produite : " + ex.Message))
Environment.Exit(2)
End Try
' display its contents
Dim lignes As DataRowCollection = contenu.Tables(0).Rows
For i As Integer = 0 To lignes.Count - 1
' table line i
Console.Out.WriteLine(lignes(i).Item("id").ToString + "," + lignes(i).Item("nom").ToString + _
"," + lignes(i).Item("prix").ToString)
Next
End Sub
End Module
End Namespace
يتم ترجمة المكونات المختلفة لهذا التطبيق على النحو التالي:
dos>vbc /t:library /r:system.dll /r:system.data.dll /r:system.xml.dll produits.vb
dos>vbc /r:produits.dll /r:system.data.dll /r:system.xml.dll /r:system.dll testproduits.vb
dos>dir
06/05/2004 16:52 118 784 produits.mdb
07/05/2004 11:07 902 produits.vb
07/04/2004 07:01 1 532 testproduits.vb
07/05/2004 14:21 3 584 produits.dll
07/05/2004 14:22 4 608 testproduits.exe
dos>testproduits produits.mdb
1,produit1,10
2,produit2,20
3,produit3,30
8.6.2. طرق العرض
الآن بعد أن أصبح لدينا فئة الوصول إلى البيانات، سنقوم بكتابة وحدات التحكم وطرق العرض لهذا التطبيق الويب. دعونا أولاً نرى كيف يعمل. طريقة العرض الأولى هي كما يلي:
![]() |
رقم | الاسم | النوع | الخصائص | الدور |
1 | مربع نص | EnableViewState=true | حقل إدخال استعلام الاختيار | |
2 | RequiredFieldValidator | EnableViewState=false | يتحقق من وجود 1 | |
3 | TextBox | EnableViewState=true | حقل الإدخال - يحدد عدد صفوف البيانات المراد عرضها في كل صفحة نتائج | |
4 | RequiredFieldValidator | EnableViewState=false | يتحقق من وجود 3 | |
5 | RangeValidator | EnableViewState=false | يتحقق من أن (3) يقع في النطاق [1,30] | |
6 | زر | EnableViewState=false | زر [submit] |
سنسمي هذا العرض عرض [form]. وهو يسمح للمستخدم بتنفيذ استعلام SQL SELECT على قاعدة البيانات [products.mdb]. يؤدي تنفيذ الاستعلام إلى إنشاء عرض جديد:
![]() |
لا | الاسم | النوع | الخصائص | الدور |
1 | تسمية | EnableViewState=false | حقل المعلومات | |
2 | زر الاختيار | EnableViewState=false GroupName=rdSort | يتيح لك اختيار ترتيب الفرز | |
3 | DataGrid | EnableViewState=true AllowPaging=true AllowSorting=true | جدول يعرض نتائج عملية الاختيار | |
4 | زر الارتباط | EnableViewState=false | [submit] |
سنسمي هذه العرض [results]. وهي تحتوي على [DataGrid] الذي سيعرض نتائج عبارة SQL SELECT. قد يرتكب المستخدم خطأ في استعلامه. سيتم إبلاغه ببعض الأخطاء في عرض [errors] بفضل عناصر التحكم في التحقق من الصحة.

سيتم إبلاغه بالأخطاء الأخرى من خلال عرض [errors]:

يتم عرض عرض [errors]:
![]() |
لا | الاسم | النوع | الخصائص | الدور |
1 | المتغير | كود HTML المطلوب لعرض الأخطاء | ||
3 | زر الارتباط | EnableViewState=false | زر [submit] |
تمثل طرق العرض الثلاثة للتطبيق ثلاثة حاويات (لوحات) مختلفة داخل نفس الصفحة [main.aspx]. وفيما يلي كود العرض الخاص بها:
<%@ Page src="main.aspx.vb" inherits="main" autoeventwireup="false" Language="vb" %>
<HTML>
<HEAD>
</HEAD>
<body>
<P>Liaison de données avec un DataGrid</P>
<HR width="100%" SIZE="1">
<form runat="server">
<asp:panel id="vueFormulaire" runat="server">
<P>Commande [select] à exécuter sur la table LISTE</P>
<P> Exemple : select id, nom, prix from LISTE
</P>
<P>
<asp:TextBox id="txtSelect" runat="server" Columns="60"></asp:TextBox></P>
<P>
<asp:RequiredFieldValidator id="RequiredFieldValidator1" runat="server" EnableViewState="False" EnableClientScript="False"
ErrorMessage="Indiquez la requête [select] à exécuter" ControlToValidate="txtSelect" Display="Dynamic"></asp:RequiredFieldValidator></P>
<P>Nombre de lignes par page :
<asp:TextBox id="txtPages" runat="server" Columns="3"></asp:TextBox></P>
<P>
<asp:RequiredFieldValidator id="RequiredFieldValidator2" runat="server" EnableViewState="False" EnableClientScript="False"
ErrorMessage="Indiquez le nombre de lignes par page désirées" ControlToValidate="txtPages" Display="Dynamic"></asp:RequiredFieldValidator>
<asp:RangeValidator id="RangeValidator1" runat="server" EnableViewState="False" EnableClientScript="False"
ErrorMessage="Vous devez indiquer un nombre entre 1 et 30" ControlToValidate="txtPages" Display="Dynamic"
Type="Integer" MinimumValue="1" MaximumValue="30"></asp:RangeValidator></P>
<P>
<asp:Button id="btnExécuter" runat="server" EnableViewState="False" Text="Exécuter"></asp:Button></P>
</asp:panel>
<asp:Panel id="vueRésultats" runat="server">
<P>Résultats de la requête
<asp:Label id="lblSelect" runat="server"></asp:Label></P>
<P>Tri
<asp:RadioButton id="rdCroissant" runat="server" Text="croissant" Checked="True" GroupName="rdTri"></asp:RadioButton>
<asp:RadioButton id="rdDécroissant" runat="server" Text="décroissant" GroupName="rdTri"></asp:RadioButton></P>
<P>
<asp:DataGrid id="DataGrid1" runat="server" BorderColor="#CC9966" BorderStyle="None" BorderWidth="1px"
BackColor="White" CellPadding="4" AllowPaging="True" PageSize="4" AllowSorting="True">
<SelectedItemStyle Font-Bold="True" ForeColor="#663399" BackColor="#FFCC66"></SelectedItemStyle>
<ItemStyle ForeColor="#330099" BackColor="White"></ItemStyle>
<HeaderStyle Font-Bold="True" ForeColor="#FFFFCC" BackColor="#990000"></HeaderStyle>
<FooterStyle ForeColor="#330099" BackColor="#FFFFCC"></FooterStyle>
<PagerStyle NextPageText="Suivant" PrevPageText="Précédent" HorizontalAlign="Center"
ForeColor="#330099" BackColor="#FFFFCC"></PagerStyle>
</asp:DataGrid></P>
<P>
<asp:LinkButton id="lnkRésultats" runat="server" EnableViewState="False">Retour au formulaire</asp:LinkButton></P>
</asp:Panel>
<asp:Panel id="vueErreurs" runat="server">
<P>Les erreurs suivantes se sont produites :</P>
<% =erreursHTML %>
<P>
<asp:LinkButton id="lnkErreurs" runat="server" EnableViewState="False">Retour vers le formulaire</asp:LinkButton></P>
</asp:Panel>
</form>
</body>
</HTML>
8.6.3. تكوين DataGrid
دعونا نلقي نظرة فاحصة على ترقيم الصفحات لمكون [DataGrid]، وهي ميزة نواجهها لأول مرة. في الكود أعلاه، يتم التحكم في ترقيم الصفحات هذا بواسطة السمات التالية:
<asp:DataGrid id="DataGrid1" runat="server" PageSize="4" AllowPaging="True" ...>
...
<PagerStyle NextPageText="Suivant" PrevPageText="Précédent" ...></PagerStyle>
</asp:DataGrid></P>
تمكين ترقيم الصفحات | |
أربعة صفوف من البيانات لكل صفحة | |
نص الرابط للانتقال إلى الصفحة التالية من مصدر البيانات | |
نص الرابط للانتقال إلى الصفحة السابقة لمصدر البيانات |
يمكن إدخال هذه المعلومات مباشرة في سمات العلامة <asp:datagrid>. يمكنك أيضًا استخدام [WebMatrix]. في نافذة خصائص [DataGrid]، انقر فوق الارتباط [Property Generator]:

يظهر المعالج التالي:

حدد الخيار [Pagination]:

أعلاه، نرى قيم سمات ترقيم الصفحات لـ [DataGrid] في كود العرض.
بالإضافة إلى ذلك، نتيح فرز البيانات في أحد أعمدة [DataGrid]. وهناك عدة طرق للقيام بذلك. إحدى هذه الطرق هي تعيين الخاصية [AllowSorting=true] في نافذة خصائص [DataGrid]. كما يمكنك استخدام مُنشئ الخصائص. وبغض النظر عن الطريقة المستخدمة، فإن ذلك يؤدي إلى ظهور السمة [AllowSorting=true] في علامة <asp:DataGrid> الخاصة بالمكون:
<asp:DataGrid id="DataGrid1" runat="server" ... AllowPaging="True" PageSize="4" AllowSorting="True">
8.6.4. وحدات التحكم
وحدة التحكم [global.asax, global.asax.vb] هي كما يلي:
[global.asax]
[global.asax.vb]
Imports st.istia.univangers.fr
Imports System.Configuration
Public Class Global
Inherits System.Web.HttpApplication
Sub Application_Start(ByVal sender As Object, ByVal e As EventArgs)
' create a product object
Dim objProduits As produits
Try
objProduits = New produits(ConfigurationSettings.AppSettings("OLEDBStringConnection"))
' put the object in the application
Application("objProduits") = objProduits
' no error
Application("erreur") = False
Catch ex As Exception
'there has been an error, we note it in the application
Application("erreur") = True
Application("message") = ex.Message
End Try
End Sub
End Class
عند بدء تشغيل التطبيق (Application_Start)، نقوم بإنشاء كائن [products] وتخزينه في التطبيق بحيث يكون متاحًا لجميع الطلبات الواردة من جميع العملاء. إذا حدث استثناء أثناء هذا الإنشاء، يتم تسجيله في التطبيق. لن يتم تشغيل الإجراء [Application_Start] سوى مرة واحدة. بعد ذلك، لن يكون وحدة التحكم [global.asax] معنية بالأمر. ستتولى وحدة التحكم [main.aspx.vb] الباقي بعد ذلك:
Imports System.Collections
Imports Microsoft.VisualBasic
Imports System.Data
Imports st.istia.univangers.fr
Imports System
Imports System.Xml
Public Class main
Inherits System.Web.UI.Page
' components page
Protected WithEvents txtSelect As System.Web.UI.WebControls.TextBox
Protected WithEvents RequiredFieldValidator1 As System.Web.UI.WebControls.RequiredFieldValidator
Protected WithEvents txtPages As System.Web.UI.WebControls.TextBox
Protected WithEvents RequiredFieldValidator2 As System.Web.UI.WebControls.RequiredFieldValidator
Protected WithEvents RangeValidator1 As System.Web.UI.WebControls.RangeValidator
Protected WithEvents btnExécuter As System.Web.UI.WebControls.Button
Protected WithEvents vueFormulaire As System.Web.UI.WebControls.Panel
Protected WithEvents lblSelect As System.Web.UI.WebControls.Label
Protected WithEvents DataGrid1 As System.Web.UI.WebControls.DataGrid
Protected WithEvents lnkRésultats As System.Web.UI.WebControls.LinkButton
Protected WithEvents vueRésultats As System.Web.UI.WebControls.Panel
Protected WithEvents lnkErreurs As System.Web.UI.WebControls.LinkButton
Protected WithEvents vueErreurs As System.Web.UI.WebControls.Panel
Protected WithEvents rdCroissant As System.Web.UI.WebControls.RadioButton
Protected WithEvents rdDécroissant As System.Web.UI.WebControls.RadioButton
' data page
Protected erreursHTML As String
Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
' check for application errors
If CType(Application("erreur"), Boolean) Then
' the application has not initialized correctly
Dim erreurs As New ArrayList
erreurs.Add("Application momentanément indisponible (" + CType(Application("message"), String) + ")")
afficheErreurs(erreurs, False)
Exit Sub
End If
'1st request
If Not IsPostBack Then
' the empty form is displayed
afficheFormulaire()
End If
End Sub
Private Sub afficheErreurs(ByVal erreurs As ArrayList, ByVal afficheLien As Boolean)
' displays the error view
erreursHTML = ""
For i As Integer = 0 To erreurs.Count - 1
erreursHTML += "<li>" + erreurs(i).ToString + "</li>" + ControlChars.CrLf
Next
lnkErreurs.Visible = afficheLien
' the [errors] view is displayed
vueErreurs.Visible = True
vueFormulaire.Visible = False
vueRésultats.Visible = False
End Sub
Private Sub afficheFormulaire()
' the [form] view is displayed
vueFormulaire.Visible = True
vueErreurs.Visible = False
vueRésultats.Visible = False
End Sub
Private Sub afficheRésultats(ByVal sqlTexte As String, ByVal données As DataView)
' initialize controls
lblSelect.Text = sqlTexte
With DataGrid1
.DataSource = données
.PageSize = CType(txtPages.Text, Integer)
.CurrentPageIndex = 0
.DataBind()
End With
' the [results] view is displayed
vueRésultats.Visible = True
vueFormulaire.Visible = False
vueErreurs.Visible = False
End Sub
Private Sub btnExécuter_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnExécuter.Click
' valid page?
If Not Page.IsValid Then
afficheFormulaire()
Exit Sub
End If
' execute query SELECT customer
Dim données As DataView
Try
données = CType(Application("objProduits"), produits).getDataSet(txtSelect.Text.Trim).Tables(0).DefaultView
Catch ex As Exception
Dim erreurs As New ArrayList
erreurs.Add("erreur d'accès à la base de données (" + ex.Message + ")")
afficheErreurs(erreurs, True)
Exit Sub
End Try
' all's well - the results are in
afficheRésultats(txtSelect.Text.Trim, données)
' put the data in the session
Session("données") = données
End Sub
Private Sub retourFormulaire(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles lnkErreurs.Click, lnkRésultats.Click
' set of views
vueErreurs.Visible = False
vueFormulaire.Visible = True
vueRésultats.Visible = False
End Sub
Private Sub DataGrid1_PageIndexChanged(ByVal source As Object, ByVal e As System.Web.UI.WebControls.DataGridPageChangedEventArgs) Handles DataGrid1.PageIndexChanged
' change page
With DataGrid1
.CurrentPageIndex = e.NewPageIndex
.DataSource = CType(Session("données"), DataView)
.DataBind()
End With
End Sub
Private Sub DataGrid1_SortCommand(ByVal source As Object, ByVal e As System.Web.UI.WebControls.DataGridSortCommandEventArgs) Handles DataGrid1.SortCommand
' sort the dataview
Dim données As DataView = CType(Session("données"), DataView)
données.Sort = e.SortExpression + " " + CType(IIf(rdCroissant.Checked, "asc", "desc"), String)
' we display it
With DataGrid1
.CurrentPageIndex = 0
.DataSource = données
.DataBind()
End With
End Sub
End Class
عندما يتم تحميل الصفحة [Page_Load]، نتحقق أولاً مما إذا كان التطبيق قادراً على التهيئة بشكل صحيح. إذا لم يكن الأمر كذلك، فإننا نعرض طريقة العرض [errors] بدون رابط للعودة إلى النموذج، لأن هذا الرابط يصبح غير ضروري في هذه الحالة. في الواقع، لا يمكن عرض سوى طريقة العرض [errors] إذا لم يتمكن التطبيق من التهيئة بشكل صحيح. بخلاف ذلك، نعرض طريقة العرض [form] إذا كان هذا هو الطلب الأول للعميل. بالنسبة للباقي، نترك للقارئ مهمة فهم الكود. سنركز فقط على ثلاثة إجراءات: إجراء [btnExecute_Click]، الذي يتم تشغيله عندما يطلب المستخدم تنفيذ استعلام SQL الذي تم إدخاله في عرض [form]، وإجراء [DataGrid1_PageIndexChanged]، الذي يتم تشغيله عندما يستخدم المستخدم رابطي [Next] و[Previous] في [DataGrid]، وإجراء [DataGrid1_SortCommand]، الذي يتم تشغيله عندما ينقر المستخدم على رأس عمود لفرز البيانات بهذا الترتيب. يتم تحديد ترتيب الفرز — تصاعدي أو تنازلي — بواسطة زري الاختيار الخاصين بالفرز.
في الإجراء [btnExécuter_Click]، نبدأ بالتالي بالتحقق مما إذا كانت الصفحة صالحة أم لا. عند تشغيل الإجراء [btnExécuter_Click]، تكون عمليات الفحص المتعلقة بعناصر التحكم المختلفة للتحقق من صحة الصفحة قد تم إجراؤها بالفعل. بالنسبة لكل عنصر تحكم للتحقق من الصحة، تم تعيين خاصيتين:
يتم تعيينها على true إذا كانت البيانات التي تم التحقق منها صالحة، وإلا يتم تعيينها على false | |
رسالة الخطأ إذا كانت البيانات التي تم التحقق منها غير صالحة |
بالنسبة للصفحة نفسها، تم تعيين سمة [IsValid]. تكون هذه السمة صحيحة فقط إذا تم تعيين سمة [IsValid] لجميع عناصر التحكم في التحقق إلى true. إذا لم يكن الأمر كذلك، يجب عرض طريقة العرض [form]. تحتوي طريقة العرض هذه على عناصر التحكم في التحقق من الصحة التي ستعرض السمة [errorMessage] الخاصة بها. إذا كانت الصفحة صالحة، نستخدم الكائن [products] الذي تم إنشاؤه بواسطة [Application_Start] للحصول على [DataSet] المطابق لتنفيذ استعلام SQL SELECT. نقوم بتحويل هذا إلى كائن [DataView]:
Dim données As DataView
Try
données = CType(Application("objProduits"), produits).getDataSet(txtSelect.Text.Trim).Tables(0).DefaultView
...
كان بإمكاننا ببساطة العمل مع [DataSet] وكتابة:
Dim données As DataSet
Try
données = CType(Application("objProduits"), produits).getDataSet(txtSelect.Text.Trim)
...
كائن [DataSet] هو في الأساس مجموعة من الجداول المرتبطة ببعضها عبر علاقات. في تطبيقنا هذا، يحتوي كائن [DataSet] المستمد من فئة [products] على جدول واحد فقط، وهو الجدول الناتج عن عبارة [select]. يمكن فرز الجدول، في حين لا يمكن فرز كائن [DataSet]؛ ومع ذلك، فإننا نرغب في فرز البيانات المسترجعة. للعمل مع جدول النتائج الناتج عن عبارة [select]، كان بإمكاننا كتابة ما يلي:
Dim données As DataTable
Try
données = CType(Application("objProduits"), produits).getDataSet(txtSelect.Text.Trim).Tables(0)
...
على الرغم من أن كائن [DataTable] يمثل جدول قاعدة بيانات، إلا أنه لا يحتوي على طريقة فرز. للقيام بذلك، تحتاج إلى عرض للجدول. العرض هو كائن من النوع [DataView]. يمكنك الحصول على عروض مختلفة لنفس الجدول باستخدام عوامل التصفية. يحتوي الجدول على عرض افتراضي، وهو العرض الذي لم يتم تعريف أي عوامل تصفية له. وبالتالي، فهو يمثل الجدول بأكمله. يتم الحصول على هذا العرض الافتراضي عبر [DataTable.DefaultView]. يمكنك فرز عرض باستخدام خاصية [sort] الخاصة به، والتي سنناقشها لاحقًا.
إذا نجح استرداد [DataSet] من فئة [products]، يتم عرض عرض [results]؛ وإلا، يتم عرض عرض [errors]. يتم عرض عرض [results] عبر الإجراء [displayResults]، الذي يتم تمرير معلمتين إليه:
- النص المراد وضعه في التسمية [lblSelect]
- [DataView] لربطه بـ [DataGrid1]
يوضح هذا المثال المرونة الكبيرة لمكون [DataGrid]. يمكنه التعرف على بنية [DataView] المرتبطة به والتكيف معها. أخيرًا، يقوم الإجراء [btnExécuter_Click] بتخزين [DataView] الذي حصل عليه للتو في جلسة عمل المستخدم بحيث يكون متاحًا عندما يطلب المستخدم صفحات أخرى من نفس [DataView].
يتم تنفيذ الإجراء [DataGrid1_PageIndexChanged] عندما ينقر المستخدم على الروابط [Next] و [Previous] في [DataGrid]. ويتلقى معلمتين:
Private Sub DataGrid1_PageIndexChanged(ByVal source As Object, ByVal e As System.Web.UI.WebControls.) Handles DataGrid1.PageIndexChanged
الكائن الذي أطلق الحدث — في هذه الحالة، أحد الرابطين [Next] أو [Previous] | |
معلومات حول الحدث. الخاصية e.NewPageIndex هي رقم الصفحة المراد عرضها استجابة لطلب العميل |
فيما يلي الكود الكامل لمعالج الحدث:
Private Sub DataGrid1_PageIndexChanged(ByVal source As Object, ByVal e As System.Web.UI.WebControls.DataGridPageChangedEventArgs) Handles DataGrid1.PageIndexChanged
' change page
With DataGrid1
.CurrentPageIndex = e.NewPageIndex
.DataSource = CType(Session("données"), DataView)
.DataBind()
End With
End Sub
يحتوي مكون [DataGrid] على سمة [CurrentPageIndex] التي تشير إلى رقم الصفحة التي يعرضها أو سيعرضها. نقوم بتعيين قيمة [NewPageIndex] للمعلمة [e] لهذه السمة. ثم يتم ربط [DataGrid] بـ [DataView] الذي تم حفظه في الجلسة بواسطة الإجراء [btnExécuter_Click].
قد يتساءل المرء عما إذا كان [DataGrid] يحتاج إلى السمة [EnableViewState=true] نظرًا لأن محتواه يتم حسابه بواسطة الكود في كل مرة يتم فيها إعادة تحميل الصفحة. قد يعتقد المرء أن الإجابة هي لا. ومع ذلك، إذا كان [DataGrid] يحتوي على السمة [EnableViewState=false]، فإننا نلاحظ أن الحدث [DataGrid1.PageIndexChanged] لا يتم تشغيله أبدًا. ولهذا السبب تركنا [EnableViewState=true]. نحن نعلم أن هذا يؤدي إلى تخزين محتوى [DataGrid] في الحقل المخفي للصفحة [__VIEWSTATE]. وهذا يمكن أن يبطئ الصفحة بشكل كبير إذا كان [DataGrid] كبير الحجم. إذا كان هذا يمثل مشكلة، يمكنك إدارة ترقيم الصفحات بنفسك دون استخدام الترقيم التلقائي لـ [DataGrid].
يتم تنفيذ الإجراء [DataGrid1_SortCommand] عندما ينقر المستخدم على رأس أحد الأعمدة المعروضة بواسطة [DataGrid] لطلب فرز البيانات حسب ترتيب ذلك العمود. ويتلقى معلمتين:
Private Sub DataGrid1_SortCommand(ByVal source As Object, ByVal e As System.Web.UI.WebControls.DataGridSortCommandEventArgs) Handles DataGrid1.SortCommand
الكائن الذي أطلق الحدث — في هذه الحالة، أحد الروابط [Next] أو [Previous] | |
معلومات حول الحدث. الخاصية [e.SortExpression] هي اسم العمود الذي تم النقر عليه للفرز |
فيما يلي الكود الكامل لمعالج الحدث:
Private Sub DataGrid1_SortCommand(ByVal source As Object, ByVal e As System.Web.UI.WebControls.DataGridSortCommandEventArgs) Handles DataGrid1.SortCommand
' sort the dataview
Dim données As DataView = CType(Session("données"), DataView)
données.Sort = e.SortExpression + " " + CType(IIf(rdCroissant.Checked, "asc", "desc"), String)
' we display it
With DataGrid1
.CurrentPageIndex = 0
.DataSource = données
.DataBind()
End With
End Sub
نسترد [DataView] المعروض بواسطة [DataGrid] في الجلسة الحالية. وقد تم وضعه هناك بواسطة الإجراء [btnExécuter_Click]. يحتوي مكون [DataView] على خاصية [Sort] التي نخصص لها تعبير الفرز. ويتم ذلك وفقًا لصيغة [select ... order by expr1, expr2, ...]، حيث يمكن أن يتبع كل [expr] الكلمة الرئيسية [asc] للفرز التصاعدي أو [desc] للفرز التنازلي. تعبير [order by] المستخدم هنا هو [order by column asc/desc]. تمنحنا الخاصية [e.SortExpression] اسم عمود [DataGrid] الذي تم النقر عليه للفرز. يتم تعيين السلسلة [asc/desc] بناءً على قيم أزرار الاختيار في المجموعة [rdTri]. بمجرد تعيين تعبير الفرز لـ [DataView]، يتم ربط [DataGrid] به. نضع [DataGrid] في صفحته الأولى.
8.7. مكون DataList وربط البيانات
سنركز الآن على مكون [DataList]. يوفر هذا المكون خيارات تنسيق أكثر من [DataGrid] ولكنه أقل مرونة. وبالتالي، لا يمكنه التكيف تلقائيًا مع مصدر البيانات المرتبط به. يجب إجراء هذا التكيف عبر الكود إذا رغبت في ذلك. إذا كانت بنية مصدر البيانات معروفة مسبقًا، فإن هذا المكون يوفر خيارات تنسيق قد تجعله مفضلًا على [DataGrid].
8.7.1. التطبيق
لتوضيح استخدام [DataList]، سنقوم بإنشاء تطبيق MVC مشابه للتطبيق السابق:
![]() |
سيتم دمج العروض الثلاثة في كود العرض الخاص بوحدة التحكم [main.aspx] كحاويات. وبالتالي، يحتوي هذا التطبيق على صفحة واحدة [main.aspx].
8.7.2. فئات الأعمال
فئة [products] هي نفسها كما كانت من قبل.
8.7.3. طرق العرض
عندما يقوم المستخدم بإرسال أول طلب إلى التطبيق، يرى طريقة العرض [results1] التالية:
![]() |
رقم | الاسم | النوع | الخصائص | الدور |
1 | زر الاختيار | EnableViewState=false | يتيح لك اختيار أحد نمطي [DataList] | |
2 | زر | EnableViewState=false | زر [submit] | |
3 | قائمة البيانات | EnableViewState=true | حقل عرض قائمة البيانات |
إذا اختار المستخدم النمط رقم 2، فسيظهر له عرض [results2] التالي:
![]() |
رقم | الاسم | النوع | الخصائص | الدور |
1 | قائمة البيانات | EnableViewState=true | حقل عرض قائمة البيانات |
تشير طريقة العرض [errors] إلى وجود مشكلة في الوصول إلى مصدر البيانات:
![]() |
رقم | الاسم | النوع | الخصائص | الدور |
1 | متغير | كود HTML المطلوب لعرض الأخطاء |
تمثل طرق العرض الثلاثة للتطبيق ثلاثة حاويات (لوحات) مختلفة داخل نفس الصفحة [main.aspx]. وفيما يلي كود العرض الخاص بها:
<%@ Page src="main.aspx.vb" inherits="main" autoeventwireup="false" Language="vb" %>
<HTML>
<HEAD>
</HEAD>
<body>
<P>Liaison de données avec un DataList</P>
<HR width="100%" SIZE="1">
<form runat="server" ID="Form1">
<asp:Panel Runat="server" ID="bandeau">
<P>Choisissez votre style :
<asp:RadioButton id="RadioButton1" runat="server" EnableViewState="False" Text="1" GroupName="rdstyle"
Checked="True"></asp:RadioButton>
<asp:RadioButton id="RadioButton2" runat="server" EnableViewState="False" Text="2" GroupName="rdstyle"></asp:RadioButton>
<asp:Button id="btnChanger" runat="server" EnableViewState="False" Text="Changer"></asp:Button></P>
<HR width="100%" SIZE="1">
</asp:Panel>
<asp:Panel id="vueRésultats1" runat="server">
<P>
<asp:DataList id="DataList1" runat="server" BorderColor="Tan" BorderWidth="1px" BackColor="LightGoldenrodYellow"
CellPadding="2" RepeatDirection="Horizontal" RepeatColumns="4" ForeColor="Black">
<SelectedItemStyle ForeColor="GhostWhite" BackColor="DarkSlateBlue"></SelectedItemStyle>
<HeaderTemplate>
Contenu de la table [liste] de la base [produits]
</HeaderTemplate>
<AlternatingItemStyle BackColor="PaleGoldenrod"></AlternatingItemStyle>
<ItemTemplate>
nom :
<%# Container.DataItem("nom") %>
<br>
prix :
<%# databinder.eval(Container.DataItem,"prix","{0:C}") %>
<br>
</ItemTemplate>
<FooterStyle BackColor="Tan"></FooterStyle>
<HeaderStyle Font-Bold="True" BackColor="Tan"></HeaderStyle>
</asp:DataList></P>
</asp:Panel>
<asp:Panel id="vueRésultats2" runat="server">
<P>
<asp:DataList id="DataList2" runat="server">
<HeaderTemplate>
Contenu de la table [liste] de la base [produits]
<HR width="100%" SIZE="1">
</HeaderTemplate>
<AlternatingItemStyle BackColor="Teal"></AlternatingItemStyle>
<SeparatorStyle BackColor="LightSkyBlue"></SeparatorStyle>
<ItemStyle BackColor="#C0C000"></ItemStyle>
<ItemTemplate>
nom :
<%# Container.DataItem("nom") %>
, prix :
<%# databinder.eval(Container.DataItem,"prix","{0:C}") %>
<BR>
</ItemTemplate>
<SeparatorTemplate>
<HR width="100%" SIZE="1">
</SeparatorTemplate>
<HeaderStyle BackColor="#C0C0FF"></HeaderStyle>
</asp:DataList></P>
</asp:Panel>
<asp:Panel id="vueErreurs" runat="server">
<P>Les erreurs suivantes se sont produites :</P>
<%= erreursHTML %>
</asp:Panel>
</form>
</body>
</HTML>
8.7.4. تكوين مكونات [DataList]
دعونا نلقي نظرة على السمات المختلفة لمكون [DataList]. هناك العديد منها، وسنغطي هنا مجموعة صغيرة منها فقط. يمكنك تعريف ما يصل إلى سبعة قوالب عرض داخل [DataList]:
قالب رأس [DataList] | |
قالب للصفوف التي تعرض العناصر في قائمة البيانات المرتبطة. هذا القالب هو الوحيد المطلوب. | |
للتمييز بصريًا بين العناصر المعروضة المتتالية، يمكن استخدام قالبين: ItemTemplate للعنصر n، وAlternatingItemTemplate للعنصر n+1 | |
قالب للعنصر المحدد في [DataList] | |
قالب للفاصل بين عنصرين في [DataList] | |
تسمح لك [DataList] بتحرير القيم التي تعرضها. [EditItemTemplate] هو القالب الخاص بعنصر في [DataList] الذي يكون حاليًا في وضع "التحرير" | |
قالب لتذييل [DataList] |
تم إنشاء مكون [DataList1] باستخدام [WebMatrix]. في نافذة خصائصه، تم تحديد الرابط [AutoFormat]:
![]() | 1234567 ![]() |
أعلاه، سيقوم مخطط [Color 5] بإنشاء [DataList] مع أنماط للقوالب التالية: HeaderTemplate (1)، ItemTemplate (2، 6)، AlternatingTemplate (3، 5)، SelectedItemTemplate (4)، FooterTemplate (7). الشفرة التي تم إنشاؤها هي كما يلي:
<asp:DataList id="DataList1" runat="server" BorderColor="Tan" BorderWidth="1px" BackColor="LightGoldenrodYellow"
CellPadding="2" ForeColor="Black">
<SelectedItemStyle ForeColor="GhostWhite" BackColor="DarkSlateBlue"></SelectedItemStyle>
<AlternatingItemStyle BackColor="PaleGoldenrod"></AlternatingItemStyle>
<FooterStyle BackColor="Tan"></FooterStyle>
<HeaderStyle Font-Bold="True" BackColor="Tan"></HeaderStyle>
</asp:DataList></P>
لم يتم تعريف أي قوالب. الأمر متروك لنا للقيام بذلك. نحدد القوالب التالية:
| |
|
تذكر أن القالب [ItemTemplate] يُستخدم لعرض العناصر من مصدر البيانات المرتبط بـ [DataList]. مصدر البيانات هذا عبارة عن مجموعة من صفوف البيانات، يحتوي كل منها على قيمة واحدة أو أكثر. يتم تمثيل الصف الحالي في مصدر البيانات بواسطة الكائن [Container.DataItem]. يحتوي هذا الصف على أعمدة. [Container.DataItem("col1")] هي قيمة العمود "col1" في الصف الحالي. لإدراج هذه القيمة في كود العرض، نكتب <%# Container.DataItem("col") %>. في بعض الأحيان، نرغب في عرض عنصر من الصف الحالي بتنسيق خاص. هنا، نرغب في عرض عمود "price" من الصف الحالي باليورو. نستخدم الدالة [DataBinder.Eval]، التي تأخذ ثلاثة معلمات:
- الصف الحالي [Container.DataItem]
- اسم العمود المراد تنسيقه
- سلسلة التنسيق في النموذج {0:format}، حيث [format] هو أحد التنسيقات التي تقبلها طريقة [string.format].
وبالتالي، فإن الكود <%# DataBinder.Eval(Container.DataItem,"price",{0:C}) %> سيعرض عمود [price] للصف الحالي بتنسيق العملة (التنسيق C=Currency).
وبالتالي، سيكون لدينا [DataList] يبدو كما يلي:

في الأعلى، تم ترتيب البيانات بأربعة عناصر بيانات في كل صف. يتم تحقيق ذلك باستخدام سمات [DataList] التالية:
أفقي | |
العدد المطلوب من الأعمدة |
في النهاية، يكون كود [DataList1] هو الكود المقدم في مقتطف الكود أعلاه. نترك للقارئ دراسة كود العرض الخاص بـ [DataList2]. كما هو الحال مع مكون [DataGrid]، يمكن تعيين معظم خصائص [DataList] باستخدام معالج [WebMatrix]. للقيام بذلك، استخدم رابط [Property Generator] في نافذة خصائص [DataList]:
![]() | ![]() |
8.7.5. وحدات التحكم
وحدة التحكم [global.asax، global.asax.vb] هي كما يلي:
[global.asax]
[global.asax.vb]
Imports System
Imports System.Web
Imports System.Web.SessionState
Imports st.istia.univangers.fr
Imports System.Configuration
Imports System.Data
Imports System.Collections
Public Class Global
Inherits System.Web.HttpApplication
Sub Application_Start(ByVal sender As Object, ByVal e As EventArgs)
' create a product object
Try
Dim données As DataSet = New produits(ConfigurationSettings.AppSettings("OLEDBStringConnection")).getDataSet("select * from LISTE")
' put the object in the application
Application("données") = données
' no error
Application("erreur") = False
Catch ex As Exception
'there has been an error, we note it in the application
Application("erreur") = True
Application("message") = ex.Message
End Try
End Sub
End Class
عند بدء تشغيل التطبيق (Application_Start)، نقوم بإنشاء [dataset] من فئة الأعمال [products] وإضافتها إلى التطبيق بحيث تكون متاحة لجميع الطلبات من جميع العملاء. إذا حدث استثناء أثناء هذا الإنشاء، يتم تسجيله في التطبيق. سيتم تشغيل الإجراء [Application_Start] مرة واحدة فقط. بعد ذلك، لن يتم إشراك وحدة التحكم [global.asax] بعد الآن. ثم ستتولى وحدة التحكم [main.aspx.vb] المهمة:
Imports System.Collections
Imports Microsoft.VisualBasic
Imports System.Data
Imports st.istia.univangers.fr
Imports System
Imports System.Xml
Public Class main
Inherits System.Web.UI.Page
' components page
Protected WithEvents vueErreurs As System.Web.UI.WebControls.Panel
Protected WithEvents DataList1 As System.Web.UI.WebControls.DataList
Protected WithEvents DataList2 As System.Web.UI.WebControls.DataList
Protected WithEvents vueRésultats1 As System.Web.UI.WebControls.Panel
Protected WithEvents vueRésultats2 As System.Web.UI.WebControls.Panel
Protected WithEvents RadioButton1 As System.Web.UI.WebControls.RadioButton
Protected WithEvents RadioButton2 As System.Web.UI.WebControls.RadioButton
Protected WithEvents btnChanger As System.Web.UI.WebControls.Button
Protected WithEvents bandeau As System.Web.UI.WebControls.Panel
' data page
Protected erreursHTML As String
Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
' check for application errors
If CType(Application("erreur"), Boolean) Then
' the application has not initialized correctly
Dim erreurs As New ArrayList
erreurs.Add("Application momentanément indisponible (" + CType(Application("message"), String) + ")")
afficheErreurs(erreurs, False)
Exit Sub
End If
'1st request
If Not IsPostBack Then
' initialize controls
With DataList1
.DataSource = CType(Application("données"), DataSet)
.DataBind()
End With
With DataList2
.DataSource = CType(Application("données"), DataSet)
.DataBind()
End With
' the empty form is displayed
afficheRésultats(True, False)
End If
End Sub
Private Sub afficheErreurs(ByVal erreurs As ArrayList, ByVal afficheLien As Boolean)
' displays the error view
erreursHTML = ""
For i As Integer = 0 To erreurs.Count - 1
erreursHTML += "<li>" + erreurs(i).ToString + "</li>" + ControlChars.CrLf
Next
' the [errors] view is displayed
vueErreurs.Visible = True
vueRésultats1.Visible = False
vueRésultats2.Visible = False
bandeau.Visible = False
End Sub
Private Sub afficheRésultats(ByVal visible1 As Boolean, ByVal visible2 As Boolean)
' the [results] view is displayed
vueRésultats1.Visible = visible1
vueRésultats2.Visible = visible2
vueErreurs.Visible = False
End Sub
Private Sub btnChanger_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnChanger.Click
' change the style
afficheRésultats(RadioButton1.Checked, RadioButton2.Checked)
End Sub
End Class
8.8. مكون Repeater وربط البيانات
يتيح لك مكون [Repeater] تكرار كود HTML لكل عنصر في قائمة البيانات. لنفترض أننا نريد عرض قائمة بالأخطاء بالصيغة التالية:

لقد واجهنا هذه المشكلة بالفعل وحللناها عن طريق تضمين متغير في كود العرض بالشكل <% =erreursHTML %>، حيث يتم حساب قيمة erreursHTML بواسطة وحدة التحكم. تحتوي هذه القيمة على كود HTML، وتحديدًا كود قائمة. الجانب السلبي هو أنه إذا أردت تعديل عرض قائمة HTML هذه، عليك الذهاب إلى قسم وحدة التحكم، وهو ما يتعارض مع الفصل بين وحدة التحكم والعرض. يوفر مكون [Repeater] حلاً لهذه المشكلة. كما هو الحال مع [DataList]، يمكننا تعريف <HeaderTemplate> للرأس، و<ItemTemplate> للعنصر الحالي في قائمة البيانات، و<FooterTemplate> لنهاية البيانات. هنا، يمكن أن يكون لدينا التعريف التالي لمكون [Repeater]:
<asp:Repeater id="Repeater1" runat="server" EnableViewState="False">
<HeaderTemplate>
Les erreurs suivantes se sont produites :
<ul>
</HeaderTemplate>
<ItemTemplate>
<li>
<%# Container.DataItem %>
</li>
</ItemTemplate>
<FooterTemplate>
</ul>
</FooterTemplate>
</asp:Repeater>
لاحظ أن [Container.DataItem] يمثل صفًا من البيانات إذا كان مصدر البيانات يحتوي على عدة أعمدة. وهو يمثل نقطة بيانات واحدة إذا كان المصدر يحتوي على عمود واحد فقط. وهذا هو الحال هنا. على سبيل المثال، نحن نبني التطبيق التالي:

فيما يلي كود تخطيط الصفحة:
<html>
<head>
</head>
<body>
<form runat="server">
<p>
Liaison de données avec un composant [Repeater]
</p>
<hr />
<p>
<asp:Repeater id="Repeater1" runat="server" EnableViewState="False">
<ItemTemplate>
<li>
<%# Container.DataItem %>
</li>
</ItemTemplate>
<HeaderTemplate>
Les erreurs suivantes se sont produites :
<ul>
</HeaderTemplate>
<FooterTemplate>
</ul>
</FooterTemplate>
</asp:Repeater>
</p>
</form>
</body>
</html>
رمز عنصر التحكم هو كما يلي:
<%@ Page Language="VB" %>
<script runat="server">
' procedure executed when the page is loaded
Sub page_Load(sender As Object, e As EventArgs)
if not IsPostBack then
' create a data source
with Repeater1
.DataSource=createDataSource
.DataBind
end with
end if
End Sub
function createDataSource as ArrayList
' create an arraylist
dim erreurs as new ArrayList
dim i as integer
for i=0 to 5
erreurs.add("erreur-"+i.ToString)
next
return erreurs
end function
</script>
<html>
...
</html>
عند الطلب الأول للعميل، نربط كائن [ArrayList] بمكون [Repeater]، الذي من المفترض أن يمثل قائمة بالأخطاء.
8.9. التطبيق
هنا، نعيد النظر في تطبيق تم تنفيذه مسبقًا باستخدام مكونات من جانب الخادم. يتيح التطبيق للمستخدمين محاكاة حسابات الضرائب. ويعتمد على فئة [impot]، والتي لن نعيد النظر فيها هنا. تتطلب هذه الفئة بيانات تستردها من مصدر بيانات OLEDB. في هذا المثال، سنستخدم مصدر بيانات ACCESS. نقدم الميزات الجديدة التالية في هذا الإصدار:
- استخدام مكونات التحقق من الصحة للتحقق من صحة البيانات
- استخدام مكونات الخادم المرتبطة بمصادر البيانات لعرض النتائج
8.9.1. هيكل MVC للتطبيق
هيكل MVC للتطبيق هو كما يلي:
![]() |
سيتم دمج العروض الثلاثة في كود العرض الخاص بوحدة التحكم [main.aspx] كحاويات. لذلك، يحتوي هذا التطبيق على صفحة واحدة [main.aspx].
8.9.2. طرق عرض التطبيق
طريقة العرض [form] هي النموذج الخاص بإدخال المعلومات المستخدمة لحساب ضريبة المستخدم:

يقوم المستخدم بملء النموذج:

يستخدم المستخدم الزر [Submit] لطلب حساب الضريبة. يظهر للمستخدم عرض [simulations] التالي:

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

يتم تمييز هذه الأخطاء في عرض [النموذج]:

ثم يقوم المستخدم بتصحيح أخطائه. يمكنه تشغيل محاكاة جديدة:

يؤدي ذلك إلى ظهور عرض [المحاكاة] مع محاكاة إضافية واحدة:

أخيرًا، إذا كان مصدر البيانات غير متاح، يتم إخطار المستخدم في عرض [الأخطاء]:

8.9.2.1. كود العرض
تذكر أن صفحة [main.aspx] تجمع جميع طرق العرض. وهي عبارة عن نموذج واحد يحتوي على ثلاثة حاويات:
- [panelform] لعرض [form]
- [panelerrors] لعرض [الأخطاء]
- [panelsimulations] لعرض [simulations]
سنقوم الآن بتفصيل مكونات هذه الحاويات الثلاث. تحتوي حاوية [panelform] على التمثيل المرئي التالي:
![]() |
رقم | الاسم | النوع | الخصائص | الدور |
لوحة | عرض النموذج | |||
زر الاختيار | GroupName=rdmarie | أزرار الاختيار | ||
المحقق المخصص | ErrorMessage=لم تحدد حالتك الاجتماعية EnableClientScript=false | يتحقق من أن برنامج العميل قد أرسل الحالة الاجتماعية المتوقعة | ||
مربع نص | عدد الأطفال | |||
RequiredFieldValidator | رسالة الخطأ=أدخل عدد الأطفال ControlToValidate=txtChildren | يتحقق من أن حقل [txtChildren] ليس فارغًا | ||
RangeValidator | ErrorMessage=أدخل رقمًا بين 1 و 30 ControlToValidate=txtChildren | يتحقق من أن الحقل [txtChildren] يقع ضمن النطاق [1,30] | ||
مربع نص | EnableViewState=true | الراتب السنوي | ||
أداة التحقق من صحة الحقول المطلوبة | ControlToValidate=txtSalary ErrorMessage=أدخل مبلغ راتبك | يتحقق من أن حقل [txtSalary] ليس فارغًا | ||
مُثبت صحة التعبير العادي | ControlToValidate=txtSalary رسالة الخطأ=راتب غير صالح التعبير العادي=\s*\d+\s* | يتحقق من أن حقل [txtSalary] عبارة عن سلسلة من الأرقام | ||
زر | ValidationTriggers=true | زر [submit] في النموذج - يبدأ حساب الضريبة | ||
زر | التحقق=false | زر [إرسال] في النموذج - يمسح النموذج |
قد تفاجأ بفحص [cvMarié]، الذي يتحقق من أن المستخدم قد حدد أحد زري الاختيار. وهذا ضروري لأنه لا توجد طريقة للتأكد من أن المستخدم يستخدم النموذج الذي أرسله الخادم. وبما أنه لا يوجد ما يضمن ذلك، يجب علينا التحقق من جميع المعلمات المرسلة. لاحظ أيضًا السمة [CausesValidation=false] للزر [btnEffacer]. عندما ينقر المستخدم على هذا الزر، لا ينبغي التحقق من البيانات المرسلة لأنها سيتم تجاهلها.
تحتوي جميع المكونات في الحاوية على الخاصية [EnableViewState=false] باستثناء [panelForm، txtEnfants، txtSalaire، rdOui، rdNon]. تحتوي الحاوية [panelerreurs] على التمثيل المرئي التالي:
![]() |
رقم | الاسم | النوع | الخصائص | الدور |
لوحة | EnableViewState=false | عرض الخطأ | ||
المكرر | EnableViewState=false | يعرض قائمة بالأخطاء |
يتم تعريف المكون [rptErrors] على النحو التالي:
<asp:Repeater id="rptErreurs" runat="server" EnableViewState="False">
<ItemTemplate>
<li>
<%# Container.Dataitem%>
</li>
</ItemTemplate>
<HeaderTemplate>
Les erreurs suivantes se sont produites
<ul>
</HeaderTemplate>
<FooterTemplate>
</ul>
</FooterTemplate>
</asp:Repeater>
ستكون قائمة البيانات المرتبطة بمكون [rptErrors] كائن [ArrayList] يحتوي على قائمة برسائل الخطأ. وبالتالي، كما هو موضح أعلاه، يشير <%# Container.Dataitem%> إلى رسالة الخطأ الحالية. يحتوي حاوية [panelsimulations] على التمثيل المرئي التالي:
![]() |
رقم | الاسم | النوع | الخصائص | الدور |
لوحة | EnableViewState=false | عرض المحاكاة | ||
زر الارتباط | EnableViewState=false | رابط إلى النموذج | ||
DataGrid | EnableViewState=false | مسؤول عن عرض المحاكاة الموضوعة في كائن [DataTable] |
يتم تكوين مكون [dgSimulations] على النحو التالي في [Webmatrix]. في نافذة خصائص [dgSimulations]، نختار الرابط [AutoFormat] ونختار نظام الألوان [Color 3]:
![]() | ![]() |
ثم، في نافذة خصائص [dlgSimulations] نفسها، نختار الرابط [Property Generator]. نطلب عرض رؤوس الأعمدة:

نختار خيار [Columns] لتعريف الأعمدة الأربعة لـ [DataGrid]:

نقوم بإلغاء تحديد الخيار [Create columns automatically...]. سنقوم بتحديد الأعمدة الأربعة لـ [DataGrid] بأنفسنا. سيتم ربط هذا بكائن [DataTable] يحتوي على أربعة أعمدة تسمى "married" و"children" و"salary" و"tax" على التوالي. لإنشاء عمود في [DataGrid]، نختار خيار [Related Columns] ونستخدم زر الإنشاء كما هو موضح أعلاه. يتم إنشاء عمود، ويمكننا تحديد خصائصه. سيحتوي العمود الأول من جدول المحاكاة على عمود "married" من كائن [DataTable] الذي سيتم ربطه بـ [DataGrid]. يتم تحديد هذا العمود الأول من [DataGrid] على النحو التالي في المعالج:

عنوان العمود، هنا "متزوج" | |
اسم العمود في مصدر البيانات الذي سيتم عرضه بواسطة هذا العمود في [DataGrid]. هنا، هو عمود "married" في [DataTable]. |
يتم تعريف العمود الثاني على النحو التالي:
الأطفال | |
الأطفال |
يتم تعريف العمود الثالث على النحو التالي:
الراتب السنوي | |
الراتب | |
{0:C} - عرض العملة للحصول على علامة اليورو |
يتم تعريف العمود الرابع على النحو التالي:
مبلغ الضريبة | |
الضريبة | |
{0:C} - عرض العملة للحصول على علامة اليورو |
نضع كود العرض وكود التحكم في ملفين منفصلين. سيكون الأول في [main.aspx] والثاني في [main.aspx.vb]. كود [main.aspx] هو كما يلي:
<%@ page src="main.aspx.vb" inherits="main" AutoEventWireUp="false" %>
<HTML>
<HEAD>
<title>Calculer votre impôt</title>
</HEAD>
<body>
<P>Calculer votre impôt</P>
<HR width="100%" SIZE="1">
<FORM id="Form1" runat="server">
<asp:panel id="panelform" Runat="server">
<TABLE id="Table1" cellSpacing="1" cellPadding="1" border="0">
<TR>
<TD height="19">Etes-vous marié(e)</TD>
<TD height="19">
<asp:RadioButton id="rdOui" runat="server" GroupName="rdMarie"></asp:RadioButton>Oui
<asp:RadioButton id="rdNon" runat="server" GroupName="rdMarie" Checked="True"></asp:RadioButton>Non
<asp:CustomValidator id="cvMarie" runat="server" ErrorMessage="Vous n'avez pas indiqué votre état marital"
Display="Dynamic" EnableClientScript="False" Visible="False" EnableViewState="False"></asp:CustomValidator></TD>
</TR>
<TR>
<TD>Nombre d'enfants</TD>
<TD>
<asp:TextBox id="txtEnfants" runat="server" Columns="3" MaxLength="3"></asp:TextBox>
<asp:RequiredFieldValidator id="rfvEnfants" runat="server" ErrorMessage="Indiquez le nombre d'enfants" Display="Dynamic"
ControlToValidate="txtEnfants" EnableViewState="False"></asp:RequiredFieldValidator>
<asp:RangeValidator id="rvEnfants" runat="server" ErrorMessage="Tapez un nombre entre 1 et 30" Display="Dynamic"
ControlToValidate="txtEnfants" Type="Integer" MaximumValue="30" MinimumValue="0" EnableViewState="False"></asp:RangeValidator></TD>
</TR>
<TR>
<TD>Salaire annuel (euro)</TD>
<TD>
<asp:TextBox id="txtSalaire" runat="server" Columns="10" MaxLength="10"></asp:TextBox>
<asp:RequiredFieldValidator id="rfvSalaire" runat="server" ErrorMessage="Indiquez le montant de votre salaire"
Display="Dynamic" ControlToValidate="txtSalaire" EnableViewState="False"></asp:RequiredFieldValidator>
<asp:RegularExpressionValidator id="revSalaire" runat="server" ErrorMessage="Salaire invalide" Display="Dynamic"
ControlToValidate="txtSalaire" ValidationExpression="\s*\d+\s*" EnableViewState="False"></asp:RegularExpressionValidator></TD>
</TR>
</TABLE>
<P>
<asp:Button id="btnCalculer" runat="server" Text="Calculer"></asp:Button>
<asp:Button id="btnEffacer" runat="server" Text="Effacer" CausesValidation="False"></asp:Button></P>
</asp:panel>
<asp:panel id="panelerreurs" runat="server" EnableViewState="False">
<asp:Repeater id="rptErreurs" runat="server" EnableViewState="False">
<ItemTemplate>
<li>
<%# Container.Dataitem%>
</li>
</ItemTemplate>
<HeaderTemplate>
Les erreurs suivantes se sont produites
<ul>
</HeaderTemplate>
<FooterTemplate>
</ul>
</FooterTemplate>
</asp:Repeater>
</asp:panel>
<asp:panel id="panelsimulations" runat="server" EnableViewState="False">
<P>
<asp:DataGrid id="dgSimulations" runat="server" BorderColor="#DEBA84" BorderStyle="None" CellSpacing="2"
BorderWidth="1px" BackColor="#DEBA84" CellPadding="3" AutoGenerateColumns="False" EnableViewState="False">
<SelectedItemStyle Font-Bold="True" ForeColor="White" BackColor="#738A9C"></SelectedItemStyle>
<ItemStyle ForeColor="#8C4510" BackColor="#FFF7E7"></ItemStyle>
<HeaderStyle Font-Bold="True" ForeColor="White" BackColor="#A55129"></HeaderStyle>
<FooterStyle ForeColor="#8C4510" BackColor="#F7DFB5"></FooterStyle>
<Columns>
<asp:BoundColumn DataField="marié" HeaderText="Marié"></asp:BoundColumn>
<asp:BoundColumn DataField="enfants" HeaderText="Enfants"></asp:BoundColumn>
<asp:BoundColumn DataField="salaire" HeaderText="Salaire annuel" DataFormatString="{0:C}"></asp:BoundColumn>
<asp:BoundColumn DataField="impôt" HeaderText="Montant de l'impôt" DataFormatString="{0:C}"></asp:BoundColumn>
</Columns>
<PagerStyle HorizontalAlign="Center" ForeColor="#8C4510" Mode="NumericPages"></PagerStyle>
</asp:DataGrid></P>
<P>
<asp:LinkButton id="lnkForm2" runat="server" EnableViewState="False">Retour au formulaire</asp:LinkButton></P>
</asp:panel>
</FORM>
</body>
</HTML>
8.9.3. كود التحكم في التطبيق
يتم توزيع كود التحكم في التطبيق عبر ملفات [global.asax.vb] و [main.aspx.vb]. يتم تعريف ملف [global.asax] على النحو التالي:
ملف [global.asax.vb] كما يلي:
Imports System
Imports System.Web
Imports System.Web.SessionState
Imports st.istia.univangers.fr
Imports System.Configuration
Imports System.Collections
Imports System.Data
Public Class Global
Inherits System.Web.HttpApplication
Sub Application_Start(ByVal sender As Object, ByVal e As EventArgs)
' create an impot object
Dim objImpot As impot
Try
objImpot = New impot(New impotsOLEDB(ConfigurationSettings.AppSettings("chaineConnexion")))
' put the object in the application
Application("objImpot") = objImpot
' no error
Application("erreur") = False
Catch ex As Exception
'there has been an error, we note it in the application
Application("erreur") = True
Application("message") = ex.Message
End Try
End Sub
Sub Session_Start(ByVal sender As Object, ByVal e As EventArgs)
' start of session - create a list of empty simulations
Dim simulations As New DataTable("simulations")
simulations.Columns.Add("marié", Type.GetType("System.String"))
simulations.Columns.Add("enfants", Type.GetType("System.String"))
simulations.Columns.Add("salaire", Type.GetType("System.Int32"))
simulations.Columns.Add("impôt", Type.GetType("System.Int32"))
Session.Item("simulations") = simulations
End Sub
End Class
عند بدء تشغيل التطبيق (الطلب الأول المقدم إلى التطبيق)، يتم تنفيذ الإجراء [Application_Start]. ويحاول إنشاء كائن من النوع [tax] عن طريق استرداد بياناته من مصدر OLEDB. يُنصح القارئ بمراجعة الفصل 5، حيث تم تعريف هذه الفئة، إذا كان قد نسيها. قد يفشل إنشاء كائن [impot] إذا كان مصدر البيانات غير متاح. في هذه الحالة، يتم تخزين الخطأ في التطبيق بحيث تعرف جميع الطلبات اللاحقة أنه لم يتم تهيئته بشكل صحيح. إذا نجح الإنشاء، يتم أيضًا تخزين كائن [impot] الذي تم إنشاؤه في التطبيق. وسيتم استخدامه من قبل جميع طلبات حساب الضرائب. عندما يقوم العميل بتقديم طلبه الأول، يتم إنشاء جلسة له بواسطة الإجراء [Application_Start]. تهدف هذه الجلسة إلى تخزين مختلف محاكاة حساب الضرائب التي سيقومون بها. سيتم تخزينها في كائن [DataTable] مرتبط بمفتاح الجلسة "simulations". عند بدء الجلسة، يرتبط هذا المفتاح بكائن [DataTable] فارغ تم تعريف هيكله. يتم وضع المعلومات المطلوبة من قبل التطبيق في ملف التكوين الخاص به [wenConfig]:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="chaineConnexion" value="Provider=Microsoft.Jet.OLEDB.4.0; Ole DB Services=-4; Data Source=D:\data\devel\aspnet\poly\webforms2\vs\impots6\impots.mdb" />
</appSettings>
</configuration>
يحدد المفتاح [connectionString] سلسلة الاتصال بمصدر OLEDB. ويوجد باقي كود التحكم في [main.aspx.vb]:
Imports System.Collections
Imports Microsoft.VisualBasic
Imports st.istia.univangers.fr
Imports System
Imports System.Web.UI.Control
Imports System.Data
Public Class main
Inherits System.Web.UI.Page
Protected WithEvents rdOui As System.Web.UI.WebControls.RadioButton
Protected WithEvents rdNon As System.Web.UI.WebControls.RadioButton
Protected WithEvents txtEnfants As System.Web.UI.WebControls.TextBox
Protected WithEvents txtSalaire As System.Web.UI.WebControls.TextBox
Protected WithEvents btnCalculer As System.Web.UI.WebControls.Button
Protected WithEvents btnEffacer As System.Web.UI.WebControls.Button
Protected WithEvents panelform As System.Web.UI.WebControls.Panel
Protected WithEvents lnkForm2 As System.Web.UI.WebControls.LinkButton
Protected WithEvents panelerreurs As System.Web.UI.WebControls.Panel
Protected WithEvents rfvEnfants As System.Web.UI.WebControls.RequiredFieldValidator
Protected WithEvents rvEnfants As System.Web.UI.WebControls.RangeValidator
Protected WithEvents rfvSalaire As System.Web.UI.WebControls.RequiredFieldValidator
Protected WithEvents rptErreurs As System.Web.UI.WebControls.Repeater
Protected WithEvents dgSimulations As System.Web.UI.WebControls.DataGrid
Protected WithEvents revSalaire As System.Web.UI.WebControls.RegularExpressionValidator
Protected WithEvents cvMarie As System.Web.UI.WebControls.CustomValidator
Protected WithEvents panelsimulations As System.Web.UI.WebControls.Panel
' local variables
Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
...
End Sub
Private Sub afficheErreurs(ByRef erreurs As ArrayList)
...
End Sub
Private Sub afficheFormulaire()
...
End Sub
Private Sub afficheSimulations(ByRef simulations As DataTable, ByRef lien As String)
...
End Sub
Private Sub btnCalculer_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnCalculer.Click
....
End Sub
Private Sub lnkForm1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)
...
End Sub
Private Sub lnkForm2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles lnkForm2.Click
...
End Sub
Private Sub btnEffacer_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnEffacer.Click
...
End Sub
Private Sub razForm()
...
End Sub
Private Sub cvMarie_ServerValidate(ByVal source As System.Object, ByVal args As System.Web.UI.WebControls.ServerValidateEventArgs)
...
End Sub
End Class
الحدث الأول الذي يعالجه الكود هو [Page_Load]:
Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
' first, we look at the state of the application
If CType(Application("erreur"), Boolean) Then
' the application failed to initialize
' the error view is displayed
Dim erreurs As New ArrayList
erreurs.Add("Application momentanément indisponible (" + CType(Application("message"), String) + ")")
afficheErreurs(erreurs)
Exit Sub
End If
' no errors - on the 1st request, the form is presented
If Not IsPostBack Then afficheFormulaire()
End Sub
قبل معالجة الطلب، نتحقق من أن التطبيق قد تم تهيئته بشكل صحيح. إذا لم يكن الأمر كذلك، نعرض طريقة العرض [errors] باستخدام الإجراء [displayErrors]. إذا كان هذا هو الطلب الأول (IsPostBack=false)، نعرض طريقة العرض [form] باستخدام [displayForm].
الإجراء الذي يعرض عرض [errors] هو كما يلي:
Private Sub afficheErreurs(ByRef erreurs As ArrayList)
' builds a list of errors
With rptErreurs
.DataSource = erreurs
.DataBind()
End With
' container display
panelerreurs.Visible = True
panelform.Visible = False
panelsimulations.Visible = False
Exit Sub
End Sub
تستقبل الإجراء كمعلمة قائمة برسائل الخطأ في [errors] من النوع [ArrayList]. نقوم ببساطة بربط مصدر البيانات هذا بمكون [rptErrors] المسؤول عن عرضها.
الإجراء الذي يعرض طريقة العرض [form] هو كما يلي:
Private Sub afficheFormulaire()
' displays the form
panelform.Visible = True
' the other containers are hidden
panelerreurs.Visible = False
panelsimulations.Visible = False
End Sub
هذا الإجراء يجعل الحاوية [panelform] مرئية ببساطة. يتم عرض المكونات بقيمتها المنشورة أو السابقة (VIEWSTATE).
عندما ينقر المستخدم على الزر [Calculate] في عرض [form]، يتم إرسال طلب POST إلى [main.aspx]. يتم تنفيذ الإجراء [Page_Load]، يليه الإجراء [btnCalculate_Click]:
Private Sub btnCalculer_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnCalculer.Click
' we check the validity of the data entered; if there are any errors, we report them
If Not Page.IsValid Then
afficheFormulaire()
Exit Sub
End If
' no errors - tax is calculated
Dim impot As Long = CType(Application("objImpot"), impot).calculer( _
rdOui.Checked, CType(txtEnfants.Text, Integer), CType(txtSalaire.Text, Long))
' the result is added to existing simulations
Dim simulations As DataTable = CType(Session.Item("simulations"), DataTable)
Dim simulation As DataRow = simulations.NewRow
simulation("marié") = CType(IIf(rdOui.Checked, "oui", "non"), String)
simulation("enfants") = txtEnfants.Text.Trim
simulation("salaire") = CType(txtSalaire.Text.Trim, Long)
simulation("impôt") = impot
simulations.Rows.Add(simulation)
' put the simulations in the session
Session.Item("simulations") = simulations
' the simulations page is displayed
afficheSimulations(simulations, "Retour au formulaire")
End Sub
يبدأ الإجراء بالتحقق من صحة الصفحة. تذكر أنه عند تشغيل الإجراء [btnCalculate_Click]، تكون عناصر التحقق من الصحة قد أنجزت مهمتها ويتم تعيين السمة [IsValid] للصفحة. إذا كانت الصفحة غير صالحة، يتم عرض طريقة العرض [form] مرة أخرى وينتهي الإجراء. ستعرض مكونات التحقق من صحة عرض [form] التي تم تعيين السمة [IsValid] لها على [false] السمة [ErrorMessage] الخاصة بها. إذا كانت الصفحة صالحة، يتم حساب مبلغ الضريبة باستخدام كائن [tax] الذي تم تخزينه في التطبيق عند بدء التشغيل. تتم إضافة هذه المحاكاة الجديدة إلى قائمة المحاكاة التي تم إجراؤها بالفعل وتخزينها في الجلسة.
أخيرًا، يتم عرض عرض [simulations] بواسطة الإجراء [displaySimulations] التالي:
Private Sub afficheSimulations(ByRef simulations As DataTable, ByRef lien As String)
' we link the datagrid to the simulations source
With dgSimulations
.DataSource = simulations
.DataBind()
End With
' link
lnkForm2.Text = lien
' the views
panelsimulations.Visible = True
panelerreurs.Visible = False
panelform.Visible = False
End Sub
يحتوي الإجراء على معلمتين:
- قائمة بالمحاكاة في [simulations] من النوع [DataTable]
- نص رابط في [link]
مصدر البيانات [simulations] مرتبط بالمكون المسؤول عن عرضه. يتم وضع نص الرابط في الخاصية [Text] للكائن [LinkButton] في العرض.
عندما ينقر المستخدم على الزر [Delete] في عرض [form]، يتم تنفيذ الإجراء [btnDelete_click] (دائمًا بعد [Page_Load]):
Private Sub btnEffacer_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnEffacer.Click
' displays the empty form
razForm()
afficheFormulaire()
End Sub
Private Sub razForm()
' empty the form
rdOui.Checked = False
rdNon.Checked = True
txtEnfants.Text = ""
txtSalaire.Text = ""
End Sub
الرمز أعلاه بسيط بما يكفي بحيث لا يحتاج إلى أي تعليقات. ما زلنا بحاجة إلى معالجة النقرات على روابط عرض [errors] و [simulations]:
Private Sub lnkForm1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles lnkForm1.Click
' displays the form
afficheFormulaire()
End Sub
Private Sub lnkForm2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles lnkForm2.Click
' displays the form
afficheFormulaire()
End Sub
يعرض كلا الإجراءين ببساطة عرض [النموذج]. ونحن نعلم أن الحقول في هذا العرض ستتلقى قيمة هي إما القيمة التي تم إرسالها لها أو قيمتها السابقة. وبما أن طلب POST الخاص بالعميل في هذه الحالة لا يرسل أي قيم لحقول النموذج، فإنها ستعود إلى قيمها السابقة. وبالتالي، يتم عرض النموذج بالقيم التي أدخلها المستخدم.
8.9.4. الاختبارات
يتم وضع جميع الملفات المطلوبة للتطبيق في مجلد باسم <application-path>: ![]() | يحتوي المجلد [bin] على ملف DLL الذي يحتوي على فئات [impot] و[impotsData] و[impotsOLEDB] التي يتطلبها التطبيق: |
إذا رغب القارئ، يمكنه الرجوع إلى الفصل 5، الذي يشرح كيفية إنشاء ملف [impot.dll] المذكور أعلاه. بمجرد الانتهاء من ذلك، يتم تشغيل خادم Cassini باستخدام المعلمات (<application-path>,/impots6). ثم نصل إلى عنوان URL [http://impots6/main.aspx] باستخدام متصفح:

إذا قمت بتغيير اسم ملف ACCESS [impots.mdb] إلى [impots1.mdb]، فسترى الصفحة التالية:

8.9.5. الخلاصة
لدينا تطبيق MVC يستخدم مكونات جانب الخادم فقط. وقد سمح لنا استخدام هذه المكونات بفصل طبقة العرض في التطبيق تمامًا عن طبقة التحكم. لم يكن هذا ممكنًا حتى الآن، حيث كان كود العرض يحتوي سابقًا على متغيرات محسوبة بواسطة كود التحكم، والتي تضمنت قيمها كود HTML. والآن لم يعد هذا هو الحال.






















