Skip to content

8. ASP اجزای سرور – ۲

8.1. Introduction

ما کار خود را بر روی رابط کاربری با بررسی موارد زیر ادامه می‌دهیم:

  • کامپوننت‌های اعتبارسنجی داده‌ها
  • نحوه پیوند دادن داده‌ها به کامپوننت‌های سرور
  • کامپوننت‌های سرور HTML

8.2. کامپوننت‌های اعتبارسنجی داده‌ها

8.2.1. مقدمه

در برنامه‌های مبتنی بر فرم، بررسی اعتبار داده‌های وارد شده در فرم‌ها ضروری است. در مثال محاسبه مالیات، فرم زیر را داشتیم:

Image

پس از دریافت مقادیر از این فرم، باید اعتبار داده‌های وارد شده را بررسی کنیم: تعداد فرزندان و حقوق باید اعداد صحیح مثبت یا صفر باشند. اگر اینطور نباشد، فرم به همان شکلی که وارد شده به کلاینت بازگردانده می‌شود، به همراه پیام‌هایی که خطاها را نشان می‌دهند. ما این سناریو را با استفاده از دو ویو مدیریت کرده بودیم، یکی برای فرم بالا و دیگری برای خطاها:

Image

ASP.NET کامپوننت‌هایی به نام کامپوننت‌های اعتبارسنجی را فراهم می‌کند که امکان بررسی موارد زیر را می‌دهند:

کامپوننت
نقش
RequiredFieldValidator
بررسی می‌کند که یک فیلد خالی نباشد
CompareValidator
دو مقدار را با یکدیگر بررسی می‌کند
RangeValidator
بررسی می‌کند که یک مقدار بین دو حد قرار دارد
RegularExpressionValidator
بررسی می‌کند که یک فیلد با یک عبارت منظم مطابقت دارد
CustomValidator
به توسعه‌دهنده اجازه می‌دهد تا قواعد اعتبارسنجی خود را تعریف کند – این کامپوننت می‌تواند جایگزین همهٔ موارد دیگر شود
ValidationSummary
امکان گروه‌بندی پیام‌های خطا تولیدشده توسط بررسی‌های قبلی را در یک مکان واحد روی صفحه فراهم می‌کند

اکنون هر یک از این کامپوننت‌ها را معرفی خواهیم کرد.

8.2.2. RequiredFieldValidator

ما در حال ساخت صفحه زیر هستیم: [requiredfieldvalidator1.aspx]:

خیر.
نام
نوع
ویژگی‌ها
نقش
1
txtNom
TextBox
EnableViewState=true
میدان ورودی
2
RequiredFieldValidator1
RequiredFieldValidator
EnableViewState=false
EnableClientScript=true
پیام خطا=میدان [name] الزامی است
کامپوننت اعتبارسنجی
۳
btnEnvoyer
دکمه
EnableViewState=false
ValidationCauses=true
دکمه [submit]

میدان [RequiredFieldValidator1] برای نمایش پیام خطا در صورتی که میدان [txtNom] خالی باشد یا شامل رشته‌ای از فضاها باشد، استفاده می‌شود. ویژگی‌های آن به شرح زیر است:

ControlToValidate
یک فیلد که مقدار آن باید توسط کامپوننت بررسی شود. مقدار یک کامپوننت به چه معناست؟ این مقدار، ارزش ویژگی [value] در تگ متناظر HTML است. برای [TextBox]، این محتواِ فیلد ورودی خواهد بود؛ برای [DropDownList]، این مقدار عنصر انتخاب‌شده خواهد بود.
EnableClientScript
بولی – تنظیم آن روی true نشان می‌دهد که محتویات فیلد قبلی نیز باید در سمت کلاینت اعتبارسنجی شوند. در این صورت، فرم تنها در صورتی توسط مرورگر ارسال می‌شود که هیچ خطایی نداشته باشد. با این حال، بررسی‌های اعتبارسنجی در سمت سرور نیز انجام می‌شوند، برای مثال در صورتی که کلاینت مرورگر نباشد.
ErrorMessage
پیام خطایی که کامپوننت باید در صورت تشخیص خطا نمایش دهد

اعتبارسنجی داده‌ها در صفحه تنها در صورتی انجام می‌شود که دکمه‌ای یا پیوندی که [POST] را در صفحه فعال کرده باشد، دارای ویژگی [CausesValidation=true] باشد. [true] مقدار پیش‌فرض این ویژگی است.

بیایید این برنامه را اجرا کنیم. ابتدا از یک مرورگر [Mozilla] استفاده خواهیم کرد:

Image

کد 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" />
                            &nbsp;
                        </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] از طریق ویژگی [onclick] به یک تابع جاوااسکریپت متصل است. همچنین می‌توانیم ببینیم که صفحه حاوی هیچ کد [Javascript] نیست. آزمون [typeof(Page_ClientValidate) == 'function'] ناموفق خواهد بود و تابع جاوااسکریپت فراخوانی نخواهد شد. سپس فرم به سرور ارسال می‌شود تا بررسی‌های اعتبارسنجی را انجام دهد. بیایید از دکمه [Envoyer] بدون مشخص کردن نام استفاده کنیم. پاسخ سرور به شرح زیر است:

Image

چه اتفاقی افتاد؟ فرم برای سرور ارسال شد. سپس سرور کد تمام کامپوننت‌های اعتبارسنجی روی صفحه را اجرا کرد. در این مورد، تنها یک مورد وجود دارد. اگر حتی یک جزء اعتبارسنجی خطایی را تشخیص دهد، سرور فرم را دقیقاً همان‌طور که ارسال شده بازمی‌گرداند (در واقع، برای جزئیاتی با [EnableViewState=true]، به همراه یک پیام خطا برای هر جزء اعتبارسنجی که خطایی را تشخیص داده است). این پیام، ویژگی [ErrorMessage]ِ کامپوننت اعتبارسنجی است. این همان سازوکاری است که در بالا می‌بینیم. اگر چیزی را در فیلد [nom] وارد کنیم، پیام خطا دیگر هنگام ارسال فرم نمایش داده نمی‌شود:

Image

اکنون، بیایید از اینترنت اکسپلورر استفاده کنیم و URL [http://localhost/requiredfieldvalidator1.aspx] را درخواست کنیم. صفحه زیر را دریافت می‌کنیم:

Image

کد 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] دریافت شده است. در اینجا وارد جزئیات نمی‌شویم. این تفاوت از این واقعیت ناشی می‌شود که سرور در سند HTML که ارسال کرده است، توابع جاوااسکریپت را گنجانده است. چرا دو کد متفاوت HTML وجود دارد در حالی که URL درخواست‌شده توسط هر دو مرورگر یکسان است؟ ما قبلاً اشاره کرده‌ایم که فناوری ASP.NET باعث می‌شود سرور سند HTML ارسالی به کلاینت را برای مطابقت با مشخصات آن کلاینت تطبیق دهد. مرندرهای مختلفی در بازار وجود دارند که همگی از قابلیت‌های یکسانی برخوردار نیستند. برای مثال، مرورگرهای مایکروسافت و نت‌اسکیپ از مدل شیءگرایی یکسانی برای سند دریافتی خود استفاده نمی‌کنند. در نتیجه، کد جاوااسکریپتی که برای دستکاری این سند در سمت مرورگر به کار می‌رود، در این دو مرورگر متفاوت است. به همین ترتیب، سازندگان مرورگر نسخه‌های متوالی از مرورگرهای خود را منتشر کرده‌اند و پیوسته قابلیت‌های آن‌ها را بهبود می‌بخشند. در نتیجه، ممکن است سند HTML که توسط IE5 قابل درک است، توسط IE3 قابل درک نباشد. مثال فوق این تطبیق توسط سرور را برای سازگاری با کلاینت خود نشان می‌دهد. به دلیلی که در اینجا به تفصیل مورد بررسی قرار نگرفته است، وب‌سرور تشخیص داد که کلاینت [Mozilla] قادر به پردازش کد اعتبارسنجی جاوااسکریپت نیست. در نتیجه، این کد در سند HTML که برای آن ارسال شد، گنجانده نشد و اعتبارسنجی در سمت سرور انجام شد. برای [IE6]، این کد جاوااسکریپت در سند HTML که ارسال شد، گنجانده شده است، همان‌طور که می‌بینیم. برای مشاهده عملکرد آن، بیایید آزمایش زیر را انجام دهیم:

  • وب‌سرور را متوقف کنید
  • از دکمه [Envoyer] بدون پر کردن فیلد [nom] استفاده می‌کنیم

سپس صفحه جدید زیر به ما نمایش داده می‌شود:

Image

در واقع این مرورگر است که پیام خطا را نمایش داده است. این به این دلیل است که سرور متوقف شده است. ما می‌توانیم این را با وارد کردن چیزی در فیلد [nom] و ارسال آن تأیید کنیم. این بار، پاسخ به شرح زیر است:

Image

چه اتفاقی افتاد؟ مرورگر کد اعتبارسنجی جاوا اسکریپت را اجرا کرد. این کد تشخیص داد که صفحه معتبر است. بنابراین مرورگر فرم را به وب سرور ارسال کرد که خاموش بود. مرورگر متوجه این موضوع شد و صفحه نشان داده شده در بالا را نمایش داد. اگر سرور را مجدداً راه‌اندازی کنید، همه چیز به حالت عادی بازمی‌گردد.

از این مثال چه می‌توانیم بیاموزیم؟

  • ارزش مفهوم مؤلفه اعتبارسنجی، که امکان بازگرداندن هر فرم نادرست به سمت کلاینت را فراهم می‌کند
  • ارزش [VIEWSTATE]، که امکان بازگرداندن این فرم را دقیقاً به همان شکلی که ارسال شده بود فراهم می‌کند
  • توانایی سرور برای سازگار شدن با کلاینت خود. کلاینت از طریق هدرهای HTTP و [User-Agent:] که به سرور ارسال می‌کند، شناسایی می‌شود. بنابراین این سرور نیست که «حدس» می‌زند با چه کسی سر و کار دارد. این قابلیت تطبیق برای توسعه‌دهنده بسیار مفید است، زیرا او نیازی ندارد نگران نوع کلاینتی باشد که برنامه‌اش با آن در تعامل است.

8.2.3. CompareValidator

ما در حال ساخت صفحه زیر هستیم: [comparevalidator1.aspx]:

Image

خیر.
نام
نوع
ویژگی‌ها
نقش
۱
cmbChoix1
DropDownList
EnableViewState=true
لیست کشویی
2
cmbChoix2
DropDownList
EnableViewState=true
لیست کشویی
۳
CompareValidator1
CompareValidator
EnableViewState=false
EnableClientScript=true
پیام خطا=انتخاب ۱ نامعتبر
مقدار برای مقایسه=؟
Operator=NotEqual
Type=string
کامپوننت اعتبارسنجی
۴
CompareValidator2
CompareValidator
EnableViewState=false
EnableClientScript=true
ErrorMessage=انتخاب ۲ نامعتبر است
ControlToCompare=?
Operator=NotEqual
Type=string
کامپوننت اعتبارسنجی
5
btnEnvoyer
دکمه
EnableViewState=false
ValidationReasons=true
دکمه [submit]

کامپوننت [CompareValidator] برای مقایسه دو مقدار در مقابل یکدیگر استفاده می‌شود. عملگرهایی که می‌توان استفاده کرد [Equal, NotEqual, LessThan, LessThanEqual, GreaterThan, GreaterThanEqual] هستند. مقدار اول توسط خاصیت [ControlToValidate] و مقدار دوم توسط [ValueToCompare] (اگر مقدار اول قرار است با یک مقدار ثابت مقایسه شود) یا توسط [ControlToCompare] (اگر قرار است با مقدار یک کامپوننت دیگر مقایسه شود) تنظیم می‌شود. ویژگی‌های مهم کامپوننت [CompareValidator] به شرح زیر است:

ControlToValidate
میدانی که محتوای آن باید توسط کامپوننت بررسی شود
EnableClientScript
بولی – تنظیم آن روی true نشان می‌دهد که محتوای فیلد قبلی نیز باید در سمت کلاینت اعتبارسنجی شود
ErrorMessage
پیام خطایی که کامپوننت باید در صورت تشخیص خطا نمایش دهد
ValeurToCompare
مقداری که مقدار فیلد باید با آن مقایسه شود [ControlToValidate]
ControlToCompare
کامپوننتی که مقدار فیلد باید با آن مقایسه شود [ControlToValidate]
Operator
عملگر مقایسه بین دو مقدار
Type
نوع مقادیری که باید مقایسه شوند

کد نمایش برای این صفحه به شرح زیر است:

<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

ما این برنامه را اجرا می‌کنیم. در اینجا مثالی از یک صفحه دریافت‌شده در طول مبادلات کلاینت-سرور آورده شده است:

Image

اگر به همان صفحه از طریق Internet Explorer 6 دسترسی پیدا شود، کد جاوااسکریپت در صفحه گنجانده می‌شود که باعث می‌شود رفتار آن کمی متفاوت باشد. هرگونه خطا به محض اینکه کاربر مقداری را در یکی از فهرست‌های کشویی تغییر دهد، علامت‌گذاری می‌شود. این امر تجربه کاربری را بهبود می‌بخشد.

8.2.4. CustomValidator, RangeValidator

ما در حال ساخت صفحه زیر هستیم: [customvalidator1.aspx]:

Image

خیر.
نام
نوع
ویژگی‌ها
نقش
1
cmbDiplomes
DropDownList
EnableViewState=true
لیست کشویی
2
CompareValidator2
CompareValidator
EnableViewState=false
EnableClientScript=true
ErrorMessage=صلاحیت نامعتبر
عملگر=مساوی نیست
مقدار برای مقایسه=؟
Type=String
کامپوننت اعتبارسنجی برای کنترل [1]
3
txtAutreDiplome
TextBox
EnableViewState=false
میدان ورودی
4
CustomValidator1
CustomValidator
EnableViewState=false
EnableClientScript=true
پیام خطا=تعیین صلاحیت نامعتبر
ClientValidationFunction=chkOtherQualification
کامپوننت اعتبارسنجی فیلد [3]
5
txtAnDiplome
TextBox
EnableViewState=false
میدان ورودی
6
RangeValidator1
RangeValidator
EnableViewState=false
EnableClientScript=true
ErrorMessage=سال فارغ‌التحصیلی باید در بازه [1990,2004] باشد
MinValue=1990
MaxValue=2004
Type=Integer
ControlToValidate=txtAnDiplome
کامپوننت اعتبارسنجی برای فیلد [5]
7
RequiredFieldValidator2
RequiredFieldValidator
EnableViewState=false
EnableClientScript=true
پیام خطا=سال صلاحیت مورد نیاز
ControlToValidate=txtAnDiplome
کامپوننت اعتبارسنجی فیلد [5]
8
btnEnvoyer
دکمه
EnableViewState=false
ValidationReasons=true
دکمه [submit]

میدان [RangeValidator] برای بررسی اینکه مقدار یک کنترل بین دو حد [MinValue] و [MaxValue] قرار دارد، استفاده می‌شود. ویژگی‌های آن به شرح زیر است:

ControlToValidate
میدانی که مقدار آن باید توسط کامپوننت بررسی شود
EnableClientScript
منطقی – وقتی روی true تنظیم شود، این نشان می‌دهد که محتویات فیلد قبلی نیز باید در سمت کلاینت اعتبارسنجی شود
ErrorMessage
پیام خطایی که کامپوننت باید در صورت تشخیص خطا نمایش دهد
MinValue
حداقل مقدار برای فیلدی که باید بررسی شود
MaxValue
حداکثر مقدار برای فیلدی که باید بررسی شود
Type
نوع مقدار فیلد برای اعتبارسنجی

میدان [CustomValidator] امکان بررسی‌های اعتبارسنجی را فراهم می‌کند که نمی‌توان آن‌ها را با کامپوننت‌های اعتبارسنجی ارائه‌شده توسط ASP.NET انجام داد. این اعتبارسنجی توسط تابعی که توسعه‌دهنده نوشته است انجام می‌شود. این تابع در سمت سرور اجرا می‌شود. از آنجا که اعتبارسنجی می‌تواند در سمت کلاینت نیز انجام شود، توسعه‌دهنده ممکن است نیاز داشته باشد تابعی جاوااسکریپتی توسعه دهد تا در سند HTML گنجانده شود. ویژگی‌های آن به شرح زیر است:

ControlToValidate
میدانی که مقدار آن باید توسط کامپوننت اعتبارسنجی شود
EnableClientScript
منطقی – اگر true باشد، نشان می‌دهد که محتویات فیلد قبلی نیز باید در سمت کلاینت اعتبارسنجی شود
ErrorMessage
پیام خطایی که کامپوننت باید در صورت تشخیص خطا نمایش دهد
ClientValidationFunction
تابعی که باید در سمت کلاینت اجرا شود

کد نمایش صفحه به شرح زیر است:

<%@ 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&#238;trise">Ma&#238;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)
        ' میدان [txtAutreDiplome] نباید خالی باشد اگر [cmbDiplomes]=[autre]
        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] انتخاب می‌کند. اگر مدرک تحصیلی او در فهرست وجود نداشته باشد، می‌تواند گزینه [Autre] را از فهرست انتخاب کند. سپس باید مدرک خود را در فیلد ورودی [txtAutreDiplome] وارد کنند. اگر [Autre] در [cmbDiplomes] انتخاب شده باشد، فیلد [txtAutreDiplome] نباید خالی باشد. اگر هیچ‌یک از [Autre] یا [?] در [cmbDiplomes] انتخاب نشده باشد، آنگاه فیلد [txtAutreDiplome] باید خالی باشد. این مورد توسط تابع مرتبط با کامپوننت [CustomValidator1] بررسی می‌شود.
  • سال فارغ‌التحصیلی باید در بازه مشخص‌شده در [1900-2004] قرار داشته باشد. این مورد توسط [RangeValidator1] بررسی می‌شود. با این حال، اگر کاربر فیلد را خالی بگذارد، تابع اعتبارسنجی برای [RangeValidator1] استفاده نمی‌شود. بنابراین، کامپوننت [RequiredFieldValidator2] برای بررسی اینکه فیلد حاوی داده است، اضافه می‌شود. این یک قاعده کلی است. محتویات یک فیلد در صورتی که خالی باشد، بررسی نمی‌شوند. تنها استثنا زمانی است که فیلد با کامپوننت [RequiredFieldValidator] مرتبط باشد.

در اینجا مثالی از یک اجرای برنامه در مرورگر [Mozilla] آورده شده است:

Image

اگر از مرورگر [IE6] استفاده کنیم، می‌توانیم یک تابع اعتبارسنجی سمت کلاینت برای کامپوننت [CustomValidator1] اضافه کنیم. برای این کار، این کامپوننت دارای ویژگی‌های زیر است:

  • EnableClientScript=true
  • ClientValidationFunction=chkAutreDiplome

تابع [chkAutreDiplome ] به شرح زیر است:

<head>
    <meta http-equiv="pragma" content="no-cache" />
    <script language="javascript">
        function chkAutreDiplome(source,args){
             //اعتبار میدان 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] را می‌گیرد:

  • منبع: ابجکتی که رویداد را فعال کرده است
  • args: رویداد. این دارای یک ویژگی به نام [IsValid] است که اگر داده‌های اعتبارسنجی‌شده صحیح باشند، باید توسط تابع روی true تنظیم شود. مقدار false باعث نمایش پیام خطای مرتبط در محل کامپوننت اعتبارسنجی می‌شود و فرم برای سرور ارسال نخواهد شد.

8.2.5. RegularExpressionValidator

ما در حال ساخت صفحه [regularexpressionvalidator1.aspx] زیر هستیم:

Image

خیر.
name
نوع
ویژگی‌ها
نقش
1
txtMel
TextBox
EnableViewState=true
میدان ورودی
2
RequiredFieldValidator3
RequiredFieldValidator
ControlToValidate=txtMel
نمایش=پویا
کامپوننت اعتبارسنجی برای کنترل [1]
3
RegularExpressionValidator1
RegularExpressionValidator
ControlToValidate=txtMel
نمایش=پویا
کامپوننت اعتبارسنجی برای کنترل [1]
4
btnEnvoyer
دکمه
EnableViewState=false
ValidationReasons=true
دکمه [submit]

در اینجا، می‌خواهیم فرمت یک آدرس ایمیل را اعتبارسنجی کنیم. این کار را با استفاده از یک کامپوننت [RegularExpressionValidator] انجام می‌دهیم که به ما امکان می‌دهد یک فیلد را با استفاده از یک عبارت منظم (regular expression) اعتبارسنجی کنیم. شایان ذکر است که عبارت منظم، الگویی برای یک رشته از کاراکترها است. بنابراین، محتویات یک فیلد را با این الگو مطابقت می‌دهیم. از آنجایی که محتویات یک فیلد در صورت خالی بودن بررسی نمی‌شوند، ما همچنین به یک کامپوننت [RequiredFieldValidator] نیاز داریم تا بررسی کند که آدرس ایمیل خالی نیست. کلاس [RegularExpressionValidator] دارای خواصی مشابه با کلاس‌های کامپوننت که قبلاً پوشش داده شده‌اند، است:

ControlToValidate
field که مقدار آن باید توسط کامپوننت بررسی شود
EnableClientScript
بولی – وقتی روی true تنظیم شود، این نشان می‌دهد که محتویات فیلد قبلی نیز باید در سمت کلاینت اعتبارسنجی شود
ErrorMessage
پیام خطایی که کامپوننت باید در صورت تشخیص خطا نمایش دهد
RegularExpression
بیان منظم (regular expression) که محتوای [ControlToValidate] بر اساس آن بررسی خواهد شد
Display
حالت نمایش: ایستا: فیلد همیشه موجود است حتی اگر پیام خطا نمایش ندهد؛ پویا: فیلد فقط در صورتی که پیام خطا وجود داشته باشد، موجود است؛ هیچ: پیام خطا نمایش داده نمی‌شود. این فیلد برای سایر اجزا نیز وجود دارد اما تا به حال استفاده نشده است.

الگوی عبارت منظم برای یک آدرس ایمیل می‌تواند به شکل زیر باشد: \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. ValidationSummary

به دلایل زیبایی‌شناختی، ممکن است بخواهید پیام‌های خطا را در یک مکان واحد گروهبندی کنید، همانند مثال زیر [summaryvalidator1.aspx]، که در آن تمام مثال‌های قبلی را در یک صفحه گردآوری کرده‌ایم:

Image

تمام کنترل‌های اعتبارسنجی دارای ویژگی‌های زیر هستند:

  • [Display=Dynamic] که تضمین می‌کند کنترل‌ها در صورتی که پیام خطای آن‌ها خالی باشد، هیچ فضایی در صفحه اشغال نکنند
  • [EnableClientScript=false] برای غیرفعال کردن تمام اعتبارسنجی‌های سمت کلاینت
  • [Text=*]. این پیامی است که در صورت بروز خطا نمایش داده می‌شود؛ محتوای ویژگی [ErrorMessage] خود توسط کنترل [ValidationSummary] نمایش داده می‌شود که در ادامه ارائه می‌دهیم.

این مجموعه کنترل‌ها در داخل یک کامپوننت [Panel] به نام [vueFormulaire] قرار می‌گیرد. در یک کامپوننت دیگر، [Panel]، که با نام [vueErreurs] شناخته می‌شود، یک کنترل با نام [ValidationSummary] قرار می‌دهیم:

Image

خیر.
نام
نوع
ویژگی‌ها
نقش
1
ValidationSummary1
ValidationSummary
متن سربرگ=خطاهای زیر رخ داده است، فعال‌سازی اسکریپت سمت کلاینت=false، نمایش خلاصه=true
نمایش خطاها از تمام کنترل‌های اعتبارسنجی صفحه
2
lnkErreursToFormulaire
LinkButton
CausesValidation=false
لینک بازگشت به فرم

برای لینک [lnkErreursToFormulaire] نیازی به فعال‌سازی اعتبارسنجی نیست، زیرا این لینک هیچ مقداری را برای تأیید ارسال نمی‌کند.

هنگامی که تمام داده‌ها معتبر هستند، نمای زیر به کاربر نمایش داده می‌شود: [infos]:

Image

1

خیر.
نام
نوع
ویژگی‌ها
نقش
1
lblInfo
برچسب
 
پیام اطلاعاتی برای کاربر

کد نمایش این صفحه به شرح زیر است:

<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>

در اینجا چند نمونه از نتایج به‌دست‌آمده آورده شده است. ما نمای [formulaire] را بدون وارد کردن هیچ مقداری اعتبارسنجی می‌کنیم:

Image

دکمه [Envoyer] پاسخ زیر را به ما می‌دهد:

Image

نما [erreurs] نمایش داده شد. اگر از لینک برای بازگشت به فرم استفاده کنیم، آن را در وضعیت زیر می‌یابیم:

Image

این نما [formulaire] است. به کاراکتر [*] در کنار داده‌ی نادرست توجه کنید. این فیلد [Text] از بررسی‌های اعتبارسنجی است که نمایش داده شده است. اگر فیلدها را به درستی پر کنیم، نمای [infos] را خواهیم دید:

Image

کد کنترل صفحه به شرح زیر است:

<%@ Page Language="VB" %>
<script runat="server">

     ' روند اجرایی هنگام بارگذاری صفحه
    Sub page_Load(sender As Object, e As EventArgs)
        'در اولین درخواست، نمای [formulaire] نمایش داده می‌شود
        if not ispostback then
            afficheVues(true,false,false)
        end if
    end sub

    sub afficheVues(byval formulaireVisible as boolean, _
        erreursVisible as boolean, infosVisible as boolean)
         ' مجموعه‌ای از نماها
        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)
        'نمای فرم را نمایش می‌دهد
        afficheVues(true,false,false)
         ' بازبینی اعتبارسنجی‌ها را مجدداً اجرا می‌کند
        Page.validate
    End Sub

    Sub btnEnvoyer_Click(sender As Object, e As EventArgs)
        ' آیا صفحه معتبر است؟
        if not Page.IsValid then
            ' نمایش نما [erreurs]
            afficheVues(false,true,false)
        else
             ' در غیر این صورت نما [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] که برای هر درخواست مشتری اجرا می‌شود، نما [formulaire] نمایش داده می‌شود، در حالی که سایر نماها مخفی هستند. این کار فقط در اولین درخواست انجام می‌شود. این رویه یک رویهٔ کمکی به نام [afficheVues] را فراخوانی می‌کند که سه مقدار بولی به آن ارسال می‌شود تا مشخص کند آیا سه نما نمایش داده شوند یا خیر.
  • هنگامی که رویه [btnEnvoyer_Click] فراخوانی می‌شود، بررسی‌های داده‌ای قبلاً انجام شده است. دکمه [btnEnvoyer]، از طریق خاصیت [CausesValidation=true]، این بررسی‌های داده‌ای را راه‌اندازی می‌کند. تمام کنترل‌های اعتبارسنجی اجرا شده و ویژگی [IsValid] آن‌ها تنظیم شده است. این ویژگی نشان می‌دهد که آیا داده‌های اعتبارسنجی‌شده توسط کنترل معتبر بوده‌اند یا خیر. علاوه بر این، ویژگی [IsValid] خود صفحه نیز تنظیم شده است. این مقدار تنها در صورتی به [vrai] تنظیم می‌شود که مقدار ویژگی [IsValid] تمام بررسی‌های اعتبارسنجی روی صفحه، برابر با [vrai] باشد. بنابراین، رویه [btnEnvoyer_Click] با بررسی اینکه آیا صفحه معتبر است یا خیر، شروع می‌شود. اگر صفحه معتبر نباشد، نما [erreurs] نمایش داده می‌شود. این نما شامل کنترل [ValidationSummary] است که ویژگی‌های [ErrorMessage] را از تمام کنترل‌ها می‌گیرد (به اسکرین‌شات بالا مراجعه کنید). اگر صفحه معتبر باشد، نمای [infos] به همراه یک پیام اطلاعاتی نمایش داده می‌شود.
  • روند [lnkErreursToFormulaire_Click] مسئول نمایش نما [formulaire] در وضعیتی است که در آن اعتبارسنجی شده است. تمام فیلدهای ورودی در نما [formulaire] که دارای ویژگی [EnableViewState=true] هستند، وضعیتشان به‌طور خودکار بازسازی می‌شود. جالب اینجاست که وضعیت اجزای اعتبارسنجی بازیابی نمی‌شود. در واقع می‌توانست انتظار داشت که با بازگشت به نمای [erreurs]، کنترل‌های نامعتبر، فیلد [Text] خود را نمایش دهند. اما این‌طور نیست. بنابراین ما با استفاده از متد [Page.Validate] صفحه، اعتبارسنجی داده‌ها را به اجبار اجرا کردیم. این کار باید پس از قابل مشاهده شدن پنل [vueFormulaire] انجام شود. بنابراین در مجموع دو مرحله اعتبارسنجی وجود دارد. در عمل باید از این امر اجتناب کرد. در اینجا، این مثال به ما امکان داد تا مفاهیم جدیدی را در مورد اعتبارسنجی صفحه معرفی کنیم.

8.3. کامپوننت‌های ListControl و پیوند داده

تعدادی از مؤلفه‌های سرور مورد بررسی امکان نمایش یک فهرست مقادیر را فراهم می‌کنند (DropDownList, ListBox). سایر مؤلفه‌ها که هنوز درباره‌شان بحث نکرده‌ایم، امکان نمایش چندین فهرست مقادیر در جداول را فراهم می‌کنند (HTML). برای همهٔ آن‌ها، از طریق یک برنامه، می‌توان مقادیر فهرست‌ها را یکی‌یکی با مؤلفهٔ مربوطه مرتبط کرد. همچنین امکان اتصال اشیاء پیچیده‌تر به این کامپوننت‌ها نیز وجود دارد، مانند اشیاء از انواع [Array]، [ArrayList]، [DataSet]، [HashTable]، ... که کدی را که داده‌ها را با کامپوننت مرتبط می‌کند، ساده‌تر می‌سازد. این ارتباط به عنوان پیوند داده (data binding) شناخته می‌شود.

تمام کامپوننت‌هایی که از کلاس [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] به شرح زیر است:

DropDownList, ListBox
<option value="V">T</option>
CheckButtonList
<input type="checkbox" value="V">T
RadioButtonList
<input type="radio" value="V">T

یک مؤلفه [ListControl] از طریق ویژگی‌های زیر به یک منبع داده متصل می‌شود:

DataSource
یک منبع داده [Array], [ArrayList], [DataTable], [DataSet], [HashTable], ...
DataMember
که در آن منبع داده یک [DataSet] است، نام جدولی را که باید به‌عنوان منبع داده استفاده شود، نشان می‌دهد. بنابراین منبع داده واقعی یک جدول است.
DataTextField
که در آن منبع داده یک جدول است ([DataTable], [DataSet])، نمایانگر نام ستون جدول است که مقادیر را برای فیلد [Text] عناصر در [ListControl] فراهم می‌کند
DataValueField
که در آن زمانی که منبع داده یک جدول ([DataTable], [DataSet]) است، نمایانگر نام ستون جدول است که مقادیر را برای فیلد [Value] عناصر در [ListControl] فراهم می‌کند

ارتباط یک کامپوننت [ListControl] با یک منبع داده، کامپوننت را با مقادیر منبع داده اولیه نمی‌کند. این کار توسط عملیات [ListControl].DataBind انجام می‌شود.

بسته به ماهیت منبع داده، اتصال آن به یک کامپوننت [ListControl] به شیوه‌های متفاوتی انجام می‌شود:

Array A
[ListControl].DataSource=A
میدان‌های [Text] و [Value] از عناصر در [ListControl] مقادیرشان را از عناصر A خواهند داشت
ArrayList AL
[ListControl].DataSource=AL
fields [Text] و [Value] از عناصر در [ListControl] مقادیرشان را از عناصر در AL خواهند داشت
DataTable DT
[ListControl].DataSource=DT, [ListControl].DataTextField="col1", [ListControl]. DatavalueField ="col2"
که col1 و col2 دو ستون در جدول DT هستند. میدان‌های [Text] و [Value] در عناصر [ListControl] دارای مقادیری خواهند بود که با مقادیر ستون‌های col1 و col2 در جدول DT مطابقت دارند.
DataSet DS
[ListControl].DataSource=DS, [ListControl].DataSource="table", که در آن "table" نام یکی از جدول‌ها در DS است.
[ListControl].DataTextField="col1", [ListControl]. DatavalueField ="col2", که col1 و col2 دو ستون در جدول "table" هستند. میدان‌های [Text] و [Value] از عناصر در [ListControl] دارای مقادیری خواهند بود که با مقادیر ستون‌های col1 و col2 در جدول «table» مطابقت دارند.
HashTable HT
[ListControl].DataSource=HT, [ListControl].DataTextField="key", [ListControl]. DatavalueField = "value"، جایی که [key] و [value] به ترتیب کلیدها و مقادیر HT هستند.

ما این اطلاعات را با استفاده از مثال زیر، [databind1.aspx]، به کار خواهیم بست:

در اینجا پنج پیوند داده داریم که هر یک دارای چهار کنترل از انواع [DropDownList]، [ListBox]، [CheckBoxList] و [RadioButtonList] هستند. این پنج پیوند از نظر منابع داده‌شان متفاوت‌اند:

لینک
منبع داده
1
آرایه
2
ArrayList
3
DataTable
4
DataSet
5
HashTable

8.3.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>

آن‌ها برای لینک‌های ۲ تا ۵ به جز شماره لینک یکسان هستند.

8.3.2. پیوند به یک منبع داده از نوع آرایه

چهار کنترل [ListBox] که در بالا فهرست شده‌اند، در رویه [Page_Load] کد کنترل به شرح زیر مرتبط شده‌اند:

' داده‌های جهانی
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

' روند زمانی اجرا می‌شود که صفحه بارگذاری می‌شود
Sub page_Load(sender As Object, e As EventArgs)
    if not IsPostBack then
      ' منابع داده ایجاد می‌شوند تا به اجزا متصل شوند
      createDataSources
       'لینک به یک آرایه [Array]
      bindToArray
       ' لینک به یک لیست [ArrayList]
      bindToArrayList
       ' لینک به یک جدول [DataTable]
      bindToDataTable
       ' لینک به یک گروه داده [DataSet]
      bindToDataSet
       ' پیوند به یک فرهنگ لغت [HashTable]
      bindToHashTable
    end if
End Sub

sub createDataSources
   'منابع داده‌ای را ایجاد می‌کند که به کامپوننت‌ها متصل خواهند شد
  ' arraylist
  dim i as integer
  for i=0 to textes.length-1
    myDataListe.add(textes(i))
  next
   ' جدول داده
   'دو ستون آن را تعریف می‌کند
  myDataTable.Columns.Add("id",Type.GetType("System.Int32"))
  myDataTable.Columns.Add("texte",Type.GetType("System.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
   'مجموعه داده‌ها  یک جدول واحد
  myDataSet.Tables.Add(myDataTable)
  'جدول هش
  for i=0 to textes.length-1
    myHashTable.add(valeurs(i),textes(i))
  next
end sub

' پیوند آرایه
sub bindToArray
         ' ارتباط با مؤلفه‌ها
        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
        ' انتخاب عناصر
        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

منبع داده [myDataListe] در رویه [createDataSources] مقداردهی اولیه می‌شود:

' داده‌های جهانی
dim textes() as string={"un","deux","trois","quatre"}
dim myDataListe as new ArrayList
..

' روندی که هنگام بارگذاری صفحه اجرا می‌شود
Sub page_Load(sender As Object, e As EventArgs)
    if not IsPostBack then
      'منابع داده‌ای که باید به اجزا متصل شوند ایجاد می‌شوند
      createDataSources
...
    end if
End Sub

sub createDataSources
   'منابع داده‌ای را ایجاد می‌کند که به کامپوننت‌ها متصل خواهند شد
  ' آرایه‌فهرست
  dim i as integer
  for i=0 to textes.length-1
    myDataListe.add(textes(i))
  next
...
end sub

چهار کنترل [ListBox] برای لینک ۲ به شرح زیر در رویه [bindToArrayList] کد کنترل مرتبط شده‌اند:

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

' داده‌های سراسری
dim textes() as string={"un","deux","trois","quatre"}
dim myDataTable as new DataTable("table1")
...

' روندی که هنگام بارگذاری صفحه اجرا می‌شود
Sub page_Load(sender As Object, e As EventArgs)
    if not IsPostBack then
      ' ایجاد منابع داده برای پیوند با مؤلفه‌ها
      createDataSources
...
    end if
End Sub

sub createDataSources
   'منابع داده‌ای را ایجاد می‌کند که به کامپوننت‌ها متصل خواهند شد
...
   'جدول داده
   ' تعریف دو ستون آن
  myDataTable.Columns.Add("id",Type.GetType("System.Int32"))
  myDataTable.Columns.Add("texte",Type.GetType("System.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
...
end sub

ما با ایجاد یک شیء [DataTable] با دو ستون: [id] و [texte] شروع می‌کنیم. ستون [id] فیلد [Value] را برای عناصر [ListControl] پر می‌کند و ستون [texte] فیلدهای [Text] آن‌ها را پر می‌کند. جدول [DataTable] که شامل دو ستون است، به شرح زیر ساخته شده است:

  myDataTable.Columns.Add("id",Type.GetType("System.Int32"))
  myDataTable.Columns.Add("texte",Type.GetType("System.String"))

بنابراین ما یک جدول با دو ستون ایجاد می‌کنیم:

  • اولی که «id» نام دارد، از نوع عدد صحیح است
  • دومی، با نام «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] خواهد بود، در حالی که ستون [texte] شامل مقادیر جدول [data] خواهد بود. پس از انجام این کار، جدول [dataListe] پر می‌شود. چهار کنترل [ListBox] در لینک ۳ در رویه [bindToDataTable] کد کنترل به شرح زیر مرتبط شده‌اند:

sub bindToDataTable
         'پیوند به کامپوننت‌ها
        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
        ' انتخاب عناصر
        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] با تخصیص موارد زیر به هر یک از آن‌ها پیوند داده می‌شود:

            .DataSource= myDataTable
            .DataValueField="id"
            .DataTextField="texte"

جدول [myDataTable] منبع داده است. ستون [id] در این جدول، فیلدهای [Value] عناصر مؤلفه را پر می‌کند، در حالی که ستون [texte] فیلدهای [Text] آن‌ها را پر می‌کند.

8.3.5. منبع داده از نوع DataSet

منبع داده [myDataSet] در رویه [createDataSources] مقداردهی اولیه می‌شود:

' داده‌های جهانی
dim myDataTable as new DataTable("table1")
dim myDataSet as new DataSet
...


' روند اجرا هنگام بارگذاری صفحه
Sub page_Load(sender As Object, e As EventArgs)
    if not IsPostBack then
      'منابع داده‌ای که باید به مؤلفه‌ها متصل شوند ایجاد می‌شوند
      createDataSources
...
    end if
End Sub

sub createDataSources
   'منابع داده‌ای را ایجاد می‌کند که به کامپوننت‌ها متصل خواهند شد
   'مجموعه داده  یک جدول واحد
  myDataSet.Tables.Add(myDataTable)
...
end sub

یک شیء [DataSet] نمایانگر مجموعه‌ای از جداول از نوع [DataTable] است. جدول [myDataTable] که قبلاً ایجاد شده است، به [DataSet] اضافه می‌شود. چهار کنترل [ListBox] در لینک ۴ به شرح زیر در رویه [bindToDataSet] کد کنترل پیوند داده شده‌اند:

sub bindToDataSet
         'لینک‌دهی به کامپوننت‌ها
        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
        'انتخاب عناصر
        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] به منبع داده به شرح زیر متصل می‌شود:

            .DataSource= myDataSet
            .DataMember="table1"
            .DataValueField="id"
            .DataTextField="texte"

گروه داده [myDataSet] منبع داده است. از آنجا که این ممکن است شامل چندین جدول باشد، نام جدول مورد استفاده در [DataMember] مشخص شده است. ستون [id] در این جدول، فیلدهای [Value] عناصر جزئی را پر می‌کند، در حالی که ستون [texte] فیلدهای [Text] آن‌ها را پر می‌کند.

8.3.6. منبع داده از نوع HashTable

منبع داده [myHashTable] در رویه [createDataSources] مقداردهی اولیه می‌شود:

' داده‌های جهانی
dim textes() as string={"un","deux","trois","quatre"}
dim valeurs() as string={"1","2","3","4"}
dim myHashTable as new HashTable
...

' روند اجرا شده هنگام بارگذاری صفحه
Sub page_Load(sender As Object, e As EventArgs)
    if not IsPostBack then
      'منابع داده‌ای که باید به مؤلفه‌ها متصل شوند ایجاد می‌شوند
      createDataSources
...
    end if
End Sub

sub createDataSources
   'منابع داده‌ای را ایجاد می‌کند که به کامپوننت‌ها متصل خواهند شد
...
  'جدول هش
  for i=0 to textes.length-1
    myHashTable.add(valeurs(i),textes(i))
  next
end sub

واژه‌نامه [myHashTable] را می‌توان به صورت جدولی با دو ستون به نام‌های «کلید» و «مقدار» در نظر گرفت. ستون [key] نمایانگر کلیدهای واژه‌نامه است و ستون [value] نمایانگر مقادیر مرتبط با آن‌هاست. ستون [key] شامل محتویات آرایه [valeurs] است و ستون [value] شامل محتویات آرایه [textes] است. این منبع به کنترل‌ها در رویه [bindToHashTable] پیوند داده شده است:

sub bindToHashTable
         'لینک‌دهی به کامپوننت‌ها
        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
        'انتخاب عناصر
        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

برای هر مؤلفه، پیوند با استفاده از دستورالعمل‌های زیر برقرار می‌شود:

            .DataSource=myHashTable
            .DataValueField="key"
            .DataTextField="value"

منبع داده، فرهنگ لغت [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. نمایش منبع داده آرایه‌ای: ArrayList، DataTable، DataSet

کامپوننت [DataGrid] به منابع داده از انواع [Array]، [ArrayList]، [DataTable] و [DataSet] را در جدولی از نوع HTML نمایش دهید. برای این چهار نوع داده، کافی است منبع را با خاصیت [DataSource] از کامپوننت [DataGrid] مرتبط کنید:

DataSource
یک منبع داده [Array], [ArrayList], [DataTable], [DataSet], ...
DataMember
جایی که منبع داده یک [DataSet] است، این نشان‌دهنده نام جدولی است که باید به عنوان منبع داده استفاده شود. بنابراین منبع داده واقعی یک جدول است. اگر این فیلد خالی گذاشته شود، تمام جداول در [DataSet] نمایش داده می‌شوند.

اکنون صفحه [datagrid1.aspx] را ارائه می‌دهیم که وابستگی یک [DataGrid] را به چهار منبع داده مختلف نشان می‌دهد:

Image

این صفحه شامل چهار مؤلفه [DataGrid] است که با استفاده از [WebMatrix] به شرح زیر ساخته شده‌اند. این مؤلفه کشیده شده و در موقعیت مورد نظر در برگه [Design] رها می‌شود:

Image

سپس یک جدول عمومی HTML رسم می‌شود. ویژگی‌های یک [DataGrid] را می‌توان در زمان طراحی تعریف کرد. این کاری است که ما در اینجا برای ویژگی‌های قالب‌بندی آن انجام می‌دهیم. برای این کار، [DataGrid] مورد نظر را برای پیکربندی انتخاب می‌کنیم. ویژگی‌های آن در پنجره‌ای در پایین سمت راست ظاهر می‌شوند:

Image

ما از دو پیوند بالا استفاده خواهیم کرد. پیوند [Générateur de propriétés] دسترسی به ویژگی‌های اصلی [DataGrid] را فراهم می‌کند:

Image

ما تیک گزینه [Afficher l'en-tête] را برای چهار کامپوننت [DataGrid] برداشته و صفحه را ذخیره می‌کنیم. لینک دیگر، [Mise en forme automatique]، به شما امکان می‌دهد از میان چندین استایل برای جدول HTML که نمایش داده خواهد شد، انتخاب کنید:

Image

ما [couleur 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">

     'داده‌های کلی
        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

        ' روشی که هنگام بارگذاری صفحه اجرا می‌شود
        Sub page_Load(sender As Object, e As EventArgs)
            if not IsPostBack then
              'منابع داده‌ای که باید به اجزا متصل شوند ایجاد می‌شوند
              createDataSources
               'لینک به یک آرایه [Array]
              bindToArray
               ' لینک به یک لیست [ArrayList]
              bindToArrayList
               ' لینک به یک جدول [DataTable]
              bindToDataTable
               ' پیوند به یک گروه داده [DataSet]
              bindToDataSet
            end if
        End Sub

        sub createDataSources
           'منابع داده‌ای را ایجاد می‌کند که به کامپوننت‌ها متصل خواهند شد
          ' فهرست آرایه‌ای
          dim i as integer
          for i=0 to textes1.length-1
            myDataListe.add(textes1(i))
          next
           ' جدول داده
           'دو ستون آن را تعریف می‌کند
          myDataTable.Columns.Add("id",Type.GetType("System.Int32"))
          myDataTable.Columns.Add("texte1",Type.GetType("System.String"))
          myDataTable.Columns.Add("texte2",Type.GetType("System.String"))
          ' جدول پر می‌شود
          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
           'مجموعه داده  یک جدول واحد
          myDataSet.Tables.Add(myDataTable)
        end sub

        ' پیوند آرایه
        sub bindToArray
          with DataGrid1
            .DataSource=textes1
            .DataBind
          end with
        end sub

        ' پیوند فهرست آرایه‌ای
        sub bindToArrayList
          with DataGrid2
            .DataSource=myDataListe
            .DataBind
          end with
        end sub

        ' پیوند داداشبکه
        sub bindToDataTable
          with DataGrid3
            .DataSource=myDataTable
            .DataBind
          end with
        end sub

        ' پیوند مجموعه داده
        sub bindToDataSet
          with DataGrid4
            .DataSource=myDataSet
            .DataBind
          end with
        end sub

</script>
<html>
...
</html>

کد تا حد زیادی شبیه به مثال قبلی است، بنابراین به طور خاص در مورد آن توضیحی نمی‌دهیم. با این حال، توجه کنید که پیوند داده‌ها چگونه انجام می‌شود. برای هر یک از چهار کنترل، توالی زیر کافی است:

          with [DataGrid]
            .DataSource=[source de données]
            .DataBind
          end with

که در آن [source de données] از نوع [Array] یا [ArrayList] یا [DataTable] یا [DataSet] است. بنابراین می‌توانیم ببینیم که این یک ابزار قدرتمند برای نمایش داده‌ها در جداول است:

  • قالب‌بندی با استفاده از [WebMatrix] یا هر IDE دیگری در مرحله طراحی انجام می‌شود
  • ارتباط داده در کد برقرار می‌شود. با [WebMatrix]، این کار در زمان طراحی قابل انجام است اگر منبع داده یک پایگاه داده سرور SQL یا یک پایگاه داده ACCESS باشد. در این صورت، باید یک کامپوننت از نوع [SqlDataSource] یا [AccessDataSource] روی شیت قرار داده شود. این کامپوننت می‌تواند در زمان طراحی به منبع داده فیزیکی، یعنی پایگاه داده سرور SQL یا پایگاه داده ACCESS، بسته به مورد، متصل شود. اگر یک شیء [SqlDataSource] یا [AccessDataSource] که به یک منبع فیزیکی متصل است به ویژگی [DataSource] یک مؤلفه [DataGrid] اختصاص داده شود، آنگاه، در حالت طراحی، داده‌های واقعی در کامپوننت [DataGrid] ظاهر خواهند شد.

8.5. ViewState برای اجزای فهرست داده

در اینجا هدف ما برجسته کردن مکانیزم [VIEWSATE] برای اجزای فهرست داده است. دو روش برای حفظ وضعیت یک جزء فهرست داده بین دو درخواست مشتری وجود دارد:

  • ویژگی [VIEWSTATE] آن را روی true تنظیم کنید
  • ویژگی [VIEWSTATE] آن را روی false تنظیم کرده و منبع داده‌های آن را در جلسه (session) ذخیره کنید تا بتوان در درخواست بعدی، این کامپوننت را به آن منبع متصل کرد.

مثال زیر جنبه‌های خاصی از مکانیزم [VIEWSTATE] برای محفظه‌های داده را نشان می‌دهد. در اولین درخواست کلاینت، برنامه نمای زیر را نمایش می‌دهد:

خیر.
name
نوع
ویژگی‌ها
نقش
۱
DataGrid1
DataGrid
EnableViewState=true
منبع داده S را نمایش می‌دهد
2
DataGrid2
DataGrid
EnableViewState=true
منبع یکسان S را مانند [DataGrid1] نمایش می‌دهد
3
Button1
دکمه
EnableViewState=false
دکمه [submit]

کامپوننت [DataGrid1] توسط مکانیزم [VIEWSTATE] نگهداری می‌شود. ما در حال بررسی هستیم که آیا این مکانیزم، که نمایش [DataGrid1] را در هر درخواست مجدداً تولید می‌کند، منبع داده‌های آن را نیز مجدداً تولید می‌کند یا خیر. برای این منظور، منبع داده‌ها به کامپوننت [DataGrid2] متصل شده است. این کد برای هر درخواست از طریق یک لینک صریح به منبع داده [DataGrid1] تولید می‌شود. همچنین ویژگی [EnableViewState] آن به [vrai] متصل است.

کد ارائهٔ برنامه [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
        'در پرس‌وجوی اول، منبع داده تعریف شده و به اولین جدول داده متصل می‌شود
        If Not IsPostBack Then
            'منبع داده را تعریف می‌کند
            With DataGrid1
                .DataSource = createDataSource()
                .DataBind()
            End With
        End If
        ' برای هر پرس‌وجو، DataGrid2 را به منبع DataGrid اول پیوند دهید
        With Datagrid2
            .DataSource = DataGrid1.DataSource
            .DataBind()
        End With
    End Sub

    Private Function createDataSource() As DataTable
        'منبع داده اولیه شده است
        Dim thèmes As New DataTable
        'ستون‌ها
        With thèmes.Columns
            .Add("id", GetType(System.Int32))
            .Add("thème", GetType(System.String))
            .Add("description", GetType(System.String))
        End With
        'ستون «id» کلید اصلی خواهد بود
        thèmes.Constraints.Add("cléprimaire", thèmes.Columns("id"), True)
        ' رده‌ها
        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] متصل می‌شود.

در طول پرس‌وجوی اول، نمای زیر را به دست می‌آوریم:

Image

کاملاً منطقی است که هر دو مؤلفه منبع داده‌ای را که به آن متصل شده‌اند نمایش می‌دهند. ما از دکمه [Envoyer] برای ارسال درخواست [PostBack] به سرور استفاده می‌کنیم. نمای حاصل سپس به شرح زیر است:

Image

می‌توانیم ببینیم که کامپوننت [DataGrid1] مقدار خود را حفظ کرده است، اما کامپوننت [DataGrid2] این کار را نکرده است. توضیح:

  • حتی پیش از شروع رویه [Page_Load]، اشیاء [DataGrid1] و [DataGrid2] به دلیل مکانیزم [viewstate]، به مقادیر قبلی خود در پرس‌وجوی پیشین بازگشته‌اند. در واقع، هر دو خاصیت [EnableViewState] خود را روی [vrai] تنظیم کرده‌اند.
  • روال [Page_Load] اجرا می‌شود. از آنجا که این شامل یک عملیات [PostBack] است، کامپوننت [DataGrid1] توسط [Page_Load] تغییر نمی‌کند (به کد مراجعه کنید). بنابراین مقدار بازیابی‌شده توسط [viewstate] را حفظ می‌کند. این موضوع در تصویر بالا نشان داده شده است.
  • از سوی دیگر، کامپوننت [DataGrid2] از طریق [DataBind] به منبع داده [DataGrid1.DataSource] متصل است. بنابراین، آن دوباره ساخته می‌شود و مقداری که به تازگی از طریق [viewstate] به دست آورده بود، از بین می‌رود. بنابراین در اینجا ترجیح داده می‌شد که خاصیت آن از [EnableViewState] به [faux] تنظیم شود تا از مدیریت وضعیت غیرضروری جلوگیری شود. اسکرین بالا نشان می‌دهد که [DataGrid2] به یک منبع خالی متصل شده است. از آنجایی که این منبع [DataGrid1.DataSource] است، می‌توان نتیجه گرفت که اگرچه مکانیزم [viewstate] در واقع نمایش کامپوننت [DataGrid1] را بازیابی می‌کند، اما ویژگی‌های آن، مانند [DataSource] را بازیابی نمی‌کند.

از این مثال چه نتیجه‌ای می‌توان گرفت؟ شما باید از تنظیم خاصیت [EnableViewState] یک مخزن داده روی [vrai] خودداری کنید، اگر قرار است به یک منبع داده برای هر پرس‌وجو پیوند (DataBind) داده شود. با این حال، موارد خاصی وجود دارد که حتی در این سناریو، ویژگی [EnableViewState] کانتینر باید روی [vrai] باقی بماند؛ در غیر این صورت، رویدادهایی که می‌خواهیم مدیریت کنیم، فعال نخواهند شد. بعداً با مثالی از این مورد مواجه خواهیم شد.

اغلب منبع دادهٔ یک مخزن داده در طول پرس‌وجوها تغییر می‌کند. بنابراین برای هر پرس‌وجو لازم است مخزن را به منبع داده متصل کرد. معمولاً منبع داده در محدودهٔ جلسه قرار می‌گیرد تا پرس‌وجوها بتوانند به آن دسترسی داشته باشند. مثال دوم ما این مکانیزم را نشان می‌دهد. برنامه تنها یک نما ارائه می‌دهد:

خیر.
نام
نوع
ویژگی‌ها
نقش
۱
DataGrid1
DataGrid
EnableViewState=true
منبع داده S را نمایش می‌دهد
2
DataGrid2
DataGrid
EnableViewState=false
منبع یکسان S را مانند [DataGrid1] نمایش می‌دهد
3
Button1
دکمه
EnableViewState=false
دکمه [submit]
4
lblInfo1
lblInfo2
lblInfo3
برچسب
EnableViewState=false
متن‌های اطلاعاتی

کامپوننت [DataGrid1] تنها در طول اولین پرس‌وجو به داده‌ها متصل می‌شود. این کامپوننت به لطف مکانیزم کامپوننت [viewstate]، مقدار خود را در پرس‌جوهای بعدی حفظ خواهد کرد. کامپوننت [DataGrid2] به یک منبع داده برای هر درخواست متصل است، که در هر درخواست جدید یک عنصر به آن اضافه می‌شود. بنابراین لازم است که کامپوننت [DataGrid2] به هر درخواست متصل (DataBind) شود. بنابراین، ما ویژگی [EnableViewState] آن را به [faux]، همان‌طور که قبلاً توصیه شده بود، تنظیم کرده‌ایم. بدین ترتیب، در پرسش دوم (با استفاده از دکمه [Envoyer])، پاسخ زیر را دریافت می‌کنیم:

Image

کامپوننت [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&nbsp;:
                <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
        ' در پرس‌وجوی اول، منبع داده تعریف شده و به اولین گرید داده متصل می‌شود
        If Not IsPostBack Then
            'منبع داده را تعریف می‌کند
            dtThèmes = createDataSource()
            With DataGrid1
                .DataSource = dtThèmes
                .DataBind()
            End With
            ' ذخیره اطلاعات در جلسه
            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
        ' با هر پرس‌وجو یک تم جدید اضافه می‌شود
        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)
        'DataGrid2 را به منبع داده متصل می‌کند
        With Datagrid2
            .DataSource = dtThèmes
            .DataBind()
        End With
        ' اطلاعات درباره تعداد درخواست‌ها
        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
        ' اطلاعاتی در جلسه ذخیره می‌شود
        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
        'در اولین درخواست، منبع داده تعریف شده و به اولین DataGrid متصل می‌شود
        If Not IsPostBack Then
            'منبع داده را تعریف می‌کند
            dtThèmes = createDataSource()
            With DataGrid1
                .DataSource = dtThèmes
                .DataBind()
            End With
            ' ذخیره اطلاعات در جلسه
            Session("source") = dtThèmes
...
        End If
        'با هر درخواست، یک تم جدید اضافه می‌شود
        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)
        'داده‌گرید2 را به منبع داده متصل می‌کند
        With Datagrid2
            .DataSource = dtThèmes
            .DataBind()
        End With
...
    End Sub

کامپوننت [DataGrid1] تنها در طول اولین پرس‌وجو به منبع داده S متصل می‌شود (نه IsPostBack). سپس در جلسه (session) قرار می‌گیرد. پس از آن دیگر در جلسه قرار نخواهد گرفت. منبع داده S که در جلسه قرار گرفته است، در هر پرس‌وجو بازیابی می‌شود و یک سطر جدید به آن اضافه می‌گردد. کامپوننت [DataGrid2] در هر پرس‌وجو به‌طور صریح به منبع داده S متصل می‌شود. به همین دلیل است که محتوای آن با هر پرس‌وجو یک سطر افزایش می‌یابد. مشاهده می‌شود که پس از تغییر محتوای منبع داده S، آن به‌طور صریح از طریق عملیاتی دوباره در جلسه قرار داده نمی‌شود:

            Session("source") = S

چرا این اتفاق می‌افتد؟ وقتی یک درخواست آغاز می‌شود، جلسه شامل یک شی Session("source") از نوع [DataTable] است که منبع داده را همان‌طور که در درخواست قبلی بود نگه می‌دارد. بیایید این شی Session("source") را S بنامیم. وقتی می‌نویسیم:


        dtThèmes = CType(Session("source"), DataTable)

[dtThèmes] و [S] دو مرجع به یک شی واحد، یعنی [DataTable]، هستند. بنابراین، هنگامی که کد مربوط به [Page_Load] یک عنصر را به جدولی که توسط [dtThèmes] ارجاع شده اضافه می‌کند، همزمان آن را به جدولی که توسط [S] ارجاع شده نیز اضافه می‌کند. در پایان اجرای صفحه، تمام اشیاء حاضر در جلسه ذخیره خواهند شد، از جمله شیء Session("source")، c.a.d. S، c.a.d و [dtThèmes] ذخیره خواهند شد. بنابراین در واقع محتوای جدید منبع داده است که ذخیره می‌شود. نیازی نبود نوشت:

            Session("source") = dtThèmes

برای انجام این ذخیره، از آنجا که 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
        'در اولین درخواست، منبع داده تعریف شده و به اولین DataGrid متصل می‌شود
....
            ' ذخیره اطلاعات در جلسه
            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
        'با هر پرس‌وجو، یک تم جدید اضافه می‌شود
....
        ' اطلاعات درباره تعداد پرس‌وجوها
        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
        ' برخی اطلاعات در جلسه ذخیره می‌شوند
        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

شمارنده‌های درخواست در سه عنصر ذخیره می‌شوند:

  • numRequête1 و numRequête2 از نوع [Integer] – [Integer] یک کلاس نیست بلکه یک ساختار است
  • numRequête3 از نوع [entier] – [entier] کلاسی است که برای این منظور تعریف شده است

وقتی می‌نویسید:


        numRequête1 = CType(Session("numRequête1"), Integer)
..
        numRequête2 = CType(Session("numRequête2"), Integer)
..
        numRequête3 = CType(Session("numRequête3"), entier)
..
  • ساختار [Session("numRequête1")] به [numRequête1] کپی می‌شود. بنابراین، هنگامی که عنصر [numRequête1] تغییر می‌یابد، عنصر [Session("numRequête1")] تغییر نمی‌یابد.
  • همین امر در مورد [Session("numRequête2")] و [numRequête2] نیز صدق می‌کند.
  • عناصر [Session("numRequête3")] و [numRequête3] هر دو ارجاع به یک شیء از نوع [entier] هستند. شیء ارجاع‌شده را می‌توان از طریق هر یک از این ارجاعات تغییر داد.

از این می‌توان نتیجه گرفت که نیازی به نوشتن زیر نیست:

        Session("numRequête3") = numRequête3

برای ذخیره مقدار جدید [numRequête3] در جلسه. در عوض، باید نوشت:

        Session("numRequête1") = numRequête1
        Session("numRequête2") = numRequête2

برای ذخیره مقادیر جدید ساختارهای [numRequête1] و [numRequête2]. ما این کار را فقط برای [numRequête2] انجام می‌دهیم، که توضیح می‌دهد چرا در اسکرین‌شاتی که پس از پرس‌وجوی دوم به دست آمده، شمارنده برای [numRequête1] نادرست است.

بنابراین مهم است بدانیم که وقتی داده‌ها یک‌بار در یک جلسه بارگذاری می‌شوند، اگر توسط یک شیء نمایش داده شوند، نیازی به بارگذاری مجدد مکرر ندارند. در موارد دیگر، اگر تغییر کرده باشند، باید دوباره بارگذاری شوند.

8.6. نمایش لیست داده‌ها با استفاده از یک DataGrid صفحه‌بندی‌شده و مرتب‌شده

کامپوننت [DataGrid] به شما امکان می‌دهد محتوای یک [DataSet] را نمایش دهید. تاکنون، ما همیشه فایل‌های [DataSet] خود را به صورت دستی ساخته‌ایم. این بار، ما از یک فایل [DataSet] که از یک پایگاه داده بازیابی شده است، استفاده می‌کنیم. ما در حال ساخت برنامه MVC زیر هستیم:

این سه نما در قالب کانtejnerها در کد ارائه کنترل‌کننده [main.aspx] گنجانده خواهند شد. در نتیجه، این برنامه دارای یک صفحه واحد به نام [main.aspx] است.

8.6.1. کلاس‌های کسب‌وکار

کلاس [produits] دسترسی به پایگاه داده زیر ACCESS را فراهم می‌کند:

Image

کد کلاس [produits] به شرح زیر است:


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)
            ' رشته اتصال ذخیره می‌شود
            Me.chaineConnexionOLEDB = chaineConnexionOLEDB
        End Sub

        Public Function getDataSet(ByVal commande As String) As DataSet
            'یک شیء DataAdapter برای خواندن داده‌ها از منبع OLEDB ایجاد می‌شود
            Dim adaptateur As New OleDbDataAdapter(commande, chaineConnexionOLEDB)
            'یک نمایش در حافظه از نتیجه عبارت SELECT ایجاد می‌کند
            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
            ' نتیجه بازگردانده می‌شود
            Return contenu
        End Function
    End Class
End Namespace

پایگاه داده ACCESS از طریق درایور OLEDB مدیریت خواهد شد. سازنده کلاس [produits] با رشته اتصال، شناسگر، درایور OLEDB و پایگاه داده قابل مدیریت تأمین می‌شود. کلاس [produits] دارای متدی به نام [getDataSet] است که یک [DataSet] حاصل از اجراییک پرس‌وجوی SQL، [select]، که متنش به‌عنوان پارامتر ارسال می‌شود. در طول این متد، چندین عملیات انجام می‌شود: برقراری اتصال به پایگاه داده، اجرای پرس‌وجوی [select] و بستن اتصال. تمام این مراحل ممکن است منجر به ایجاد یک استثنا شود که در اینجا مدیریت می‌شود. یک برنامهٔ آزمایشی ممکن است به این شکل باشد:

Option Explicit On 
Option Strict On

' فضاهای نام
Imports System
Imports System.Data
Imports Microsoft.VisualBasic

Namespace st.istia.univangers.fr

     ' صفحه آزمایشی
    Module testproduits
        Sub Main(ByVal arguments() As String)
             ' محتویات جدول محصولات را نمایش می‌دهد
             'جدول در یک پایگاه داده به نام ACCESS قرار دارد که pg نام فایل خود را از آن می‌گیرد
            Const syntaxe1 As String = "pg bdACCESS"

             'بررسی پارامترهای برنامه
            If arguments.Length <> 1 Then
                 ' پیام خطا
                Console.Error.WriteLine(syntaxe1)
                 'پایان
                Environment.Exit(1)
            End If

             ' آماده‌سازی رشته اتصال
            Dim chaineConnexion As String = "Provider=Microsoft.Jet.OLEDB.4.0; Ole DB Services=-4; Data Source=" + arguments(0)

             ' ایجاد یک شیء محصولات
            Dim objProduits As produits = New produits(chaineConnexion)

             ' بازیابی جدول محصولات در یک مجموعه داده
            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

             ' نمایش محتویات آن
            Dim lignes As DataRowCollection = contenu.Tables(0).Rows
            For i As Integer = 0 To lignes.Count - 1
                 ' ردیف 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. دیدگاه‌ها

حالا که کلاس دسترسی به داده‌ها را داریم، کنترلرها و ویوهایی را برای این برنامه وب می‌نویسیم. ابتدا بیایید ببینیم چگونه کار می‌کند. اولین ویو به شرح زیر است:

خیر.
نام
نوع
ویژگی‌ها
نقش
۱
txtSelect
TextBox
EnableViewState=true
میدان ورودی پرس‌وجوی 'SELECT'
2
RequiredFieldValidator1
RequiredFieldValidator
EnableViewState=false
بررسی وجود ۱
3
txtPages
TextBox
EnableViewState=true
میدان ورودی – تعداد سطرهای داده‌ای را که در هر صفحه نتایج نمایش داده می‌شود مشخص می‌کند
4
RequiredFieldValidator2
RequiredFieldValidator
EnableViewState=false
وجود ۳ را بررسی می‌کند
۵
RangeValidator1
RangeValidator
EnableViewState=false
تأیید می‌کند که (3) در محدوده [1,30] قرار دارد
6
btnExécuter
دکمه
EnableViewState=false
دکمه [submit]

ما این نما را نمای [formulaire] می‌نامیم. این نما به کاربر اجازه می‌دهد تا یک پرس‌وجوی SELECT SQL را روی پایگاه داده [produits.mdb] اجرا کند. اجرای این پرس‌وجو یک نمای جدید ایجاد می‌کند:

خیر.
نام
نوع
ویژگی‌ها
نقش
۱
lblSelect
برچسب
EnableViewState=false
میدان اطلاعاتی
2
rdCroissant
rdDécroissant
RadioButton
EnableViewState=false
GroupName=rdTri
امکان انتخاب ترتیب مرتب‌سازی را برای شما فراهم می‌کند
۳
DataGrid1
DataGrid
EnableViewState=true
AllowPaging=true
AllowSorting=true
جدول نمایش نتایج انتخاب
۴
lnkRésultats
LinkButton
EnableViewState=false
دکمه لینک [submit]

ما این نما را نمای [résultats] می‌نامیم. این نما شامل [DataGrid] است که نتیجه دستور انتخاب SQL را نمایش می‌دهد. کاربر ممکن است در پرس‌وجوی خود اشتباه کند. برخی خطاها به لطف بررسی‌های اعتبارسنجی در نمای [erreurs] علامت‌گذاری خواهند شد.

Image

سایر خطاها در نمای [erreurs] علامت‌گذاری خواهند شد:

Image

نما [erreurs] نمایش داده می‌شود:

خیر.
نام
نوع
ویژگی‌ها
نقش
۱
erreursHTML
متغیر
 
برای نمایش خطاها، کد HTML لازم است
۳
lnkForm2
LinkButton
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>&nbsp;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&#233;c&#233;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&#233;c&#233;dent" ...></PagerStyle>
                    </asp:DataGrid></P>
AllowPaging="true"
فعال‌سازی پیجینیشن
PageSize="4"
چهار خط داده در هر صفحه
NextPageText="Suivant"
متن لینک برای رفتن به صفحه بعدی منبع داده
PrevPageText="Précédent"
متن لینک برای رفتن به صفحه قبلی منبع داده

این اطلاعات را می‌توان مستقیماً در ویژگی‌های تگ <asp:datagrid> وارد کرد. همچنین می‌توانید از [WebMatrix] استفاده کنید. در پنجرهٔ ویژگی‌ها برای [DataGrid]، پیوند [Générateur de propriétés] را دنبال کنید:

Image

این کار، جادوگر زیر را باز می‌کند:

Image

گزینه [Pagination] را انتخاب کنید:

Image

مقادیر ویژگی‌های پیجینیشن برای [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]

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

[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)
        'ایجاد یک شیء محصول
        Dim objProduits As produits
        Try
            objProduits = New produits(ConfigurationSettings.AppSettings("OLEDBStringConnection"))
            ' شیء به برنامه اضافه می‌شود
            Application("objProduits") = objProduits
            ' بدون خطا
            Application("erreur") = False
        Catch ex As Exception
            'خطایی رخ داده است؛ این در برنامه ثبت می‌شود
            Application("erreur") = True
            Application("message") = ex.Message
        End Try
    End Sub
End Class

هنگامی که برنامه کاربردی شروع می‌شود (Application_Start)، ما یک شیء [produits] ایجاد کرده و آن را در برنامه کاربردی قرار می‌دهیم تا برای تمام درخواست‌ها از سوی همه کلاینت‌ها در دسترس باشد. اگر در حین این ایجاد یک خطا (exception) رخ دهد، در برنامه کاربردی ثبت می‌شود. روال [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

    ' اجزای صفحه
    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
    ' داده‌های صفحه
    Protected erreursHTML As String

    Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        'بررسی کنید که آیا برنامه با خطایی مواجه شده است
        If CType(Application("erreur"), Boolean) Then
            ' برنامه به درستی راه‌اندازی نشده است
            Dim erreurs As New ArrayList
            erreurs.Add("Application momentanément indisponible (" + CType(Application("message"), String) + ")")
            afficheErreurs(erreurs, False)
            Exit Sub
        End If
        'اولین درخواست
        If Not IsPostBack Then
            'نمایش فرم خالی
            afficheFormulaire()
        End If
    End Sub

    Private Sub afficheErreurs(ByVal erreurs As ArrayList, ByVal afficheLien As Boolean)
        'نمای خطاها را نمایش می‌دهد
        erreursHTML = ""
        For i As Integer = 0 To erreurs.Count - 1
            erreursHTML += "<li>" + erreurs(i).ToString + "</li>" + ControlChars.CrLf
        Next
        lnkErreurs.Visible = afficheLien
        'نمایش نمای [erreurs]
        vueErreurs.Visible = True
        vueFormulaire.Visible = False
        vueRésultats.Visible = False
    End Sub

    Private Sub afficheFormulaire()
        'نما نمایش داده می‌شود [formulaire]
        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)
        'کنترل‌ها را راه‌اندازی می‌کند
        lblSelect.Text = sqlTexte
        With DataGrid1
            .DataSource = données
            .PageSize = CType(txtPages.Text, Integer)
            .CurrentPageIndex = 0
            .DataBind()
        End With
        'نمای [résultats] نمایش داده می‌شود
        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
        'آیا صفحه معتبر است؟
        If Not Page.IsValid Then
            afficheFormulaire()
            Exit Sub
        End If

        ' اجرای پرس‌وجوی کلاینت SELECT
        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
        'همه چیز خوب است – نمایش نتایج
        afficheRésultats(txtSelect.Text.Trim, données)
        'ذخیرهٔ داده‌ها در جلسه
        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
        ' مجموعهٔ نماها
        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
        ' تغییر صفحه
        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
        'مرتب‌سازی نمای داده
        Dim données As DataView = CType(Session("données"), DataView)
        données.Sort = e.SortExpression + " " + CType(IIf(rdCroissant.Checked, "asc", "desc"), String)
        ' نمایش آن
        With DataGrid1
            .CurrentPageIndex = 0
            .DataSource = données
            .DataBind()
        End With
    End Sub
End Class

وقتی صفحه [Page_Load] بارگذاری می‌شود، ابتدا بررسی می‌کنیم که آیا برنامه به درستی راه‌اندازی شده است یا خیر. در غیر این صورت، نما [erreurs] را بدون لینک بازگشت به فرم نمایش می‌دهیم، زیرا این لینک در آن صورت غیرضروری است. در واقع، تنها نمای [erreurs] می‌تواند در صورتی که برنامه به درستی راه‌اندازی نشده باشد، نمایش داده شود. در غیر این صورت، اگر این اولین درخواست مشتری باشد، نمای [formulaire] را نمایش می‌دهیم. مابقی را به خواننده واگذار می‌کنیم تا کد را درک کند. ما صرفاً بر روی سه رویه تمرکز خواهیم کرد: رویه [btnExécuter_Click]، که زمانی اجرا می‌شود که کاربر درخواست اجرای پرس‌وجوی SQL را که در نمای [formulaire] وارد شده است، داده باشد، روال [DataGrid1_PageIndexChanged]، که زمانی اجرا می‌شود کهکاربر از لینک‌های [Suivant] و [Précédent] در [DataGrid] استفاده می‌کند، و رویه [DataGrid1_SortCommand]، که زمانی اجرا می‌شود که کاربر برای مرتب‌سازی داده‌ها در یک سرستون کلیک می‌کندفرمان مرتب‌سازی، صعودی یا نزولی، توسط دو دکمه رادیویی مرتب‌سازی تعیین می‌شود.

در رویه [btnExécuter_Click]، بنابراین ابتدا بررسی می‌کنیم که آیا صفحه معتبر است یا خیر. وقتی رویه [btnExécuter_Click] اجرا می‌شود، بررسی‌های مربوط به کنترل‌های اعتبارسنجی مختلف روی صفحه قبلاً انجام شده است. برای هر کنترل اعتبارسنجی، دو ویژگی تعیین شده است:

IsValid
در صورتی که داده‌های بررسی‌شده معتبر باشند روی true و در غیر این صورت روی false تنظیم می‌شود
ErrorMessage
پیام خطا در صورتی که داده‌های بررسی‌شده نامعتبر تشخیص داده شوند

برای خود صفحه، یک ویژگی [IsValid] تنظیم شده است. این مقدار تنها در صورتی روی true تنظیم می‌شود که تمام بررسی‌های اعتبارسنجی ویژگی [IsValid] خود را روی true تنظیم کرده باشند. در غیر این صورت، نمای [formulaire] باید نمایش داده شود. این نما شامل بررسی‌های اعتبارسنجی است که ویژگی [errorMessage] خود را نمایش خواهند داد. اگر صفحه معتبر باشد، از شیء از نوع [produits] که توسط [Application_Start] ایجاد شده است، برای به دست آوردن [DataSet] متناظر با اجرای پرس‌وجوی SELECT SQL استفاده می‌شود. سپس این به یک شیء [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] مشتق‌شده از کلاس [produits] تنها شامل یک جدول است، یعنی جدولی که از عبارت [select] حاصل شده است. یک جدول را می‌توان مرتب‌سازی کرد، در حالی که یک [DataSet] را نمی‌توان؛ با این حال، ما به مرتب‌سازی داده‌های به‌دست‌آمده علاقه‌مند هستیم. برای کار با جدول نتیجه از [select]، می‌توانستیم بنویسیم:


        Dim données As DataTable
        Try
            données = CType(Application("objProduits"), produits).getDataSet(txtSelect.Text.Trim).Tables(0)
...

شیء [DataTable]، اگرچه یک جدول پایگاه داده را نشان می‌دهد، روش مرتب‌سازی ندارد. برای این کار، به یک نما (view) از جدول نیاز دارید. یک نما (view) شیئی از نوع [DataView] است. شما می‌توانید با استفاده از فیلترها، نماهای مختلفی از یک جدول واحد داشته باشید. یک جدول دارای یک نمای پیش‌فرض است که همان نمایی است که در آن هیچ فیلتری تعریف نشده است. بنابراین نمای پیش‌فرض، کل جدول را نشان می‌دهد. این نمای پیش‌فرض از طریق [DataTable.DefaultView] به دست می‌آید. یک نما را می‌توان با استفاده از خاصیت [sort] آن مرتب‌سازی کرد، که بعداً به آن باز خواهیم گشت.

اگر [DataSet] کلاس [produits] با موفقیت بازیابی شود، نمای [résultats] نمایش داده می‌شود؛ در غیر این صورت، نمای [erreurs] نمایش داده می‌شود. نما [résultats] توسط رویه [afficheRésultats] نمایش داده می‌شود که دو پارامتر به آن ارسال می‌شود:

  • متنی که باید در برچسب [lblSelect] قرار گیرد
  • [DataView] که باید به [DataGrid1] پیوند داده شود

این مثال انعطاف‌پذیری فوق‌العادهٔ مؤلفهٔ [DataGrid] را نشان می‌دهد. این مؤلفه قادر است ساختار [DataView] را که به آن متصل است تشخیص دهد و خود را با آن تطبیق دهد. در نهایت، رویه [btnExécuter_Click]، [DataView] را که به‌تازگی به‌دست آورده است، در جلسه کاربر ذخیره می‌کند تا زمانی که کاربر صفحات دیگری را از همان [DataView] درخواست کند، در دسترس باشد.

روند [DataGrid1_PageIndexChanged] زمانی اجرا می‌شود که کاربر روی پیوندهای [Suivant] و [Précédent] در [DataGrid] کلیک می‌کند. این روند دو پارامتر دریافت می‌کند:


    Private Sub DataGrid1_PageIndexChanged(ByVal source As Object, ByVal e As System.Web.UI.WebControls.) Handles DataGrid1.PageIndexChanged
source
شیئی که رویداد را فعال کرده است – در این مورد، یکی از لینک‌های [Suivant] یا [Précédent]
e
اطلاعات مربوط به رویداد. ویژگی e.NewPageIndex شماره صفحه‌ای است که در پاسخ به درخواست مشتری نمایش داده می‌شود

کد کامل برای رویدادپرداز به شرح زیر است:


    Private Sub DataGrid1_PageIndexChanged(ByVal source As Object, ByVal e As System.Web.UI.WebControls.DataGridPageChangedEventArgs) Handles DataGrid1.PageIndexChanged
        'تغییر صفحه
        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
source
شیء‌ای که رویداد را تحریک کرده است – در این مورد، یکی از لینک‌های [Suivant] یا [Précédent]
e
اطلاعات مربوط به رویداد. ویژگی [e.SortExpression] نام ستونی است که برای مرتب‌سازی کلیک شده است

کد کامل برای رویدادپرداز به شرح زیر است:


    Private Sub DataGrid1_SortCommand(ByVal source As Object, ByVal e As System.Web.UI.WebControls.DataGridSortCommandEventArgs) Handles DataGrid1.SortCommand
        'مرتب‌سازی نمای داده‌ها
        Dim données As DataView = CType(Session("données"), DataView)
        données.Sort = e.SortExpression + " " + CType(IIf(rdCroissant.Checked, "asc", "desc"), String)
        ' نمایش آن
        With DataGrid1
            .CurrentPageIndex = 0
            .DataSource = données
            .DataBind()
        End With
    End Sub

ما [DataView] را که توسط [DataGrid] در جلسهٔ جاری نمایش داده شده است، بازیابی می‌کنیم. این رویهٔ [btnExécuter_Click] بود که آن را آنجا قرار داد. کامپوننت [DataView] دارای خاصیت [Sort] است که عبارت مرتب‌سازی به آن اختصاص داده شده است. این از نحو [select ... order by expr1, expr2, ...] پیروی می‌کند، که در آن هر [expri] می‌تواند با کلمه کلیدی [asc] برای مرتب‌سازی صعودی یا [desc] برای مرتب‌سازی نزولی دنبال شود. بیان [order by] که در اینجا استفاده شده، [order by colonne asc/desc] است. ویژگی [e.SortExpression] نام ستونی را در [DataGrid] که برای مرتب‌سازی کلیک شده است، در اختیار ما قرار می‌دهد. مجموعه کاراکتری [asc/desc] بر اساس مقادیر دکمه‌های رادیویی در گروه [rdTri] تنظیم می‌شود. هنگامی که عبارت مرتب‌سازی برای [DataView] تنظیم شد، [DataGrid] با آن مرتبط می‌شود. [DataGrid] در صفحهٔ اول خود قرار دارد.

8.7. کامپوننت DataList و پیوند داده

اکنون به کامپوننت [DataList] می‌پردازیم. این کامپوننت گزینه‌های قالب‌بندی بیشتری نسبت به [DataGrid] ارائه می‌دهد، اما انعطاف‌پذیری کمتری دارد. در نتیجه، این کامپوننت نمی‌تواند به طور خودکار خود را با منبع داده‌ای که به آن متصل است وفق دهد. این تطبیق در صورت لزوم باید از طریق کد انجام شود. اگر ساختار منبع داده از قبل مشخص باشد، این کامپوننت گزینه‌های قالب‌بندی‌ای را ارائه می‌دهد که ممکن است آن را به [DataGrid] ترجیح دهد.

8.7.1. برنامه

برای نشان دادن نحوه استفاده از [DataList]، ما در حال ساخت یک برنامه MVC مشابه برنامه قبلی هستیم:

سه نما در قالب کانtejنرها در کد ارائه کنترل‌کننده [main.aspx] گنجانده خواهند شد. در نتیجه، این برنامه دارای یک صفحه واحد است: [main.aspx].

8.7.2. کلاس‌های کسب‌وکار

کلاس [produits] مانند قبل است.

8.7.3. ویوها

هنگامی که کاربر اولین درخواست خود را به برنامه ارسال می‌کند، نمای زیر، [résultats1]، به او نمایش داده می‌شود:

خیر.
نام
نوع
ویژگی‌ها
نقش
۱
RadioButton1
RadioButton2
RadioButton
EnableViewState=false
به شما امکان می‌دهد یکی از دو سبک را برای [DataList] انتخاب کنید
2
btnChanger
دکمه
EnableViewState=false
دکمه [submit]
3
DataList1
DataList
EnableViewState=true
حوزه نمایش لیست داده‌ها

اگر کاربر سبک شمارهٔ ۲ را انتخاب کند، نمای زیر به او نمایش داده می‌شود: [résultats2]:

خیر
نام
نوع
ویژگی‌ها
نقش
1
DataList2
DataList
EnableViewState=true
حوزه نمایش لیست داده

نما [erreurs] مشکل دسترسی به منبع داده را گزارش می‌دهد:

خیر.
نام
نوع
ویژگی‌ها
نقش
۱
erreursHTML
متغیر
 
کد 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("name") %>
                            <br>
                            prix :
                            <%# databinder.eval(Container.DataItem,"price","{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("name") %>
                            , prix :
                            <%# databinder.eval(Container.DataItem,"price","{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] تعریف کرد:

HeaderTemplate
قالب سربرگ برای [DataList]
ItemTemplate
قالب برای خطوط نمایش آیتم‌ها در فهرست داده‌های مرتبط. تنها این قالب الزامی است.
AlternatingItemTemplate
برای تمایز بصری بین آیتم‌های متوالی نمایش داده شده، می‌توان از دو قالب استفاده کرد: ItemTemplate برای آیتم n، و AlternatingItemTemplate برای آیتم n+1
SelectedItemTemplate
قالب برای عنصر انتخاب‌شده در [DataList]
SeparatorTemplate
قالب جداکننده بین دو عنصر در [DataList]
EditItemTemplate
[DataList] اجازه می‌دهد مقادیر نمایش‌داده‌شده توسط آن ویرایش شوند. [EditItemTemplate] قالب یک عنصر در [DataList] است که حالت «ویرایش» در آن فعال است.
FooterTemplate
قالب فوتر برای [DataList]

کامپوننت [DataList1] با استفاده از [WebMatrix] ایجاد شده است. در پنجرهٔ ویژگی‌های آن، لینک [Mise en forme automatique] انتخاب شده است:

1234567

همانطور که در بالا نشان داده شده است، اسکیمای [Couleur 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>

هیچ قالب‌هایی تعریف نشده‌اند. این وظیفه بر عهده ماست. ما قالب‌های زیر را تعریف می‌کنیم:

HeaderTemplate

                        <HeaderTemplate>
                            Contenu de la table [liste] de la base [produits]
                        </HeaderTemplate>
ItemTemplate

                        <ItemTemplate>
                            nom :
                            <%# Container.DataItem("name") %>
                            <br>
                            prix :
                            <%# DataBinder.Eval(Container.DataItem,"price","{0:C}") %>
                            <br>
                        </ItemTemplate>

شایان ذکر است که مدل [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}) %> ستون [prix] ردیف جاری را به صورت پولی (قالب C=Currency) نمایش خواهد داد.

بنابراین ما یک [DataList] خواهیم داشت که به این شکل به نظر می‌رسد:

Image

در مثال بالا، داده‌ها با چهار ورودی در هر خط مرتب شده‌اند. این با استفاده از ویژگی‌های زیر برای [DataList] انجام می‌شود:

RepeatDirection
افقی
RepeatColumns
تعداد ستون‌های مورد نیاز

در نهایت، کد مربوط به [DataList1] همان کدی است که کمی پیش‌تر در کد نمایش ارائه شد. بررسی کد نمایش برای [DataList2] را به خواننده واگذار می‌کنیم. مانند کامپوننت [DataGrid]، بیشتر ویژگی‌های [DataList] را می‌توان با استفاده از یک جادوگر برای [WebMatrix] تنظیم کرد. برای این کار، از پیوند [Générateur de propriétés] در پنجرهٔ ویژگی‌های [DataList] استفاده کنید:

8.7.5. کنترل‌کننده‌ها

کنترل‌کننده [global.asax, global.asax.vb] به شرح زیر است:

[global.asax]

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

[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)
        ' ما یک شیء محصول ایجاد می‌کنیم
        Try
            Dim données As DataSet = New produits(ConfigurationSettings.AppSettings("OLEDBStringConnection")).getDataSet("select * from LISTE")
            ' شیء به برنامه اضافه می‌شود
            Application("données") = données
            ' بدون خطا
            Application("erreur") = False
        Catch ex As Exception
            'خطایی رخ داده است؛ این در برنامه ثبت می‌شود
            Application("erreur") = True
            Application("message") = ex.Message
        End Try
    End Sub
End Class

هنگامی که برنامه شروع می‌شود (Application_Start)، ما یک [dataset] را از کلاس تجاری [produits] ایجاد کرده و آن را در برنامه قرار می‌دهیم تا برای تمام درخواست‌ها از سوی همه کلاینت‌ها در دسترس باشد. اگر در حین این ایجاد خطایی رخ دهد، در برنامه ثبت می‌شود. رویه [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

    'اجزای صفحه
    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
    ' داده‌های صفحه
    Protected erreursHTML As String

    Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        'بررسی می‌کند که آیا برنامه با خطایی مواجه شده است
        If CType(Application("erreur"), Boolean) Then
            ' برنامه به درستی راه‌اندازی نشده است
            Dim erreurs As New ArrayList
            erreurs.Add("Application momentanément indisponible (" + CType(Application("message"), String) + ")")
            afficheErreurs(erreurs, False)
            Exit Sub
        End If
        'اولین درخواست
        If Not IsPostBack Then
            ' ابتدایی‌سازی کنترل‌ها
            With DataList1
                .DataSource = CType(Application("données"), DataSet)
                .DataBind()
            End With
            With DataList2
                .DataSource = CType(Application("données"), DataSet)
                .DataBind()
            End With
            ' نمایش فرم خالی
            afficheRésultats(True, False)
        End If
    End Sub

    Private Sub afficheErreurs(ByVal erreurs As ArrayList, ByVal afficheLien As Boolean)
        ' نمایش صفحهٔ خطاها
        erreursHTML = ""
        For i As Integer = 0 To erreurs.Count - 1
            erreursHTML += "<li>" + erreurs(i).ToString + "</li>" + ControlChars.CrLf
        Next
        'نمایش نما [erreurs]
        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)
        'نمای [résultats] را نمایش می‌دهد
        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
        ' سبک را تغییر می‌دهد
        afficheRésultats(RadioButton1.Checked, RadioButton2.Checked)
    End Sub
End Class

8.8. کامپوننت تکرارکننده و پیوند داده

کامپوننت [Repeater] به شما امکان می‌دهد کد HTML را برای هر آیتم در یک لیست داده تکرار کنید. فرض کنید می‌خواهید لیستی از خطاها را به شکل زیر نمایش دهید:

Image

ما قبلاً با این مشکل مواجه شده‌ایم و آن را با افزودن یک متغیر در کد نمایش به شکل <% =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] در صورتی که منبع داده چندین ستون داشته باشد، نمایانگر یک سطر از داده‌ها است. اگر منبع تنها یک ستون داشته باشد، این نمایانگر یک نقطه داده واحد است. در اینجا نیز همین حالت برقرار است. به‌عنوان مثال، ما در حال ساخت اپلیکیشن زیر هستیم:

Image

کد نمایش صفحه به شرح زیر است:

<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">

     ' روندی که هنگام بارگذاری صفحه اجرا می‌شود
    Sub page_Load(sender As Object, e As EventArgs)
        if not IsPostBack then
          'یک منبع داده ایجاد می‌شود
          with Repeater1
              .DataSource=createDataSource
              .DataBind
          end with
        end if
    End Sub

    function createDataSource as ArrayList
      ' یک 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. Application

در اینجا، ما در حال بازنگری یک برنامه‌ای هستیم که قبلاً با استفاده از کامپوننت‌های سرور پیاده‌سازی شده است. این برنامه امکان شبیه‌سازی محاسبه مالیات را فراهم می‌کند. این برنامه به کلاسی به نام [impot] متکی است که در اینجا به آن نمی‌پردازیم. این کلاس به داده‌هایی نیاز دارد که از یک منبع داده به نام OLEDB بازیابی می‌کند. برای اهداف این مثال، از یک منبع داده به نام ACCESS استفاده خواهیم کرد. در این نسخه ویژگی‌های جدید زیر را معرفی می‌کنیم:

  • استفاده از کامپوننت‌های اعتبارسنجی برای بررسی صحت داده‌ها
  • استفاده از کامپوننت‌های سمت سرور متصل به منابع داده برای نمایش نتایج

8.9.1. ساختار MVC برنامه

ساختار MVC برنامه به شرح زیر است:

سه نما در قالب کانتینرها در کد ارائه کنترل‌کننده [main.aspx] گنجانده خواهند شد. در نتیجه، این برنامه دارای یک صفحه واحد به نام [main.aspx] است.

8.9.2. نماهای برنامه

ویوی [formulaire] فرم وارد کردن اطلاعاتی است که برای محاسبه مالیات کاربر استفاده می‌شود:

Image

کاربر فرم را تکمیل می‌کند:

Image

آنها با استفاده از دکمه [Envoyer] درخواست محاسبه مالیات می‌کنند. سپس نمای زیر، [simulations]، به آنها نمایش داده می‌شود:

Image

آنها از طریق لینک بالا به فرم بازمی‌گردند. آنها آن را در وضعیتی می‌یابند که در آن وارد شده بود. ممکن است در وارد کردن داده‌ها خطاهایی رخ دهد:

Image

این موارد در صفحه [formulaire] برجسته شده‌اند:

Image

سپس کاربر این خطاها را اصلاح می‌کند. او می‌تواند شبیه‌سازی‌های بیشتری را اجرا کند:

Image

سپس نمای [simulations] به آنها ارائه می‌شود که شامل یک شبیه‌سازی اضافی است:

Image

در نهایت، اگر منبع داده در دسترس نباشد، کاربر در نمای [erreurs] از این موضوع مطلع می‌شود:

Image

8.9.2.1. کد ارائه

به یاد داشته باشید که صفحه [main.aspx] تمام نماها را گرد هم می‌آورد. این یک فرم واحد با سه کانتینر است:

  • [panelform] برای نما [formulaire]
  • [panelerreurs] برای نما [erreurs]
  • [panelsimulations] برای نمای [simulations]

اکنون اجزای این سه کانتینر را با جزئیات بررسی خواهیم کرد. کانتینر [panelform] نمای بصری زیر را دارد:

خیر.
نام
نوع
ویژگی‌ها
نقش
0
panelform
پنل
 
نما فرم
1
rdOui
rdNon
RadioButton
نام گروه=rdmarie
دکمه‌های رادیویی
2
cvMarie
CustomValidator
پیام خطا=شما وضعیت تأهل خود را مشخص نکرده‌اید
EnableClientScript=false
بررسی می‌کند که برنامهٔ کلاینت وضعیت تأهل مورد انتظار را ارسال کرده است
3
txtEnfants
TextBox
 
تعداد فرزندان
4
rfvEnfants
RequiredFieldValidator
پیام خطا=لطفاً تعداد فرزندان را وارد کنید
ControlToValidate=txtChildren
بررسی می‌کند که فیلد [txtEnfants] خالی نباشد
5
rvEnfants
RangeValidator
پیام خطا=یک عدد بین 1 و 30 وارد کنید
ControlToValidate=txtChildren
تأیید می‌کند که مقدار فیلد [txtEnfants] در بازه [1,30] قرار دارد
6
txtSalaire
TextBox
EnableViewState=true
حقوق سالانه
7
rfvSalaire
RequiredFieldValidator
ControlToValidate=txtSalary
پیام خطا=لطفاً حقوق خود را وارد کنید
بررسی می‌کند که فیلد [txtSalaire] خالی نباشد
8
revSalaire
RegularExpressionValidator
ControlToValidate=txtSalary
پیام خطا=حقوق نامعتبر
RegularExpression=\s*\d+\s*
تأیید می‌کند که فیلد [txtSalaire] شامل یک دنباله از اعداد است
9
btnCalculer
دکمه
دلایل اعتبارسنجی=true
دکمه [submit] در فرم – محاسبه مالیات را آغاز می‌کند
10
btnEffacer
دکمه
CausesValidation=false
دکمه [submit] در فرم – فرم را پاک می‌کند

ممکن است از بررسی [cvMarié] که مسئول تأیید این است که کاربر واقعاً یکی از دو دکمه رادیویی را علامت زده، شگفت‌زده شوید. در واقع، اگر از فرم ارسال‌شده توسط سرور استفاده می‌کنند، این باید صادق باشد. از آنجایی که هیچ راهی برای اطمینان از این موضوع وجود ندارد، ما مجبوریم تمام پارامترهای ارسال‌شده را بررسی کنیم. همچنین به ویژگی [CausesValidation=false] دکمه [btnEffacer] توجه کنید. هنگامی که کاربر این دکمه را کلیک می‌کند، داده‌های ارسال‌شده نباید بررسی شوند، زیرا نادیده گرفته خواهند شد.

تمام اجزای کانتینر دارای ویژگی [EnableViewState=false] هستند به جز [panelForm, txtEnfants, txtSalaire, rdOui, rdNon]. کانتینر [panelerreurs] نمای بصری زیر را دارد:

خیر.
نام
نوع
ویژگی‌ها
نقش
0
panelerreurs
پنل
EnableViewState=false
نمايش خطاها
1
rptErreurs
تکرارکننده
EnableViewState=false
فهرستی از خطاها را نمایش می‌دهد

کامپوننت [rptErreurs] به صورت زیر تعریف شده است:


                <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>

فهرست داده‌های مرتبط با مؤلفه [rptErreurs] یک شیء [ArrayList] خواهد بود که شامل فهرستی از پیام‌های خطا است. بنابراین، همان‌طور که در بالا نشان داده شده است، <%# Container.Dataitem%> به پیام خطای جاری اشاره دارد. کانتینر [panelsimulations] نمایش بصری زیر را دارد:

خیر.
نام
نوع
ویژگی‌ها
نقش
0
panelsimulations
پنل
EnableViewState=false
نمایه شبیه‌سازی‌ها
2
lnkForm2
LinkButton
EnableViewState=false
پیوند به فرم
1
dgSimulations
DataGrid
EnableViewState=false
مسئول نمایش شبیه‌سازی‌های قرار داده شده در یک شی [DataTable]

کامپوننت [dgSimulations] زیر [Webmatrix] به صورت زیر پیکربندی شده است. در پنجرهٔ ویژگی‌ها برای [dgSimulations]، لینک [Mise en forme automatique] را انتخاب کرده و اسکیمای [Couleur 3] را انتخاب می‌کنیم:

سپس، همچنان در پنجرهٔ ویژگی‌ها برای [dlgSimulations]، پیوند [Générateur de propriétés] را انتخاب می‌کنیم. درخواست می‌کنیم که سربرگ‌های ستون نمایش داده شوند:

Image

ما گزینه [Colonnes] را برای تعریف چهار ستون [DataGrid] انتخاب می‌کنیم:

Image

ما گزینه [Créer des colonnes automatiquement ...] را لغو انتخاب می‌کنیم. ما خودمان چهار ستون [DataGrid] را تعریف خواهیم کرد. این به یک شیء [DataTable] با چهار ستون به نام‌های «married»، «children»، «salary» و «tax» به ترتیب متصل خواهد شد. برای ایجاد یک ستون در [DataGrid]، گزینه [Colonnes connexe] را انتخاب کرده و از دکمه create همان‌طور که در بالا نشان داده شده است، استفاده می‌کنیم. یک ستون ایجاد می‌شود و می‌توانیم ویژگی‌های آن را تعریف کنیم. ستون اول جدول شبیه‌سازی حاوی ستون «married» از شیء [DataTable] خواهد بود که به [DataGrid] متصل می‌شود. این ستون اول در [DataGrid] در ویزارد به شرح زیر تعریف می‌شود:

Image

Texte de l'en-tête
سرستون، در این مورد «متأهل»
Champ de données
نام ستون در منبع داده که توسط این ستون در [DataGrid] نمایش داده خواهد شد. در اینجا، این ستون «married» در [DataTable] است.

ستون دوم به شرح زیر تعریف می‌شود:

Texte de l'en-tête
فرزندان
Champ de données
فرزندان

ستون سوم به شرح زیر تعریف می‌شود:

Texte de l'en-tête
حقوق سالانه
Champ de données
حقوق
Expression de mise en forme
{0:C} – نمایش ارز برای دریافت نماد یورو

ستون چهارم به شرح زیر تعریف می‌شود:

Texte de l'en-tête
مبلغ مالیات
Champ de données
مالیات
Expression de mise en forme
{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&#233;" HeaderText="Mari&#233;"></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&#244;t" HeaderText="Montant de l'imp&#244;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] به شرح زیر تعریف شده است:

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

فایل [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)
        ' یک شیء Import ایجاد می‌کند
        Dim objImpot As impot
        Try
            objImpot = New impot(New impotsOLEDB(ConfigurationSettings.AppSettings("chaineConnexion")))
            ' شیء به برنامه اضافه می‌شود
            Application("objImpot") = objImpot
            ' بدون خطا
            Application("erreur") = False
        Catch ex As Exception
            'خطایی رخ داده است؛ این در برنامه ثبت می‌شود
            Application("erreur") = True
            Application("message") = ex.Message
        End Try
    End Sub

    Sub Session_Start(ByVal sender As Object, ByVal e As EventArgs)
        ' آغاز جلسه – ایجاد یک لیست خالی از شبیه‌سازی‌ها
        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] اجرا می‌گردد. این رویه تلاش می‌کند یک شی از نوع [impot] ایجاد کند و داده‌های آن را از منبعی از نوع OLEDB دریافت نماید. به خوانندگان توصیه می‌شود در صورت فراموشی، به فصل ۵ که این کلاس در آن تعریف شده است مراجعه کنند. ایجاد شیء [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>

کلید [chaineConnexion] به رشته اتصال منبع 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

    ' متغیرهای محلی

    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
        ' ابتدا وضعیت برنامه را بررسی می‌کنیم
        If CType(Application("erreur"), Boolean) Then
            ' برنامه نتوانست راه‌اندازی شود
            'نمایش نمای خطاها
            Dim erreurs As New ArrayList
            erreurs.Add("Application momentanément indisponible (" + CType(Application("message"), String) + ")")
            afficheErreurs(erreurs)
            Exit Sub
        End If
        ' بدون خطا – در اولین درخواست، فرم را نمایش می‌دهیم
        If Not IsPostBack Then afficheFormulaire()
    End Sub

قبل از شروع پردازش درخواست، اطمینان حاصل می‌کنیم که برنامه به درستی راه‌اندازی شده است. اگر اینطور نباشد، نمای [erreurs] را با استفاده از رویه [afficheErreurs] نمایش می‌دهیم. اگر این اولین درخواست باشد (IsPostBack=false)، نما [formulaire] را با استفاده از [afficheFormulaire] نمایش می‌دهیم.

روشی که نمای [erreurs] را نمایش می‌دهد به شرح زیر است:


    Private Sub afficheErreurs(ByRef erreurs As ArrayList)
        ' فهرست خطاها را بسازید
        With rptErreurs
            .DataSource = erreurs
            .DataBind()
        End With
        'نمایش کانتینرها 
        panelerreurs.Visible = True
        panelform.Visible = False
        panelsimulations.Visible = False
        Exit Sub
    End Sub

این رویه به‌عنوان پارامتر، فهرستی از پیام‌های خطا در [erreurs] از نوع [ArrayList] را دریافت می‌کند. ما به‌سادگی این منبع داده را به مؤلفه [rptErreurs] که مسئول نمایش آن است، متصل می‌کنیم.

روند نمایش نما [formulaire] به شرح زیر است:


    Private Sub afficheFormulaire()
        ' فرم را نمایش می‌دهد
        panelform.Visible = True
        ' بقیهٔ کانتینرها پنهان می‌شوند
        panelerreurs.Visible = False
        panelsimulations.Visible = False
    End Sub

این رویه به سادگی کانتینر [panelform] را قابل مشاهده می‌کند. اجزا با مقدار ارسال‌شده یا قبلی خود (VIEWSTATE) نمایش داده می‌شوند.

وقتی کاربر دکمه [Calculer] را در نمای [formulaire] کلیک می‌کند، یک انتقال از POST به [main.aspx] انجام می‌شود. روند [Page_Load] اجرا می‌شود و پس از آن روند [btnCalculer_Click] اجرا می‌گردد:


    Private Sub btnCalculer_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnCalculer.Click
        'اعتبار داده‌های واردشده بررسی می‌شود؛ در صورت وجود خطا، مشخص می‌شوند
        If Not Page.IsValid Then
            afficheFormulaire()
            Exit Sub
        End If
        ' بدون خطا – مالیات محاسبه می‌شود
        Dim impot As Long = CType(Application("objImpot"), impot).calculer( _
        rdOui.Checked, CType(txtEnfants.Text, Integer), CType(txtSalaire.Text, Long))
        'نتیجه به شبیه‌سازی‌های موجود اضافه می‌شود
        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)
        'شبیه‌سازی‌ها به جلسه اضافه می‌شوند
        Session.Item("simulations") = simulations
        'صفحه شبیه‌سازی‌ها را نمایش دهید
        afficheSimulations(simulations, "Retour au formulaire")
    End Sub

روند با بررسی اعتبار صفحه آغاز می‌شود. باید توجه داشت که وقتی رویه [btnCalculer_Click] اجرا می‌شود، بررسی‌های اعتبارسنجی قبلاً انجام شده و ویژگی [IsValid] صفحه تنظیم شده است. اگر صفحه معتبر نباشد، نما [formulaire] مجدداً نمایش داده می‌شود و رویه خاتمه می‌یابد. کامپوننت‌های اعتبارسنجی نما [formulaire]، که ویژگی [IsValid] آنها در بازه [IsValid] تا [false] است، ویژگی [ErrorMessage] خود را نمایش خواهند داد. اگر صفحه معتبر باشد، مبلغ مالیات با استفاده از شیء از نوع [impot] که هنگام راه‌اندازی برنامه ذخیره شده بود، محاسبه می‌شود. این شبیه‌سازی جدید به فهرست شبیه‌سازی‌های انجام‌شده و ذخیره‌شده در جلسه اضافه می‌شود.

در نهایت، نمای [simulations] توسط رویه زیر [afficheSimulations] نمایش داده می‌شود:


    Private Sub afficheSimulations(ByRef simulations As DataTable, ByRef lien As String)
        ' ارتباط گرید داده با منبع شبیه‌سازی‌ها
        With dgSimulations
            .DataSource = simulations
            .DataBind()
        End With
        ' لینک
        lnkForm2.Text = lien
        'نماها
        panelsimulations.Visible = True
        panelerreurs.Visible = False
        panelform.Visible = False
    End Sub

این رویه دو پارامتر دارد:

  • فهرستی از شبیه‌سازی‌ها در [simulations] از نوع [DataTable]
  • یک متن پیوند در [lien]

منبع داده [simulations] به مؤلفه‌ای که مسئول نمایش آن است، پیوند داده شده است. متن پیوند در خصوصیت [Text] از شیء [LinkButton] در نما ذخیره می‌شود.

وقتی کاربر روی دکمه [Effacer] در نمای [formulaire] کلیک می‌کند، رویه [btnEffacer_click] اجرا می‌شود (همیشه پس از [Page_Load]):


    Private Sub btnEffacer_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnEffacer.Click
        ' فرم خالی را نمایش می‌دهد
        razForm()
        afficheFormulaire()
    End Sub

    Private Sub razForm()
        ' فرم را پاک می‌کند
        rdOui.Checked = False
        rdNon.Checked = True
        txtEnfants.Text = ""
        txtSalaire.Text = ""
    End Sub

کد بالا به اندازه کافی ساده است که نیازی به هیچ‌گونه توضیحی ندارد. اکنون باید کلیک‌های روی لینک‌ها در ویو‌های [erreurs] و [simulations] را مدیریت کنیم:


    Private Sub lnkForm1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles lnkForm1.Click
        ' فرم را نمایش می‌دهد
        afficheFormulaire()
    End Sub

    Private Sub lnkForm2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles lnkForm2.Click
        ' فرم را نمایش می‌دهد
        afficheFormulaire()
    End Sub

هر دو رویه صرفاً نما [formulaire] را نمایش می‌دهند. ما می‌دانیم که فیلدهای این نما بر اساس مقدار ارسال‌شده برای آن‌ها یا مقدار قبلی‌شان تنظیم می‌شوند. در این مورد، POST کلاینت هیچ مقداری برای فیلدهای فرم ارسال نمی‌کند، بنابراین این فیلدها به مقادیر قبلی خود بازمی‌گردند. در نتیجه، فرم با مقادیر واردشده توسط کاربر نمایش داده می‌شود.

8.9.4. آزمایش‌ها

تمام فایل‌های مورد نیاز برنامه در پوشه‌ای به نام <مسیر-برنامه> قرار می‌گیرند:
پوشه [bin] حاوی DLL شامل کلاس‌های [impot]، [impotsData] و [impotsOLEDB] مورد نیاز برنامه است:

خوانندگان در صورت تمایل می‌توانند به فصل ۵ مراجعه کنند که نحوه ایجاد فایل [impot.dll] مذکور را توضیح می‌دهد. پس از انجام این کار، سرور Cassini با پارامترهای (<application-path>,/impots6) راه‌اندازی می‌شود. URL [http://impots6/main.aspx] با استفاده از یک مرورگر وب درخواست می‌شود:

Image

اگر نام فایل ACCESS [impots.mdb] را به [impots1.mdb] تغییر دهید، صفحه زیر را مشاهده خواهید کرد:

Image

8.9.5. نتیجه‌گیری

ما یک برنامه به نام MVC داریم که فقط از کامپوننت‌های سمت سرور استفاده می‌کند. استفاده از این کامپوننت‌ها این امکان را فراهم کرده است که لایهٔ نمایش اپلیکیشن به طور کامل از لایهٔ کنترل آن جدا شود. این امر تا به حال ممکن نبود، زیرا کد نمایش قبلاً شامل متغیرهایی بود که توسط کد کنترل محاسبه می‌شدند و مقادیرشان حاوی کد HTML بود. دیگر اینطور نیست.