Skip to content

8. Servercomponenten ASP - 2

8.1. Introduction

We zetten ons werk aan de gebruikersinterface voort en bekijken:

  • componenten voor gegevensvalidatie
  • hoe gegevens aan servercomponenten kunnen worden gekoppeld
  • de servercomponenten HTML

8.2. Componenten voor gegevensvalidatie

8.2.1. Inleiding

In formuliertoepassingen is het van cruciaal belang om de geldigheid van de ingevoerde gegevens te controleren. In het voorbeeld over de belastingberekening hadden we het volgende formulier:

Image

Zodra we de waarden van dit formulier ontvangen, moeten we de geldigheid van de ingevoerde gegevens controleren: het aantal kinderen en het salaris moeten positieve gehele getallen of nul zijn. Als dat niet het geval is, wordt het formulier teruggestuurd naar de klant zoals het is ingevuld, met foutmeldingen. We hadden dit geval afgehandeld met twee weergaven, één voor het bovenstaande formulier en één voor de fouten:

Image

ASP.NET biedt zogenaamde validatiecomponenten waarmee de volgende gevallen kunnen worden gecontroleerd:

Component
Functie
RequiredFieldValidator
controleert of een veld niet leeg is
CompareValidator
vergelijkt twee waarden met elkaar
RangeValidator
controleert of een waarde tussen twee grenzen ligt
RegularExpressionValidator
controleert of een veld voldoet aan een reguliere uitdrukking
CustomValidator
stelt de ontwikkelaar in staat om eigen validatieregels op te stellen – deze component zou alle andere kunnen vervangen
ValidationSummary
maakt het mogelijk om de foutmeldingen van de voorgaande controles op één plek op de pagina te verzamelen

We zullen nu elk van deze componenten bespreken.

8.2.2. RequiredFieldValidator

We bouwen de volgende pagina [requiredfieldvalidator1.aspx]:

nr.
naam
type
eigenschappen
rol
1
txtNom
TextBox
EnableViewState=true
invoerveld
2
RequiredFieldValidator1
RequiredFieldValidator
EnableViewState=false
EnableClientScript=true
ErrorMessage=Het veld [naam] is verplicht
validatiecomponent
3
btnEnvoyer
Button
EnableViewState=false
Validatieoorzaken=true
knop [submit]

Het veld [RequiredFieldValidator1] wordt gebruikt om een foutmelding weer te geven als het veld [txtNom] leeg is of een reeks spaties bevat. De eigenschappen ervan zijn als volgt:

ControlToValidate
veld waarvan de waarde door de component moet worden gecontroleerd. Wat betekent de waarde van een component? Dit is de waarde van het attribuut [value] van de bijbehorende tag HTML. Voor een [TextBox] is dit de inhoud van het invoerveld, voor een [DropDownList] de waarde van het geselecteerde element.
EnableClientScript
booleaanse waarde – als deze op ‘waar’ staat, geeft dit aan dat de inhoud van het vorige veld ook aan de clientzijde moet worden gecontroleerd. In dat geval wordt het formulier pas door de browser verzonden als het geen fouten bevat. De validatietests worden echter ook op de server uitgevoerd, voor het geval de client bijvoorbeeld geen browser is.
ErrorMessage
de foutmelding die de component moet weergeven wanneer er een fout wordt gedetecteerd

De gegevens op de pagina worden alleen door de validatiecontroles gecontroleerd als de knop of link die de [POST] van de pagina heeft geactiveerd, de eigenschap [CausesValidation=true] heeft. [true] is de standaardwaarde van deze eigenschap.

Laten we deze toepassing uitvoeren. We gebruiken eerst een browser met de eigenschap [Mozilla]:

Image

De code HTML die door [Mozilla] is ontvangen, is als volgt:

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

We zien dat de knop [btnEnvoyer] via het attribuut [onclick] aan een JavaScript-functie is gekoppeld. We merken ook op dat de pagina geen [Javascript]-code bevat. De test [typeof(Page_ClientValidate) == 'function'] zal mislukken en de JavaScript-functie zal niet worden aangeroepen. Het formulier wordt dan naar de server verzonden en deze voert de validatiecontroles uit. Laten we de knop [Envoyer] gebruiken zonder een naam op te geven. Het antwoord van de server is als volgt:

Image

Wat is er gebeurd? Het formulier is naar de server verzonden. De server heeft de code van alle validatiecomponenten op de pagina uitgevoerd. Hier is er maar één. Als ten minste één validatiecomponent een fout detecteert, stuurt de server het formulier terug zoals het is ingevuld (in feite voor de componenten met [EnableViewState=true], met bovendien een foutmelding voor elke validatiecomponent die een fout heeft gedetecteerd. Dit bericht is het attribuut [ErrorMessage] van de validatiecomponent. Dit is het mechanisme dat we hierboven in werking zien. Als we iets in het veld [nom] invoeren, verschijnt het foutbericht niet meer wanneer het formulier wordt gevalideerd:

Image

Laten we nu Internet Explorer gebruiken en de URL [http://localhost/requiredfieldvalidator1.aspx] opvragen. We krijgen de volgende pagina te zien:

Image

De code HTML die door IE is ontvangen, is als volgt:

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

We zien dat deze code veel omvangrijker is dan die welke door [Mozilla] is ontvangen. We zullen hier niet in detail op ingaan. Het verschil komt doordat de server JavaScript-functies heeft opgenomen in het verzonden document HTML. Waarom zijn er twee verschillende HTML-codes, terwijl de door beide browsers opgevraagde URL dezelfde is? We hebben al eerder vermeld dat de ASP.NET-technologie ervoor zorgt dat de server het naar de client verzonden document HTML aanpast aan de mogelijkheden van die client. Er zijn verschillende browsers op de markt die niet allemaal dezelfde mogelijkheden hebben. De browsers van Microsoft en Netscape gebruiken bijvoorbeeld niet dezelfde objectmodellering voor het document dat ze ontvangen. Daardoor vertoont de JavaScript-code voor het bewerken van dit document aan de browserzijde verschillen tussen de twee browsers. Ook hebben de browserfabrikanten opeenvolgende versies van hun browser uitgebracht, waarbij ze de mogelijkheden voortdurend hebben verbeterd. Daardoor kan een document HTML dat door IE5 wordt begrepen, mogelijk niet worden begrepen door IE3. Hierboven zien we een voorbeeld van deze aanpassing van de server aan de client. Om een reden die hier niet nader is toegelicht, was de webserver van mening dat de client [Mozilla] niet in staat was om de JavaScript-code voor validatie te verwerken. Daarom is deze code niet opgenomen in het document HTML dat naar de client is verzonden, en vond de validatie plaats aan de serverzijde. Voor [IE6] is deze JavaScript-code wel opgenomen in het verzonden document HTML, zoals we kunnen zien. Om te zien hoe dit werkt, doen we het volgende experiment:

  • laten we de webserver stoppen
  • gebruik de knop [Envoyer] zonder het veld [nom] in te vullen

We krijgen dan de volgende nieuwe pagina te zien:

Image

Het is inderdaad de browser die de foutmelding heeft weergegeven. De server is namelijk gestopt. We kunnen dit controleren door iets in het veld [nom] in te voeren en op verzenden te klikken. Dit keer is het antwoord als volgt:

Image

Wat is er gebeurd? De browser heeft de JavaScript-code voor de validatie uitgevoerd. Deze code gaf aan dat de pagina geldig was. De browser heeft het formulier daarom verzonden naar de webserver, die echter was uitgeschakeld. De browser merkte dit op en gaf de bovenstaande pagina weer. Als we de server opnieuw opstarten, werkt alles weer normaal.

Wat kunnen we uit dit voorbeeld leren?

  • het nut van het concept van een validatiecomponent, waarmee elk onjuist ingevuld formulier naar de klant kan worden teruggestuurd
  • het nut van de code [VIEWSTATE], waarmee dit formulier precies zo kan worden teruggestuurd als het is ingevuld
  • het aanpassingsvermogen van de server aan zijn client. Deze wordt geïdentificeerd door de header HTTP [User-Agent:] die hij naar de server stuurt. Het is dus niet de server die ‘raadt’ met wie hij te maken heeft. Dit aanpassingsvermogen is van groot belang voor de ontwikkelaar, die zich geen zorgen hoeft te maken over het type client van zijn applicatie.

8.2.3. CompareValidator

We bouwen de volgende pagina [comparevalidator1.aspx]:

Image

nr.
naam
type
eigenschappen
rol
1
cmbChoix1
DropDownList
EnableViewState=true
keuzelijst
2
cmbChoix2
DropDownList
EnableViewState=true
keuzelijst
3
CompareValidator1
CompareValidator
EnableViewState=false
EnableClientScript=true
ErrorMessage=Keuze 1 ongeldig
TeVergelijkenWaarde=?
Operator=Niet gelijk
Type=string
validatiecomponent
4
CompareValidator2
CompareValidator
EnableViewState=false
EnableClientScript=true
ErrorMessage=Keuze 2 is ongeldig
ControlToCompare=?
Operator=Niet gelijk
Type=string
validatiecomponent
5
btnEnvoyer
Button
EnableViewState=false
Validatieoorzaken=true
knop [submit]

De component [CompareValidator] wordt gebruikt om twee waarden met elkaar te vergelijken. De beschikbare operatoren zijn [Equal, NotEqual, LessThan, LessThanEqual, GreaterThan, GreaterThanEqual]. De eerste waarde wordt bepaald door de eigenschap [ControlToValidate], de tweede door [ValueToCompare] als de vorige waarde met een constante moet worden vergeleken, of door [ControlToCompare] als deze moet worden vergeleken met de waarde van een andere component. De belangrijke eigenschappen van de component [CompareValidator] zijn de volgende:

ControlToValidate
veld waarvan de inhoud door de component moet worden gecontroleerd
EnableClientScript
booleaanse waarde – ‘waar’ geeft aan dat de inhoud van het vorige veld ook aan de clientzijde moet worden gecontroleerd
ErrorMessage
de foutmelding die de component moet weergeven wanneer er een fout wordt gedetecteerd
ValeurToCompare
waarde waarmee de waarde van het veld moet worden vergeleken [ControlToValidate]
ControlToCompare
component waarvan de waarde moet worden vergeleken met de waarde van het veld [ControlToValidate]
Operator
vergelijkingsoperator tussen de twee waarden
Type
type van de te vergelijken waarden

De weergavecode van deze pagina is als volgt:

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

De validatievoorwaarden voor de pagina zijn als volgt:

  • de geselecteerde waarde in [cmbChoix1] moet verschillen van de tekenreeks "?". Dit houdt de volgende eigenschappen in voor de component [CompareValidator1]: Operator=NotEqual, ValueToCompare=?, Type=string
  • de waarde die in [cmbChoix2] is geselecteerd, moet verschillen van de waarde die in [cmbChoix1] is geselecteerd. Dit houdt de volgende eigenschappen in voor de component [CompareValidator2]: Operator=NotEqual, ControlToCompare=cmbChoix1, Type=string

We voeren deze applicatie uit. Hieronder volgt een voorbeeld van een pagina die tijdens de communicatie tussen client en server is ontvangen:

Image

Als dezelfde pagina wordt opgevraagd via Internet Explorer 6, wordt er JavaScript-code in opgenomen die ervoor zorgt dat de pagina iets anders werkt. Eventuele fouten worden gemeld zodra de gebruiker de waarde in een van de keuzelijsten wijzigt. Dit verhoogt het gebruiksgemak.

8.2.4. CustomValidator, RangeValidator

We bouwen de volgende pagina [customvalidator1.aspx]:

Image

nr.
naam
type
eigenschappen
rol
1
cmbDiplomes
DropDownList
EnableViewState=true
keuzelijst
2
CompareValidator2
CompareValidator
EnableViewState=false
EnableClientScript=true
ErrorMessage=Ongeldig diploma
Operator=Niet gelijk
ValueToCompare=?
Type=String
validatiecomponent van de controle [1]
3
txtAutreDiplome
TextBox
EnableViewState=false
invoerveld
4
CustomValidator1
CustomValidator
EnableViewState=false
EnableClientScript=true
ErrorMessage=Ongeldige diploma-specificatie
ClientValidationFunction=chkAutreDiplome
validatiecomponent voor het veld [3]
5
txtAnDiplome
TextBox
EnableViewState=false
invoerveld
6
RangeValidator1
RangeValidator
EnableViewState=false
EnableClientScript=true
ErrorMessage=Het jaar van het diploma moet binnen het bereik [1990,2004] liggen
MinValue=1990
MaxValue=2004
Type=Integer
ControlToValidate=txtAnDiplome
validatiecomponent voor veld [5]
7
RequiredFieldValidator2
RequiredFieldValidator
EnableViewState=false
EnableClientScript=true
ErrorMessage=Diploma-jaar vereist
ControlToValidate=txtAnDiplome
validatiecomponent voor het veld [5]
8
btnEnvoyer
Knop
EnableViewState=false
CausesValidation=true
knop [submit]

Het veld [RangeValidator] wordt gebruikt om te controleren of de waarde van een besturingselement tussen de twee grenzen [MinValue] en [MaxValue] ligt. De eigenschappen ervan zijn als volgt:

ControlToValidate
veld waarvan de waarde door de component moet worden gecontroleerd
EnableClientScript
booleaanse waarde – als deze op ‘waar’ staat, geeft dit aan dat de inhoud van het vorige veld ook aan de clientzijde moet worden gecontroleerd
ErrorMessage
de foutmelding die de component moet weergeven als er een fout wordt gedetecteerd
MinValue
minimale waarde van het te controleren veld
MaxValue
maximumwaarde van het te controleren veld
Type
type van de waarde van het te controleren veld

Met het veld [CustomValidator] kunnen validaties worden uitgevoerd die niet mogelijk zijn met de validatiecomponenten die door ASP.NET worden aangeboden. Deze validatie wordt uitgevoerd door een functie die door de ontwikkelaar is geschreven. Deze wordt aan de serverzijde uitgevoerd. Aangezien de controle ook aan de clientzijde kan worden uitgevoerd, kan de ontwikkelaar genoodzaakt zijn een JavaScript-functie te ontwikkelen die hij in het document HTML opneemt. De eigenschappen ervan zijn als volgt:

ControlToValidate
veld waarvan de waarde door de component moet worden gecontroleerd
EnableClientScript
booleaanse waarde – als deze op ‘waar’ staat, geeft dit aan dat de inhoud van het vorige veld ook aan de clientzijde moet worden gecontroleerd
ErrorMessage
de foutmelding die de component moet weergeven als er een fout wordt gedetecteerd
ClientValidationFunction
de functie die aan de clientzijde moet worden uitgevoerd

De code voor de weergave van de pagina is als volgt:

<%@ 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;verwerking</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>

Met het attribuut [OnServerValidate] van de component [CustomValidator] kan worden aangegeven welke functie verantwoordelijk is voor de validatie aan de serverzijde. Hierboven roept de component [CustomValidator1] de volgende procedure [CustomValidator1_ServerValidate_1] aan:

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

    Sub CustomValidator1_ServerValidate_1(sender As Object, e As ServerValidateEventArgs)
        ' het veld [txtAutreDiplome] mag niet leeg zijn als [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>
....

Een validatiefunctie die gekoppeld is aan een component [CustomValidator] ontvangt twee parameters:

  • sender: het object dat de gebeurtenis heeft veroorzaakt
  • e: de gebeurtenis. De procedure moet het attribuut [e.IsValid] op 'waar' zetten als de gecontroleerde gegevens correct zijn, en op 'onwaar' in het tegenovergestelde geval.

Hier worden de volgende controles uitgevoerd:

  • de vervolgkeuzelijst [cmbDiplomes] mag niet de waarde [?] hebben. Dit wordt gecontroleerd door de component [CompareValidator2]
  • de gebruiker selecteert een diploma in de keuzelijst [cmbDiplomes]. Als zijn diploma niet in de lijst voorkomt, kan hij de optie [Autre] uit de lijst selecteren. Vervolgens moet hij zijn diploma invoeren in het invoerveld [txtAutreDiplome]. Als [Autre] is geselecteerd in [cmbDiplomes], dan mag het veld [txtAutreDiplome] niet leeg zijn. Als noch [Autre], noch [?] is geselecteerd in [cmbDiplomes], dan moet het veld [txtAutreDiplome] leeg zijn. Dit wordt gecontroleerd door de functie die is gekoppeld aan de component [CustomValidator1].
  • Het jaar van het behalen van het diploma moet binnen het bereik van [1900-2004] vallen. Dit wordt gecontroleerd door [RangeValidator1]. Als de gebruiker echter niets in het veld invoert, wordt de validatiefunctie van [RangeValidator1] niet gebruikt. Daarom wordt de component [RequiredFieldValidator2] toegevoegd om te controleren of er inhoud aanwezig is. Dit is een algemene regel. De inhoud van een veld wordt niet gecontroleerd als het leeg is. Het enige geval waarin dit wel gebeurt, is wanneer het gekoppeld is aan een component [RequiredFieldValidator].

Hier volgt een voorbeeld van de uitvoering in de browser [Mozilla]:

Image

Als we de browser [IE6] gebruiken, kunnen we een client-side validatiefunctie toevoegen voor de component [CustomValidator1]. Hiervoor heeft deze component de volgende eigenschappen:

  • EnableClientScript=true
  • ClientValidationFunction=chkAutreDiplome

De functie [chkAutreDiplome ] is als volgt:

<head>
    <meta http-equiv="pragma" content="no-cache" />
    <script language="javascript">
        function chkAutreDiplome(source,args){
             // controleert de geldigheid van het veld txtAutreDiplome
            with(document.frmCandidature){
                diplome=cmbDiplomes.options[cmbDiplomes.selectedIndex].text;
                    args.IsValid= !(diplome=="[Autre]" && txtAutreDiplome.value=="")
                        && ! (diplome!="[Autre]" && diplome!="?" && txtAutreDiplome.value!="");
            }
        }
        </script>
</head>

De functie [chkAutreDiplome] ontvangt dezelfde twee parameters als de serverfunctie [CustomValidator1_ServerValidate_1]:

  • bron: het object dat de gebeurtenis heeft veroorzaakt
  • args: de gebeurtenis. Deze heeft een attribuut [IsValid] dat door de functie op ‘waar’ moet worden gezet als de gecontroleerde gegevens correct zijn. Een waarde ‘onwaar’ zorgt ervoor dat op de plaats van de validatiecomponent de bijbehorende foutmelding wordt weergegeven en het formulier niet naar de server wordt verzonden.

8.2.5. RegularExpressionValidator

We bouwen de volgende pagina [regularexpressionvalidator1.aspx]:

Image

nr.
naam
type
eigenschappen
rol
1
txtMel
TextBox
EnableViewState=true
invoerveld
2
RequiredFieldValidator3
RequiredFieldValidator
ControlToValidate=txtMel
Display=Dynamic
validatiecomponent van het besturingselement [1]
3
RegularExpressionValidator1
RegularExpressionValidator
ControlToValidate=txtMel
Display=Dynamic
validatiecomponent van het besturingselement [1]
4
btnEnvoyer
Knop
EnableViewState=false
CausesValidation=true
knop [submit]

Hier willen we het formaat van een e-mailadres controleren. Dat doen we met een component [RegularExpressionValidator] waarmee de geldigheid van een veld kan worden gecontroleerd met behulp van een reguliere expressie. Ter herinnering: een reguliere expressie is een patroon van tekenreeksen. We controleren dus de inhoud van een veld aan de hand van een patroon. Aangezien de inhoud van een veld niet wordt gecontroleerd als het leeg is, hebben we ook een component [RequiredFieldValidator] nodig om te controleren of het e-mailadres niet leeg is. De klasse [RegularExpressionValidator] heeft eigenschappen die vergelijkbaar zijn met die van de reeds besproken componentklassen:

ControlToValidate
veld waarvan de waarde door de component moet worden gecontroleerd
EnableClientScript
booleaanse waarde – als deze op ‘waar’ staat, geeft dit aan dat de inhoud van het vorige veld ook aan de clientzijde moet worden gecontroleerd
ErrorMessage
de foutmelding die de component moet weergeven als er een fout wordt gedetecteerd
RegularExpression
de reguliere expressie waarmee de inhoud van [ControlToValidate] wordt vergeleken
Display
weergavemodus: Static: het veld is altijd aanwezig, zelfs als er geen foutmelding wordt weergegeven; Dynamic: het veld is alleen aanwezig als er een foutmelding is; None: de foutmelding wordt niet weergegeven. Dit veld bestaat ook voor de andere componenten, maar werd tot nu toe nog niet gebruikt.

De reguliere uitdrukking voor een e-mailadres zou als volgt kunnen zijn: \s*[\w-]+(\.[\w-]+)*@[\w-]+(\.[\w-]+)+\s*

Een e-mailadres heeft de vorm [champ1.champ2....@champA.champB...]. Er moet minstens één veld vóór het @-teken staan en minstens twee velden erachter. Deze velden bestaan uit alfanumerieke tekens en het teken -. Het alfanumerieke teken wordt weergegeven door het symbool \w. De reeks [\w-] staat voor het teken \w of het teken -. Het teken + achter een reeks S betekent dat deze één of meerdere keren kan worden herhaald, het teken * betekent dat deze nul of meerdere keren kan worden herhaald, en het teken ? betekent dat deze nul of één keer kan worden herhaald.

Een veld van het e-mailadres komt overeen met het patroon [\w-]+. Het feit dat er verplicht ten minste één veld vóór het teken @ en ten minste twee erna moeten staan, gescheiden door het teken ., komt overeen met het patroon: [\w-]+(\.[\w-]+)*@[\w-]+(\.[\w-]+)+. De gebruiker mag spaties voor en na het adres invoeren. Deze worden tijdens de verwerking verwijderd. Een reeks spaties, die eventueel leeg kan zijn, wordt weergegeven door het patroon \s*. Vandaar de reguliere expressie voor het e-mailadres: \s*[\w-]+(\.[\w-]+)*@[\w-]+(\.[\w-]+)+\s*.

De opmaakcode van de pagina is dan als volgt:

<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

Om esthetische redenen kan het wenselijk zijn om de foutmeldingen op één plek samen te brengen, zoals in het volgende voorbeeld [summaryvalidator1.aspx], waarin we alle voorgaande voorbeelden op één pagina hebben samengebracht:

Image

Alle validatiecontroles hebben de volgende eigenschappen:

  • [Display=Dynamic], waardoor de controlevelden geen ruimte innemen op de pagina als hun foutmelding leeg is
  • [EnableClientScript=false] om elke validatie aan de clientzijde te verbieden
  • [Text=*]. Dit is het bericht dat bij een fout wordt weergegeven; de inhoud van het attribuut [ErrorMessage] wordt weergegeven door het validatieveld [ValidationSummary] dat we hieronder presenteren.

Deze reeks besturingselementen is ondergebracht in een component [Panel] met de naam [vueFormulaire]. In een andere component [Panel], genaamd [vueErreurs], plaatsen we een besturingselement [ValidationSummary]:

Image

nr.
naam
type
eigenschappen
rol
1
ValidationSummary1
ValidationSummary
HeaderText=De volgende fouten zijn opgetreden, EnableClientScript=false, ShowSummary=true
toont de fouten van alle validatiecontroles op de pagina
2
lnkErreursToFormulaire
LinkButton
CausesValidation=false
link terug naar het formulier

Voor de link [lnkErreursToFormulaire] hoeft de validatie niet te worden geactiveerd, aangezien deze link geen waarden verstuurt die moeten worden gecontroleerd.

Wanneer alle gegevens geldig zijn, wordt de volgende weergave [infos] aan de gebruiker getoond:

Image

1

nr.
naam
type
eigenschappen
rol
1
lblInfo
Label
 
informatiebericht voor de gebruiker

De weergavecode van deze pagina is als volgt:

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

Hier volgen enkele voorbeelden van de verkregen resultaten. We valideren de weergave [formulaire] zonder waarden in te voeren:

Image

De knop [Envoyer] geeft ons het volgende antwoord:

Image

De weergave [erreurs] werd weergegeven. Als we de link terug naar het formulier gebruiken, vinden we dit terug in de volgende toestand:

Image

Dit is de weergave [formulaire]. Let op het teken [*] naast de foutieve gegevens. Dit is het veld [Text] van de validatiecontroles dat is weergegeven. Als we de velden correct invullen, krijgen we de weergave [infos]:

Image

De controlecode van de pagina is als volgt:

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

     ' procedure die wordt uitgevoerd bij het laden van de pagina
    Sub page_Load(sender As Object, e As EventArgs)
        ' bij het eerste verzoek wordt de weergave [formulaire] weergegeven
        if not ispostback then
            afficheVues(true,false,false)
        end if
    end sub

    sub afficheVues(byval formulaireVisible as boolean, _
        erreursVisible as boolean, infosVisible as boolean)
         ' set van weergaven
        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)
        ' geeft de formulierweergave weer
        afficheVues(true,false,false)
         ' voert de validatiecontroles opnieuw uit
        Page.validate
    End Sub

    Sub btnEnvoyer_Click(sender As Object, e As EventArgs)
        ' is de pagina geldig?
        if not Page.IsValid then
            ' de weergave [erreurs] wordt weergegeven
            afficheVues(false,true,false)
        else
             ' anders de weergave [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>
  • In de procedure [Page_Load], die bij elk verzoek van de klant wordt uitgevoerd, geven we de weergave [formulaire] weer, terwijl de overige worden verborgen. Dit gebeurt alleen bij het eerste verzoek. De procedure roept een hulpprocedure [afficheVues] aan, waaraan drie booleaanse waarden worden doorgegeven om te bepalen of de drie weergaven al dan niet worden weergegeven.
  • Wanneer de procedure [btnEnvoyer_Click] wordt aangeroepen, zijn de gegevenscontroles al uitgevoerd. De knop [btnEnvoyer] heeft de eigenschap [CausesValidation=true] die deze gegevenscontrole afdwingt. Alle validatiecontroles zijn uitgevoerd en hun eigenschap [IsValid] is ingesteld. Deze geeft aan of de door de controle geverifieerde gegevens geldig waren of niet. Bovendien is de eigenschap [IsValid] van de pagina zelf ook ingesteld. Deze staat alleen op [vrai] als de eigenschap [IsValid] van alle validatiecontroles op de pagina de waarde [vrai] heeft. De procedure [btnEnvoyer_Click] begint dus met het controleren of de pagina al dan niet geldig is. Als deze ongeldig is, wordt de weergave [erreurs] weergegeven. Deze bevat de controle [ValidationSummary], die de attributen [ErrorMessage] van alle controles overneemt (zie schermafbeelding hierboven). Als de pagina geldig is, wordt de weergave [infos] weergegeven met een informatiemelding.
  • De procedure [lnkErreursToFormulaire_Click] zorgt ervoor dat de weergave [formulaire] wordt weergegeven in de toestand waarin deze is gevalideerd. Voor alle invoervelden van de weergave [formulaire] die de eigenschap [EnableViewState=true] hebben, wordt de status automatisch opnieuw gegenereerd. Vreemd genoeg wordt de status van de validatiecomponenten echter niet hersteld. Men zou namelijk verwachten dat bij het terugkeren naar de weergave [erreurs] de foutieve controlevelden hun veld [Text] zouden weergeven. Dit is echter niet het geval. Daarom is de validatie van de gegevens geforceerd met behulp van de methode [Page.Validate] van de pagina. Dit moet gebeuren zodra het paneel [vueFormulaire] zichtbaar is gemaakt. Er vinden dus in totaal twee validaties plaats. In de praktijk zou dit moeten worden vermeden. In dit voorbeeld konden we echter nieuwe concepten over paginavalidatie introduceren.

8.3. Componenten ListControl en gegevenskoppeling

Met een aantal van de onderzochte servercomponenten kan een lijst met waarden worden weergegeven (DropDownList, ListBox). Met andere componenten, die we nog niet hebben besproken, kunnen meerdere lijsten met waarden in tabellen worden weergegeven (HTML). Voor alle componenten is het mogelijk om de waarden uit de lijsten programmatisch één voor één aan de bijbehorende component te koppelen. Het is ook mogelijk om complexere objecten aan deze componenten te koppelen, zoals objecten van het type [Array], [ArrayList], [DataSet], [HashTable], ... wat de code vereenvoudigt waarmee de gegevens aan de component worden gekoppeld. Deze koppeling wordt een gegevenskoppeling genoemd.

Alle componenten die zijn afgeleid van de klasse [ListControl] kunnen aan een gegevenslijst worden gekoppeld. Het gaat om de componenten [DropDownList], [ListBox], [CheckButtonList] en [RadioButtonList]. Elk van deze componenten kan aan een gegevensbron worden gekoppeld. Deze kan van verschillende aard zijn: [Array], [ArrayList], [DataTable], [DataSet], [HashTable],...., in het algemeen een object dat een van de interfaces IEnumerable, ICollection of IListSource implementeert. We zullen er slechts enkele van bespreken. Een [DataSet]-object is een afbeelding van een relationele database. Het is dus een verzameling tabellen die door relaties met elkaar zijn verbonden. Het [DataTable]-object vertegenwoordigt zo’n tabel. De gegevensbron wijst de eigenschappen [Text] en [Value] toe aan elk van de leden [Item] van het object [ListControl]. Als T de waarde is van [Text] en V de waarde van [Value], dan is de tag HTML die voor elk element van [ListControl] wordt gegenereerd, als volgt:

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

Het koppelen van een component [ListControl] aan een gegevensbron gebeurt via de volgende eigenschappen:

DataSource
een gegevensbron [Array], [ArrayList], [DataTable], [DataSet], [HashTable], ...
DataMember
indien de gegevensbron een [DataSet] is, staat dit voor de naam van de tabel die als gegevensbron moet worden gebruikt. De daadwerkelijke gegevensbron is dan een tabel.
DataTextField
in het geval dat de gegevensbron een tabel is ([DataTable], [DataSet]), staat dit voor de naam van de kolom in de tabel die de waarden zal leveren voor het veld [Text] van de elementen van [ListControl]
DataValueField
in het geval dat de gegevensbron een tabel is ([DataTable],[DataSet]), staat dit voor de naam van de kolom in de tabel die de waarden levert aan het veld [Value] van de elementen van [ListControl]

Het koppelen van een component [ListControl] aan een gegevensbron initialiseert de component niet met de waarden uit de gegevensbron. Dit gebeurt door de bewerking [ListControl].DataBind.

Afhankelijk van de aard van de gegevensbron verloopt de koppeling ervan aan een [ListControl]-component op een andere manier:

Array A
[ListControl].DataSource=A
de velden [Text] en [Value] van de elementen van [ListControl] krijgen als waarden de elementen van A
ArrayList AL
[ListControl].DataSource=AL
de velden [Text] en [Value] van de elementen van [ListControl] krijgen als waarden de elementen van AL
DataTable DT
[ListControl].DataSource=DT, [ListControl].DataTextField="col1", [ListControl]. DatavalueField ="col2"
waarbij col1 en col2 twee kolommen zijn van de tabel DT. De velden [Text] en [Value] van de elementen van [ListControl] krijgen de waarden van de kolommen col1 en col2 van de tabel DT
DataSet DS
[ListControl].DataSource=DS, [ListControl].DataSource="table", waarbij "table" de naam is van een van de tabellen van DS.
[ListControl].DataTextField="col1", [ListControl]. DatavalueField ="col2", waarbij col1 en col2 twee kolommen zijn van de tabel "table". De velden [Text] en [Value] van de elementen van [ListControl] krijgen de waarden van de kolommen col1 en col2 van de tabel "table"
HashTable HT
[ListControl].DataSource=HT, [ListControl].DataTextField="key", [ListControl]. DatavalueField ="value", waarbij [key] en [value] respectievelijk de sleutels en de waarden zijn van HT.

We passen deze informatie toe op het volgende voorbeeld: [databind1.aspx]:

We hebben hier vijf gegevenskoppelingen met telkens vier controlevelden van het type [DropDownList], [ListBox], [CheckBoxList] en [RadioButtonList]. De vijf onderzochte koppelingen verschillen qua gegevensbronnen:

verbinding
gegevensbron
1
Array
2
ArrayList
3
DataTable
4
DataSet
5
HashTable

8.3.1. Weergavecode van de componenten

De weergavecode voor de besturingselementen van koppeling 1 is als volgt:

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

Die van de koppelingen 2 tot en met 5 is identiek, op het koppelingsnummer na.

8.3.2. Koppeling met een gegevensbron van het type Array

De koppeling van de vier bovenstaande besturingselementen [ListBox] gebeurt als volgt in de procedure [Page_Load] van de besturingscode:

' de algemene gegevens
dim textes() as string={"un","deux","trois","quatre"}
dim valeurs() as string={"1","2","3","4"}
dim myDataListe as new ArrayList
dim myDataTable as new DataTable("table1")
dim myDataSet as new DataSet
dim myHashTable as new HashTable

' procedure die wordt uitgevoerd bij het laden van de pagina
Sub page_Load(sender As Object, e As EventArgs)
    if not IsPostBack then
      ' de bronnen worden aangemaakt  van de gegevens die aan de componenten zullen worden gekoppeld
      createDataSources
       ' koppeling aan een tabel [Array]
      bindToArray
       ' koppeling aan een lijst [ArrayList]
      bindToArrayList
       ' koppeling aan een tabel [DataTable]
      bindToDataTable
       ' koppeling naar een gegevensgroep [DataSet]
      bindToDataSet
       ' koppeling aan een woordenboek [HashTable]
      bindToHashTable
    end if
End Sub

sub createDataSources
   ' maakt de gegevensbronnen aan die aan de componenten zullen worden gekoppeld
  ' arraylist
  dim i as integer
  for i=0 to textes.length-1
    myDataListe.add(textes(i))
  next
   ' datatable
   ' de twee kolommen worden gedefinieerd
  myDataTable.Columns.Add("id",Type.GetType("System.Int32"))
  myDataTable.Columns.Add("texte",Type.GetType("System.String"))
  ' de tabel wordt gevuld
  dim ligne as DataRow
  for i=0 to textes.length-1
    ligne=myDataTable.NewRow
    ligne("id")=i
    ligne("texte")=textes(i)
    myDataTable.Rows.Add(ligne)
  next
   ' dataset  één enkele tabel
  myDataSet.Tables.Add(myDataTable)
  ' hashtable
  for i=0 to textes.length-1
    myHashTable.add(valeurs(i),textes(i))
  next
end sub

' tabelkoppeling
sub bindToArray
         ' koppeling aan componenten
        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
        ' selectie van elementen
        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

De koppeling van de besturingselementen aan de gegevens vindt hier alleen plaats bij de eerste aanvraag. Daarna behouden de besturingselementen hun gegevens via het mechanisme van [VIEWSTATE]. De koppeling vindt plaats in de procedure [bindToArray]. Aangezien de gegevensbron van het type [Array] is, wordt alleen het veld [DataSource] van de componenten [ListControl] geïnitialiseerd. Het invullen van de controle met de waarden uit de bijbehorende gegevensbron gebeurt via de methode [ListControl].DataBind. Pas daarna bevatten de objecten [ListControl] elementen. Vervolgens kunnen sommige daarvan worden geselecteerd.

8.3.3. Koppeling aan een gegevensbron van het type ArrayList

De gegevensbron [myDataListe] wordt geïnitialiseerd in de procedure [createDataSources]:

' de algemene gegevens
dim textes() as string={"un","deux","trois","quatre"}
dim myDataListe as new ArrayList
..

' procedure die wordt uitgevoerd bij het laden van de pagina
Sub page_Load(sender As Object, e As EventArgs)
    if not IsPostBack then
      ' de gegevensbronnen worden aangemaakt die aan de componenten zullen worden gekoppeld
      createDataSources
...
    end if
End Sub

sub createDataSources
   ' de gegevensbronnen aanmaken die aan de componenten zullen worden gekoppeld
  ' arraylist
  dim i as integer
  for i=0 to textes.length-1
    myDataListe.add(textes(i))
  next
...
end sub

De koppeling van de vier controles [ListBox] van koppeling 2 gebeurt als volgt in de procedure [bindToArrayList] van de controlecode:

' koppeling van de arraylist
sub bindToArrayList
         ' de koppeling aan de componenten
        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
        ' de selectie van de elementen
        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

Aangezien de gegevensbron van het type [ArrayList] is, wordt alleen het veld [DataSource] van de componenten [ListControl] geïnitialiseerd.

8.3.4. Gegevensbron van het type DataTable

De gegevensbron [myDataTable] wordt geïnitialiseerd in de procedure [createDataSources]:

' de globale gegevens
dim textes() as string={"un","deux","trois","quatre"}
dim myDataTable as new DataTable("table1")
...

' procedure die wordt uitgevoerd bij het laden van de pagina
Sub page_Load(sender As Object, e As EventArgs)
    if not IsPostBack then
      ' de gegevensbronnen worden aangemaakt  die aan de componenten zullen worden gekoppeld
      createDataSources
...
    end if
End Sub

sub createDataSources
   ' de gegevensbronnen aanmaken die aan de componenten zullen worden gekoppeld
...
   ' datatable
   ' de twee kolommen worden gedefinieerd
  myDataTable.Columns.Add("id",Type.GetType("System.Int32"))
  myDataTable.Columns.Add("texte",Type.GetType("System.String"))
  ' de tabel wordt gevuld
  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

We beginnen met het aanmaken van een object [DataTable] met twee kolommen: [id] en [texte]. De kolom [id] vult het veld [Value] van de elementen van [ListControl], en de kolom [texte] vult hun velden [Text]. De opbouw van de tabel [DataTable] met twee kolommen verloopt als volgt:

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

We maken dus een tabel met twee kolommen:

  • de eerste, genaamd „id”, is van het type geheel getal
  • de tweede, genaamd "tekst", is van het type tekenreeks

Nu de structuur van de tabel is aangemaakt, kunnen we deze vullen met de volgende code:

  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

De kolom [id] bevat gehele getallen uit [0,1,..,n], terwijl de kolom [texte] de waarden uit de tabel [data] bevat. Zodra dit is gebeurd, is de tabel [dataListe] gevuld. De koppeling van de vier besturingselementen [ListBox] van koppeling 3 gebeurt als volgt in de procedure [bindToDataTable] van de besturingscode:

sub bindToDataTable
         ' de koppeling aan de componenten
        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
        ' de selectie van de elementen
        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

Elk onderdeel [ListControl] is gekoppeld aan de bron [myDataTable] door voor elk daarvan het volgende toe te wijzen:

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

De tabel [myDataTable] is de gegevensbron. De kolom [id] van deze tabel vult de velden [Value] van de componentenelementen, terwijl de kolom [texte] hun velden [Text] vult.

8.3.5. Gegevensbron van het type DataSet

De gegevensbron [myDataSet] wordt geïnitialiseerd in de procedure [createDataSources]:

' de algemene gegevens
dim myDataTable as new DataTable("table1")
dim myDataSet as new DataSet
...


' procedure die wordt uitgevoerd bij het laden van de pagina
Sub page_Load(sender As Object, e As EventArgs)
    if not IsPostBack then
      ' de gegevensbronnen worden aangemaakt  die aan de componenten zullen worden gekoppeld
      createDataSources
...
    end if
End Sub

sub createDataSources
   ' de gegevensbronnen aanmaken die aan de componenten zullen worden gekoppeld
   ' dataset  één enkele tabel
  myDataSet.Tables.Add(myDataTable)
...
end sub

Een object [DataSet] vertegenwoordigt een verzameling tabellen van het type [DataTable]. De eerder aangemaakte tabel [myDataTable] wordt toegevoegd aan [DataSet]. De koppeling van de vier besturingselementen [ListBox] van koppeling 4 gebeurt als volgt in de procedure [bindToDataSet] van de besturingscode:

sub bindToDataSet
         ' de koppeling aan de componenten
        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
        ' de selectie van de elementen
        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

Elk onderdeel [ListControl] is als volgt gekoppeld aan de gegevensbron:

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

De gegevensgroep [myDataSet] is de gegevensbron. Aangezien deze uit meerdere tabellen kan bestaan, wordt in [DataMember] de naam van de tabel gespecificeerd die zal worden gebruikt. De kolom [id] van deze tabel vult de velden [Value] van de componentenelementen, terwijl de kolom [texte] hun velden [Text] vult.

8.3.6. Gegevensbron van het type HashTable

De gegevensbron [myHashTable] wordt geïnitialiseerd in de procedure [createDataSources]:

' de algemene gegevens
dim textes() as string={"un","deux","trois","quatre"}
dim valeurs() as string={"1","2","3","4"}
dim myHashTable as new HashTable
...

' procedure die wordt uitgevoerd bij het laden van de pagina
Sub page_Load(sender As Object, e As EventArgs)
    if not IsPostBack then
      ' de gegevensbronnen worden aangemaakt  die aan de componenten zullen worden gekoppeld
      createDataSources
...
    end if
End Sub

sub createDataSources
   ' de gegevensbronnen aanmaken die aan de componenten zullen worden gekoppeld
...
  ' hashtabel
  for i=0 to textes.length-1
    myHashTable.add(valeurs(i),textes(i))
  next
end sub

Het woordenboek [myHashTable] kan worden gezien als een tabel met twee kolommen, genaamd "key" en "value". De kolom [key] bevat de sleutels van het woordenboek en de kolom [value] de waarden die aan deze sleutels zijn gekoppeld. De kolom [key] bestaat hier uit de inhoud van de tabel [valeurs] en de kolom [value] uit de inhoud van de tabel [textes]. De koppeling van deze bron aan de besturingselementen vindt plaats in de procedure [bindToHashTable]:

sub bindToHashTable
         ' de koppeling aan de componenten
        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
        ' de selectie van de elementen
        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

Voor elk van de componenten wordt de koppeling gemaakt met de volgende instructies:

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

De gegevensbron is het woordenboek [myHashTable]. De waarden van de besturingselementen worden geleverd door kolom [key] van het woordenboek en de teksten door kolom [value]. Het invoegen van de woordenboekelementen in de besturingselementen gebeurt in de volgorde van de sleutels, die in principe willekeurig is.

8.3.7. Richtlijnen voor het importeren van naamruimten

Een aantal naamruimten wordt automatisch geïmporteerd in een pagina ASP.NET. Dit is niet het geval voor "System.Data", waar de klassen [DataTable] en [DataSet] zich bevinden. Daarom moet deze klasse worden geïmporteerd. Dit gebeurt als volgt:

<%@ Page Language="VB" %>
<%@ import Namespace="System.Data" %>
<script runat="server">
...
</script>
<html>
...
</html>

8.4. Component DataGrid en gegevenskoppeling

Met de component [DataGrid] kunt u gegevens in tabelvorm weergeven, maar deze component gaat veel verder dan alleen deze weergave:

  • hij biedt de mogelijkheid om de "visuele weergave" van de tabel nauwkeurig in te stellen
  • maakt het bijwerken van de gegevensbron mogelijk

De component [DataGrid] is een krachtige en complexe component. We zullen deze stap voor stap toelichten.

8.4.1. Weergave van een Array-gegevensbron, ArrayList, DataTable, DataSet

Met de component [DataGrid] kunnen gegevensbronnen van het type [Array], [ArrayList], [DataTable] en [DataSet] weer te geven in een tabel van het type HTML. Voor deze vier gegevenstypen volstaat het om de bron te koppelen aan de eigenschap [DataSource] van de component [DataGrid]:

DataSource
een gegevensbron [Array], [ArrayList], [DataTable], [DataSet], ...
DataMember
indien de gegevensbron een [DataSet] is, geeft dit de naam aan van de tabel die als gegevensbron moet worden gebruikt. De daadwerkelijke gegevensbron is dan een tabel. Als dit veld niet is ingevuld, worden alle tabellen van de [DataSet] weergegeven.

We presenteren nu de pagina [datagrid1.aspx], die de koppeling van een [DataGrid] aan vier verschillende gegevensbronnen toont:

Image

De pagina bevat vier [DataGrid]-componenten die als volgt zijn opgebouwd met [WebMatrix]. De component wordt op zijn plaats in het tabblad [Design] geplaatst:

Image

Vervolgens wordt een generieke tabel HTML getekend. De eigenschappen van een [DataGrid] kunnen tijdens het ontwerpen worden gedefinieerd. Dat doen we hier voor de opmaakeigenschappen. Hiervoor selecteren we de [DataGrid] die we willen configureren. De eigenschappen verschijnen in een venster rechtsonder:

Image

We gaan de twee bovenstaande links gebruiken. De link [Générateur de propriétés] geeft toegang tot de belangrijkste eigenschappen van de [DataGrid]:

Image

We vinken de zin [Afficher l'en-tête] uit voor de vier componenten [DataGrid] en bevestigen de pagina. Via de andere link [Mise en forme automatique] kun je kiezen uit verschillende stijlen voor de tabel HTML die zal worden weergegeven:

Image

We kiezen [couleur i] voor de [DataGrid] nr. i. Deze ontwerpkeuzes worden verwerkt in de opmaakcode van de pagina:

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

In de ontwerpmodus hebben we alleen opmaakkenmerken ingesteld. In de besturingscode koppelen we gegevens aan de vier componenten:

<%@ Page Language="VB" %>
<%@ import Namespace="system.data" %>
<script runat="server">

     ' de algemene gegevens
        dim textes1() as string={"un","deux","trois","quatre"}
        dim textes2() as string={"one","two","three","for"}
        dim valeurs() as string={"1","2","3","4"}
        dim myDataListe as new ArrayList
        dim myDataTable as new DataTable("table1")
        dim myDataSet as new DataSet

        ' procedure die wordt uitgevoerd bij het laden van de pagina
        Sub page_Load(sender As Object, e As EventArgs)
            if not IsPostBack then
              ' de bronnen worden aangemaakt  van de gegevens die aan de componenten zullen worden gekoppeld
              createDataSources
               ' koppeling aan een tabel [Array]
              bindToArray
               ' koppeling aan een lijst [ArrayList]
              bindToArrayList
               ' koppeling aan een tabel [DataTable]
              bindToDataTable
               ' koppeling naar een gegevensgroep [DataSet]
              bindToDataSet
            end if
        End Sub

        sub createDataSources
           ' maakt de gegevensbronnen aan die aan de componenten zullen worden gekoppeld
          ' arraylist
          dim i as integer
          for i=0 to textes1.length-1
            myDataListe.add(textes1(i))
          next
           ' datatable
           ' hier worden de twee kolommen gedefinieerd
          myDataTable.Columns.Add("id",Type.GetType("System.Int32"))
          myDataTable.Columns.Add("texte1",Type.GetType("System.String"))
          myDataTable.Columns.Add("texte2",Type.GetType("System.String"))
          ' de tabel wordt gevuld
          dim ligne as DataRow
          for i=0 to textes1.length-1
            ligne=myDataTable.NewRow
            ligne("id")=valeurs(i)
            ligne("texte1")=textes1(i)
            ligne("texte2")=textes2(i)
            myDataTable.Rows.Add(ligne)
          next
           ' dataset – één enkele tabel
          myDataSet.Tables.Add(myDataTable)
        end sub

        ' array-koppeling
        sub bindToArray
          with DataGrid1
            .DataSource=textes1
            .DataBind
          end with
        end sub

        ' arraylist-koppeling
        sub bindToArrayList
          with DataGrid2
            .DataSource=myDataListe
            .DataBind
          end with
        end sub

        ' datatable-koppeling
        sub bindToDataTable
          with DataGrid3
            .DataSource=myDataTable
            .DataBind
          end with
        end sub

        ' dataset-koppeling
        sub bindToDataSet
          with DataGrid4
            .DataSource=myDataSet
            .DataBind
          end with
        end sub

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

De code lijkt sterk op die van het vorige voorbeeld, dus we zullen er niet speciaal op ingaan. Laten we echter wel even kijken hoe de koppeling van gegevens tot stand komt. Voor elk van de vier besturingselementen volstaat de volgende reeks:

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

waarbij [source de données] van het type is [Array] of [ArrayList] of [DataTable] of [DataSet]. We zien dus dat we hier te maken hebben met een krachtig hulpmiddel voor het weergeven van gegevens in tabellen:

  • de opmaak gebeurt met [WebMatrix] of een andere IDE tijdens het ontwerp
  • de koppeling met de gegevens gebeurt in de code. Met [WebMatrix] kan dit tijdens het ontwerp gebeuren als de gegevensbron een SQL-server of een ACCESS-database is. In dat geval plaatst men een component van het type [SqlDataSource] of [AccessDataSource] op het werkblad. Deze component kan tijdens het ontwerpen worden gekoppeld aan de fysieke gegevensbron, een SQL-server of een ACCESS-database, al naar gelang het geval. Als aan de eigenschap [DataSource] van een component [DataGrid] een object [SqlDataSource] of [AccessDataSource] wordt toegewezen dat is gekoppeld aan een fysieke bron, dan verschijnen in de ontwerpmodus de werkelijke gegevens in de component [DataGrid].

8.5. ViewState van gegevenslijstcomponenten

We willen hier het mechanisme van [VIEWSATE] voor gegevenslijstcomponenten toelichten. Men kan twijfelen tussen twee methoden om de status van een gegevenslijstcomponent tussen twee verzoeken van de client te behouden:

  • het attribuut [VIEWSTATE] op ‘waar’ zetten
  • het attribuut [VIEWSTATE] op 'false' zetten en de gegevensbron in de sessie opslaan, zodat de component bij het volgende verzoek weer aan deze bron kan worden gekoppeld.

Het volgende voorbeeld illustreert enkele aspecten van het [VIEWSTATE]-mechanisme van gegevenscontainers. Bij het eerste verzoek van de client toont de applicatie de volgende weergave:

nr.
naam
type
eigenschappen
rol
1
DataGrid1
DataGrid
EnableViewState=true
geeft een gegevensbron S weer
2
DataGrid2
DataGrid
EnableViewState=true
geeft dezelfde bron S weer als [DataGrid1]
3
Button1
Button
EnableViewState=false
knop [submit]

De component [DataGrid1] wordt onderhouden door het mechanisme van [VIEWSTATE]. We willen weten of dit mechanisme, dat de weergave van [DataGrid1] bij elke aanvraag vernieuwt, ook de gegevensbron ervan vernieuwt. Hiervoor is deze gekoppeld aan de component [DataGrid2]. Deze wordt bij elke aanvraag gegenereerd via een expliciete koppeling met de gegevensbron van [DataGrid1]. Het heeft ook het attribuut [EnableViewState] aan [vrai].

De weergavecode [main.aspx] van de applicatie is als volgt:


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

De controller [main.aspx.vb] is als volgt:


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
        ' bij de eerste query wordt de gegevensbron gedefinieerd en gekoppeld aan de eerste datagrid
        If Not IsPostBack Then
            'de gegevensbron definiëren
            With DataGrid1
                .DataSource = createDataSource()
                .DataBind()
            End With
        End If
        ' bij elke query wordt datagrid2 gekoppeld aan de bron van het eerste datagrid
        With Datagrid2
            .DataSource = DataGrid1.DataSource
            .DataBind()
        End With
    End Sub

    Private Function createDataSource() As DataTable
        ' de gegevensbron wordt geïnitialiseerd
        Dim thèmes As New DataTable
        ' kolommen
        With thèmes.Columns
            .Add("id", GetType(System.Int32))
            .Add("thème", GetType(System.String))
            .Add("description", GetType(System.String))
        End With
        ' de kolom 'id' wordt de primaire sleutel
        thèmes.Constraints.Add("cléprimaire", thèmes.Columns("id"), True)
        ' rijen
        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

De methode [createDataSource] maakt een bron S van het type [DataTable] aan. We zullen niet ingaan op de code ervan, aangezien die niet het onderwerp van dit voorbeeld is. Wat ons interesseert, is de manier waarop de twee componenten [DataGrid] worden opgebouwd:

  • de component [DataGrid1] wordt bij de eerste query eenmalig gekoppeld aan de S-tabel. Daarna is deze koppeling niet meer aanwezig.
  • De component [DataGrid2] wordt bij elke nieuwe query gekoppeld aan de bron [DataGrid1.DataSource].

Bij de eerste query krijgen we het volgende overzicht:

Image

Logischerwijs geven beide componenten de gegevensbron weer waaraan ze zijn gekoppeld. We gebruiken de knop [Envoyer] om een [PostBack] naar de server te sturen. Het verkregen beeld is dan als volgt:

Image

We zien dat de component [DataGrid1] zijn waarde heeft behouden, maar de component [DataGrid2] niet. Uitleg:

  • nog voordat de procedure [Page_Load] van start ging, hebben de objecten [DataGrid1] en [DataGrid2] de waarde aangenomen die ze bij de vorige aanvraag hadden, dankzij het mechanisme van [viewstate]. Beide hebben namelijk de eigenschap [EnableViewState] ingesteld op [vrai].
  • De procedure [Page_Load] wordt uitgevoerd. Aangezien het hier gaat om een bewerking [PostBack], wordt de component [DataGrid1] niet gewijzigd door [Page_Load] (zie code). Daarom behoudt deze de waarde die via [viewstate] is opgehaald. Dit is te zien in het bovenstaande scherm.
  • De component [DataGrid2] is via [DataBind] gekoppeld aan de gegevensbron [DataGrid1.DataSource]. Hij wordt dus opnieuw opgebouwd en de waarde die hij zojuist via [viewstate] had opgehaald, gaat verloren. Het zou hier dus beter zijn geweest als de eigenschap van [EnableViewState] was gekoppeld aan [faux], om onnodig beheer van de status te voorkomen. Het bovenstaande scherm laat zien dat [DataGrid2] aan een lege bron is gekoppeld. Aangezien deze bron [DataGrid1.DataSource] is, kunnen we hieruit afleiden dat, hoewel het mechanisme van [viewstate] de weergave van de component [DataGrid1] weliswaar herstelt, het de eigenschappen ervan, zoals [DataSource], niet herstelt.

Wat kunnen we uit dit voorbeeld concluderen? Men moet vermijden om de eigenschap [EnableViewState] van een gegevenscontainer in te stellen op [vrai] als deze bij elke aanvraag gekoppeld moet worden (DataBind) aan een gegevensbron. Er zijn echter bepaalde gevallen waarin, zelfs in dit scenario, de eigenschap [EnableViewState] van de container op [vrai] moet worden gehouden, anders worden gebeurtenissen die men zou willen afhandelen niet geactiveerd. We zullen hier later een voorbeeld van tegenkomen.

Vaak verandert de gegevensbron van een gegevenscontainer in de loop van de verzoeken. Daarom moet de container bij elk verzoek opnieuw aan de gegevensbron worden gekoppeld. Het komt vaak voor dat deze in de sessie wordt opgeslagen, zodat de verzoeken er toegang toe hebben. Ons tweede voorbeeld illustreert dit mechanisme. De applicatie biedt slechts één weergave:

nr.
naam
type
eigenschappen
rol
1
DataGrid1
DataGrid
EnableViewState=true
geeft een gegevensbron S weer
2
DataGrid2
DataGrid
EnableViewState=false
geeft dezelfde bron S weer als [DataGrid1]
3
Button1
Button
EnableViewState=false
knop [submit]
4
lblInfo1
lblInfo2
lblInfo3
Label
EnableViewState=false
informatieteksten

De component [DataGrid1] wordt alleen bij de eerste aanvraag aan de gegevens gekoppeld. Dankzij het mechanisme van de [viewstate] behoudt deze component zijn waarde bij volgende aanvragen. De component [DataGrid2] wordt bij elke aanvraag gekoppeld aan een gegevensbron waaraan bij elke nieuwe aanvraag een element wordt toegevoegd. Daarom moet de component [DataGrid2] bij elke aanvraag worden gekoppeld (DataBind). We hebben daarom het attribuut [EnableViewState] ingesteld op [faux], zoals eerder geadviseerd. Bij de tweede aanvraag (met behulp van de knop [Envoyer]) krijgen we dus het volgende antwoord:

Image

De component [DataGrid1] heeft zijn oorspronkelijke waarde behouden. De component [DataGrid2] heeft één element meer. De drie gegevens [1,2,2] vertegenwoordigen het verzoeknummer. We zien dat één van de gegevens onjuist is. We zullen proberen te achterhalen waarom.

De weergavecode [main.aspx] van de applicatie is als volgt:


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

De code van de controller [main.aspx.vb] is als volgt:


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
        ' bij de eerste query is de gegevensbron gedefinieerd en gekoppeld aan het eerste datagrid
        If Not IsPostBack Then
            'de gegevensbron definiëren
            dtThèmes = createDataSource()
            With DataGrid1
                .DataSource = dtThèmes
                .DataBind()
            End With
            ' informatie opslaan in de sessie
            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
        ' bij elke aanvraag wordt een nieuw thema toegevoegd
        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)
        'koppel datagrid2 aan de gegevensbron
        With Datagrid2
            .DataSource = dtThèmes
            .DataBind()
        End With
        ' informatie over het aantal verzoeken
        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
        ' er wordt wat informatie in de sessie opgeslagen
        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

We hebben de code van de methode [createDataSource] niet weergegeven. Deze is hetzelfde als in de vorige toepassing, met als enige verschil dat er slechts drie regels in de bron staan. Laten we ons eerst richten op het beheer van de gegevensbron en de twee containers:


    Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        ' bij de eerste aanvraag wordt de gegevensbron gedefinieerd en gekoppeld aan de eerste datagrid
        If Not IsPostBack Then
            'de gegevensbron definiëren
            dtThèmes = createDataSource()
            With DataGrid1
                .DataSource = dtThèmes
                .DataBind()
            End With
            ' informatie opslaan in de sessie
            Session("source") = dtThèmes
...
        End If
        ' bij elke aanvraag wordt een nieuw thema toegevoegd
        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)
        'koppelt datagrid2 aan de gegevensbron
        With Datagrid2
            .DataSource = dtThèmes
            .DataBind()
        End With
...
    End Sub

De component [DataGrid1] wordt alleen bij de eerste aanvraag gekoppeld aan de gegevensbron S (niet IsPostBack). Deze wordt dan in de sessie geplaatst. Daarna gebeurt dit niet meer. De in de sessie geplaatste gegevensbron S wordt bij elke aanvraag opgehaald en er wordt een nieuwe regel aan toegevoegd. De component [DataGrid2] wordt bij elke aanvraag expliciet gekoppeld aan de bron S. Daarom neemt de inhoud ervan bij elke aanvraag met één regel toe. We zien dat na het wijzigen van de inhoud van de bron S, deze niet expliciet opnieuw in de sessie wordt geplaatst via een bewerking:

            Session("source") = S

Waarom? Wanneer een verzoek start, bevat de sessie een Session("source")-object van het type [DataTable], dat de gegevensbron is zoals deze was tijdens het laatste verzoek. Laten we het Session("source")-object S noemen. Wanneer we schrijven:


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

dan zijn [dtThèmes] en [S] twee verwijzingen naar hetzelfde object [DataTable]. Wanneer de code van [Page_Load] dus een element toevoegt aan de tabel waarnaar [dtThèmes] verwijst, voegt deze het tegelijkertijd ook toe aan de tabel waarnaar [S] verwijst. Aan het einde van de uitvoering van de pagina worden alle objecten in de sessie opgeslagen, dus ook het object Session("source"), c.a.d. S, c.a.d en [dtThèmes]. Het is dus inderdaad de nieuwe inhoud van de gegevensbron die wordt opgeslagen. Het was niet nodig om het volgende te schrijven:

            Session("source") = dtThèmes

om deze back-up te maken, omdat Session("source") al gelijk is aan [dtThèmes]. Dit geldt niet meer wanneer de gegevens die in de sessie worden opgeslagen geen objecten zijn, zoals de structuren [Integer, Float, ...]. Dit blijkt uit het beheer van de verzoekentellers:


    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
        ' bij de eerste aanvraag wordt de gegevensbron gedefinieerd en gekoppeld aan de eerste datagrid
....
            ' informatie opslaan in de sessie
            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
        ' bij elke query wordt een nieuw thema toegevoegd
....
        ' informatie over het aantal verzoeken
        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
        ' er wordt wat informatie opgeslagen in de sessie
        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

De verzoekentellers worden opgeslagen in drie elementen:

  • numRequête1 en numRequête2 van het type [Integer] – [Integer] is geen klasse maar een structuur
  • numRequête3 van het type [entier] – [entier] is een klasse die speciaal voor dit doel is gedefinieerd

Wanneer men schrijft:


        numRequête1 = CType(Session("numRequête1"), Integer)
..
        numRequête2 = CType(Session("numRequête2"), Integer)
..
        numRequête3 = CType(Session("numRequête3"), entier)
..
  • de structuur [Session("numRequête1")] wordt gekopieerd naar [numRequête1]. Wanneer het element [numRequête1] wordt gewijzigd, wordt het element [Session("numRequête1")] dus niet gewijzigd
  • Hetzelfde geldt voor [Session("numRequête2")] en [numRequête2]
  • De elementen [Session("numRequête3")] en [numRequête3] zijn beide verwijzingen naar hetzelfde object van het type [entier]. Het object waarnaar wordt verwezen, kan via beide verwijzingen worden gewijzigd.

Hieruit volgt dat het niet nodig is om het volgende te schrijven:

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

om de nieuwe waarde van [numRequête3] in de sessie op te slaan. In plaats daarvan moet je schrijven:

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

om de nieuwe waarden van de structuren [numRequête1] en [numRequête2] op te slaan. We doen dit alleen voor [numRequête2], wat verklaart waarom op de schermafbeelding die na de tweede query is verkregen, de teller [numRequête1] onjuist is.

We onthouden dus dat, zodra gegevens in de sessie zijn opgenomen, deze niet herhaaldelijk opnieuw hoeven te worden ingevoerd als ze door een object worden vertegenwoordigd. In andere gevallen moet dit wel gebeuren als de gegevens zijn gewijzigd.

8.6. Weergave van een gegevenslijst met behulp van een gepagineerde en gesorteerde DataGrid

Met de component [DataGrid] kan de inhoud van een [DataSet] worden weergegeven. Tot nu toe hebben we onze [DataSet]-bestanden altijd ‘met de hand’ samengesteld. Deze keer gebruiken we een [DataSet] uit een database. We bouwen de volgende MVC-toepassing:

De drie weergaven worden als containers opgenomen in de presentatiecode van de controller [main.aspx]. Deze applicatie heeft dus één enkele pagina: [main.aspx].

8.6.1. De businessklassen

De klasse [produits] biedt toegang tot de volgende database ACCESS:

Image

De code van de klasse [produits] is als volgt:


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)
            ' de verbindingsstring wordt opgeslagen
            Me.chaineConnexionOLEDB = chaineConnexionOLEDB
        End Sub

        Public Function getDataSet(ByVal commande As String) As DataSet
            ' er wordt een object DataAdapter aangemaakt om de gegevens uit de bron OLEDB te lezen
            Dim adaptateur As New OleDbDataAdapter(commande, chaineConnexionOLEDB)
            ' er wordt een geheugenafbeelding gemaakt van het resultaat van de select-opdracht
            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
            ' het resultaat wordt weergegeven
            Return contenu
        End Function
    End Class
End Namespace

De database ACCESS wordt beheerd via een stuurprogramma OLEDB. We geven aan de constructor van de klasse [produits] de verbindingsstring, de identificatie, het stuurprogramma OLEDB en de database die moet worden beheerd. De klasse [produits] heeft een methode [getDataSet] die een [DataSet] retourneert, verkregen door het uitvoeren vaneen query SQL [select], waarvan de tekst als parameter wordt doorgegeven. Tijdens de methode vinden verschillende bewerkingen plaats: het tot stand brengen van de verbinding met de database, het uitvoeren van de [select] en het verbreken van de verbinding. Dit alles kan een uitzondering veroorzaken, die hier wordt afgehandeld. Een testprogramma zou er als volgt uit kunnen zien:

Option Explicit On 
Option Strict On

' naamruimten
Imports System
Imports System.Data
Imports Microsoft.VisualBasic

Namespace st.istia.univangers.fr

     ' testpagina
    Module testproduits
        Sub Main(ByVal arguments() As String)
             ' de inhoud van een producttabel weergeven
             ' de tabel bevindt zich in een database ACCESS waarvan de pg de bestandsnaam krijgt
            Const syntaxe1 As String = "pg bdACCESS"

             ' controle van de programma-instellingen
            If arguments.Length <> 1 Then
                 ' foutmelding
                Console.Error.WriteLine(syntaxe1)
                 ' einde
                Environment.Exit(1)
            End If

             ' de verbindingsstring wordt voorbereid
            Dim chaineConnexion As String = "Provider=Microsoft.Jet.OLEDB.4.0; Ole DB Services=-4; Data Source=" + arguments(0)

             ' een productobject aanmaken
            Dim objProduits As produits = New produits(chaineConnexion)

             ' de producttabel wordt opgehaald in een dataset
            Dim contenu As DataSet
            Try
                contenu = objProduits.getDataSet("select id,nom,prix from liste")
            Catch ex As Exception
                Console.Error.WriteLine(("L'erreur suivante s'est produite : " + ex.Message))
                Environment.Exit(2)
            End Try

             ' de inhoud ervan wordt weergegeven
            Dim lignes As DataRowCollection = contenu.Tables(0).Rows
            For i As Integer = 0 To lignes.Count - 1
                 ' rij i van de tabel
                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

De verschillende onderdelen van deze applicatie worden als volgt samengevoegd:

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. De weergaven

Nu we de klasse voor gegevenstoegang hebben, gaan we de controllers en views van deze webapplicatie schrijven. Laten we eerst eens kijken hoe deze werkt. De eerste view ziet er als volgt uit:

nr.
naam
type
eigenschappen
rol
1
txtSelect
TextBox
EnableViewState=true
invoerveld voor de select-query
2
RequiredFieldValidator1
RequiredFieldValidator
EnableViewState=false
controleert of er 1 aanwezig is
3
txtPages
TextBox
EnableViewState=true
invoerveld – geeft het aantal rijen met gegevens aan dat per resultatenpagina moet worden weergegeven
4
RequiredFieldValidator2
RequiredFieldValidator
EnableViewState=false
controleert of er 3 aanwezig zijn
5
RangeValidator1
RangeValidator
EnableViewState=false
controleert of (3) binnen het bereik [1,30] ligt
6
btnExécuter
Knop
EnableViewState=false
knop [submit]

We noemen deze weergave de weergave [formulaire]. Hiermee kan de gebruiker een select-query SQL uitvoeren op de database [produits.mdb]. De uitvoering van de query leidt tot een nieuwe weergave:

nr.
naam
type
eigenschappen
rol
1
lblSelect
Label
EnableViewState=false
informatieveld
2
rdCroissant
rdDécroissant
RadioButton
EnableViewState=false
GroupName=rdTri
hiermee kunt u een sorteervolgorde kiezen
3
DataGrid1
DataGrid
EnableViewState=true
AllowPaging=true
AllowSorting=true
tabel met de resultaten van de selectie
4
lnkRésultats
LinkButton
EnableViewState=false
link-knop [submit]

We noemen deze weergave de weergave [résultats]. Deze bevat de [DataGrid] die het resultaat van de opdracht SQL select weergeeft. De gebruiker kan zich vergissen in zijn zoekopdracht. Bepaalde fouten worden in de weergave [erreurs] gemeld dankzij de validatiecontroles.

Image

Andere fouten worden gemeld via de weergave [erreurs]:

Image

De weergave [erreurs] wordt weergegeven:

nr.
naam
type
eigenschappen
rol
1
erreursHTML
variabele
 
code HTML nodig voor het weergeven van fouten
3
lnkForm2
LinkButton
EnableViewState=false
link-knop [submit]

De drie weergaven van de applicatie zijn drie verschillende containers (panelen) binnen dezelfde pagina [main.aspx]. De weergavecode is als volgt:


<%@ 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. Configuratie van de DataGrid

Laten we even stilstaan bij de paginering van de component [DataGrid], een optie die we hier voor het eerst tegenkomen. In de bovenstaande code wordt deze paginering geregeld door de volgende attributen:


                    <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"
paginering toestaan
PageSize="4"
vier regels gegevens per pagina
NextPageText="Suivant"
De linktekst om naar de volgende pagina van de gegevensbron te gaan
PrevPageText="Précédent"
De linktekst om naar de vorige pagina van de gegevensbron te gaan

Deze informatie kan rechtstreeks in de attributen van de tag <asp:datagrid> worden ingevoerd. U kunt ook gebruikmaken van [WebMatrix]. In het eigenschappenvenster van [DataGrid] volgt u de link [Générateur de propriétés]:

Image

Je krijgt dan de volgende wizard te zien:

Image

Kies de optie [Pagination]:

Image

Hierboven zien we de waarden van de paginatie-attributen van [DataGrid] uit de presentatiecode.

Daarnaast maken we het sorteren van de gegevens op een van de kolommen van [DataGrid] mogelijk. Er zijn verschillende manieren om dit te doen. Een daarvan is het instellen van de eigenschap [AllowSorting=true] in het eigenschappenvenster van [DataGrid]. Je kunt ook de eigenschappen-generator gebruiken. Welke methode je ook gebruikt, het resultaat is dat het attribuut [AllowSorting=true] aanwezig is in de tag <asp:DataGrid> van de component:


                    <asp:DataGrid id="DataGrid1" runat="server" ... AllowPaging="True" PageSize="4" AllowSorting="True">

8.6.4. De controllers

De controller [global.asax, global.asax.vb] is als volgt:

[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)
        ' een productobject aanmaken
        Dim objProduits As produits
        Try
            objProduits = New produits(ConfigurationSettings.AppSettings("OLEDBStringConnection"))
            ' het object wordt in de applicatie geplaatst
            Application("objProduits") = objProduits
            ' geen fout
            Application("erreur") = False
        Catch ex As Exception
            'er is een fout opgetreden, dit wordt in de applicatie genoteerd
            Application("erreur") = True
            Application("message") = ex.Message
        End Try
    End Sub
End Class

Wanneer de applicatie wordt gestart (Application_Start), maken we een object [produits] aan en plaatsen we dit in de applicatie, zodat het beschikbaar is voor alle verzoeken van alle clients. Als er tijdens het aanmaken een uitzondering optreedt, wordt deze in de applicatie geregistreerd. De procedure [Application_Start] wordt slechts één keer uitgevoerd. Daarna komt de controller [global.asax] niet meer in actie. Het is dan de controller [main.aspx.vb] die het werk zal doen:


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

    ' paginacomponenten
    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
    ' pagina-gegevens
    Protected erreursHTML As String

    Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        ' er wordt gecontroleerd of er een fout in de applicatie is
        If CType(Application("erreur"), Boolean) Then
            ' de applicatie is niet correct geïnitialiseerd
            Dim erreurs As New ArrayList
            erreurs.Add("Application momentanément indisponible (" + CType(Application("message"), String) + ")")
            afficheErreurs(erreurs, False)
            Exit Sub
        End If
        'Eerste verzoek
        If Not IsPostBack Then
            ' het lege formulier wordt weergegeven
            afficheFormulaire()
        End If
    End Sub

    Private Sub afficheErreurs(ByVal erreurs As ArrayList, ByVal afficheLien As Boolean)
        ' de foutpagina wordt weergegeven
        erreursHTML = ""
        For i As Integer = 0 To erreurs.Count - 1
            erreursHTML += "<li>" + erreurs(i).ToString + "</li>" + ControlChars.CrLf
        Next
        lnkErreurs.Visible = afficheLien
        ' de weergave [erreurs] wordt weergegeven
        vueErreurs.Visible = True
        vueFormulaire.Visible = False
        vueRésultats.Visible = False
    End Sub

    Private Sub afficheFormulaire()
        ' de weergave wordt weergegeven [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)
        ' de besturingselementen worden geïnitialiseerd
        lblSelect.Text = sqlTexte
        With DataGrid1
            .DataSource = données
            .PageSize = CType(txtPages.Text, Integer)
            .CurrentPageIndex = 0
            .DataBind()
        End With
        ' de weergave [résultats] wordt weergegeven
        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
        ' is de pagina geldig?
        If Not Page.IsValid Then
            afficheFormulaire()
            Exit Sub
        End If

        ' de client-query wordt uitgevoerd 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
        ' alles is in orde – de resultaten worden weergegeven
        afficheRésultats(txtSelect.Text.Trim, données)
        ' de gegevens worden in de sessie opgeslagen
        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
        ' weergaven
        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
        ' pagina wisselen
        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
        ' de dataview wordt gesorteerd
        Dim données As DataView = CType(Session("données"), DataView)
        données.Sort = e.SortExpression + " " + CType(IIf(rdCroissant.Checked, "asc", "desc"), String)
        ' we geven deze weer
        With DataGrid1
            .CurrentPageIndex = 0
            .DataSource = données
            .DataBind()
        End With
    End Sub
End Class

Bij het laden van de pagina [Page_Load] wordt eerst gecontroleerd of de applicatie correct is opgestart. Als dat niet het geval is, wordt de weergave [erreurs] weergegeven zonder teruglink naar het formulier, omdat deze link dan overbodig is. Alleen de weergave [erreurs] kan namelijk worden weergegeven als de applicatie niet correct kon worden geïnitialiseerd. Anders wordt de weergave [formulaire] weergegeven als het om het eerste verzoek van de klant gaat. Voor het overige laten we het aan de lezer over om de code te begrijpen. We gaan alleen dieper in op drie procedures: de procedure [btnExécuter_Click] die wordt uitgevoerd wanneer de gebruiker heeft gevraagd om de uitvoering van de aanvraag SQL die is ingevoerd in de weergave [formulaire], de procedure [DataGrid1_PageIndexChanged], die wordt uitgevoerd wanneer dede gebruiker de links [Suivant] en [Précédent] van [DataGrid] gebruikt, en de procedure [DataGrid1_SortCommand] die wordt uitgevoerd wanneer de gebruiker op de titel van een kolom klikt om de gegevens te sorteren volgens devolgorde daarvan. De richting van de volgorde, oplopend of aflopend, wordt bepaald door de twee keuzerondjes voor het sorteren.

In de procedure [btnExécuter_Click] wordt dus eerst gecontroleerd of de pagina geldig is of niet. Wanneer de procedure [btnExécuter_Click] wordt uitgevoerd, zijn de controles met betrekking tot de verschillende validatiecontroles van de pagina al uitgevoerd. Voor elke validatiecontrole zijn twee attributen ingesteld:

IsValid
op ‘waar’ als de gecontroleerde gegevens geldig zijn, op ‘onwaar’ als dat niet het geval is
ErrorMessage
de foutmelding als de gecontroleerde gegevens ongeldig bleken te zijn

Voor de pagina zelf is het attribuut [IsValid] ingesteld. Dit is alleen waar als alle validatiecontroles het attribuut [IsValid] op waar hebben staan. Als dat niet het geval is, moet de weergave [formulaire] worden getoond. Deze bevat de validatiecontroles die hun attribuut [errorMessage] zullen weergeven. Als de pagina geldig is, wordt het object van het type [produits] gebruikt, dat door [Application_Start] is aangemaakt, om het [DataSet] te verkrijgen dat overeenkomt met de uitvoering van de select-query SQL. Dit wordt omgezet in het object [DataView]:


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

We hadden ook gewoon met [DataSet] kunnen werken en het volgende kunnen schrijven:


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

Een [DataSet]-object is in wezen een verzameling tabellen die via relaties met elkaar zijn verbonden. In onze specifieke toepassing bevat het [DataSet], afgeleid van de klasse [produits], slechts één tabel, namelijk die welke voortkomt uit het resultaat van de instructie [select]. Een tabel kan worden gesorteerd, terwijl een [DataSet] dat niet kan, maar we willen de verkregen gegevens juist wel sorteren. Om met de resultatentabel van de [select] te werken, hadden we het volgende kunnen schrijven:


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

Het object [DataTable] vertegenwoordigt weliswaar een databasetabel, maar beschikt niet over een sorteermethode. Hiervoor is een weergave van de tabel nodig. Een weergave is een object van het type [DataView]. Met behulp van filters kunnen verschillende weergaven van dezelfde tabel worden gecreëerd. Een tabel heeft een standaardweergave, namelijk die waarbij geen filter is gedefinieerd. Deze vertegenwoordigt dus de volledige tabel. Deze standaardweergave wordt verkregen via [DataTable.DefaultView]. Een weergave kan worden gesorteerd met behulp van de eigenschap [sort], waar we later op terugkomen.

Als het ophalen van de [DataSet] van de klasse [produits] goed verloopt, wordt de weergave [résultats] weergegeven; anders is het de weergave [erreurs]. De weergave van de weergave [résultats] gebeurt via de procedure [afficheRésultats], waaraan twee parameters worden doorgegeven:

  • de tekst die in het label [lblSelect] moet worden geplaatst
  • de [DataView] die aan [DataGrid1] moet worden gekoppeld

Dit voorbeeld illustreert de grote flexibiliteit van de component [DataGrid]. Deze component herkent de structuur van de [DataView] waaraan hij wordt gekoppeld en past zich daaraan aan. Ten slotte slaat de procedure [btnExécuter_Click] het zojuist verkregen [DataView] op in de sessie van de gebruiker, zodat het beschikbaar is wanneer de gebruiker andere pagina’s van hetzelfde [DataView] opvraagt.

De procedure [DataGrid1_PageIndexChanged] wordt uitgevoerd wanneer de gebruiker de links [Suivant] en [Précédent] van de [DataGrid] gebruikt. Deze procedure ontvangt twee parameters:


    Private Sub DataGrid1_PageIndexChanged(ByVal source As Object, ByVal e As System.Web.UI.WebControls.) Handles DataGrid1.PageIndexChanged
source
het object dat aan de gebeurtenis ten grondslag ligt – in dit geval een van de koppelingen [Suivant] of [Précédent]
e
informatie over de gebeurtenis. Het attribuut e.NewPageIndex is het paginanummer dat moet worden weergegeven om aan het verzoek van de klant te voldoen

De volledige code van de gebeurtenisbehandelaar is als volgt:


    Private Sub DataGrid1_PageIndexChanged(ByVal source As Object, ByVal e As System.Web.UI.WebControls.DataGridPageChangedEventArgs) Handles DataGrid1.PageIndexChanged
        ' pagina wisselen
        With DataGrid1
            .CurrentPageIndex = e.NewPageIndex
            .DataSource = CType(Session("données"), DataView)
            .DataBind()
        End With
    End Sub

De component [DataGrid] heeft een attribuut [CurrentPageIndex] dat het paginanummer aangeeft dat wordt weergegeven of zal worden weergegeven. Aan dit attribuut wordt de waarde [NewPageIndex] van de parameter [e] toegekend. Vervolgens wordt [DataGrid] gekoppeld aan [DataView], dat in de sessie was opgeslagen via de procedure [btnExécuter_Click].

Men kan zich afvragen of [DataGrid] het attribuut [EnableViewState=true] nodig heeft, aangezien de inhoud ervan bij elke nieuwe uitvoering van de pagina door de code wordt berekend. Men zou kunnen denken van niet. Maar als [DataGrid] het attribuut [EnableViewState=false] heeft, zien we dat de gebeurtenis [DataGrid1.PageIndexChanged] nooit wordt geactiveerd. Daarom hebben we [EnableViewState=true] behouden. We weten dat dit ertoe leidt dat de inhoud van [DataGrid] in het verborgen veld [__VIEWSTATE] van de pagina wordt geplaatst. Dit kan leiden tot een aanzienlijke overbelasting van de pagina als de [DataGrid] omvangrijk is. Als dit een probleem vormt, kan men de paginering zelf beheren zonder gebruik te maken van de automatische paginering van de [DataGrid].

De procedure [DataGrid1_SortCommand] wordt uitgevoerd wanneer de gebruiker op de titel van een van de kolommen klikt die door de [DataGrid] worden weergegeven, om de gegevens op de volgorde van die kolom te sorteren. Deze procedure ontvangt twee parameters:


    Private Sub DataGrid1_SortCommand(ByVal source As Object, ByVal e As System.Web.UI.WebControls.DataGridSortCommandEventArgs) Handles DataGrid1.SortCommand
source
het object dat de gebeurtenis heeft veroorzaakt – in dit geval een van de links [Suivant] of [Précédent]
e
informatie over de gebeurtenis. Het attribuut [e.SortExpression] is de naam van de kolom waarop is geklikt om te sorteren

De volledige code van de gebeurtenishandler is als volgt:


    Private Sub DataGrid1_SortCommand(ByVal source As Object, ByVal e As System.Web.UI.WebControls.DataGridSortCommandEventArgs) Handles DataGrid1.SortCommand
        ' de dataview wordt gesorteerd
        Dim données As DataView = CType(Session("données"), DataView)
        données.Sort = e.SortExpression + " " + CType(IIf(rdCroissant.Checked, "asc", "desc"), String)
        ' de dataview wordt weergegeven
        With DataGrid1
            .CurrentPageIndex = 0
            .DataSource = données
            .DataBind()
        End With
    End Sub

We halen de [DataView] op die door de [DataGrid] in de huidige sessie wordt weergegeven. Dit is de procedure [btnExécuter_Click] die deze daar had geplaatst. De component [DataView] heeft een eigenschap [Sort] waaraan de sorteeruitdrukking wordt toegewezen. Deze volgt de syntaxis [select ... order by expr1, expr2, ...], waarbij elke [expri] kan worden gevolgd door het trefwoord [asc] voor oplopende sortering of [desc] voor aflopende sortering. De hier gebruikte uitdrukking [order by] is [order by colonne asc/desc]. De eigenschap [e.SortExpression] geeft ons de naam van de kolom van [DataGrid] waarop is geklikt om te sorteren. De tekenreeks [asc/desc] wordt vastgesteld op basis van de waarden van de keuzerondjes in de groep [rdTri]. Zodra de sorteeruitdrukking van [DataView] is vastgesteld, wordt [DataGrid] hieraan gekoppeld. De [DataGrid] wordt op de eerste pagina geplaatst.

8.7. Component DataList en gegevenskoppeling

We richten ons nu op de component [DataList]. Deze biedt meer opmaakmogelijkheden dan de [DataGrid], maar is minder flexibel. Zo kan hij zich niet automatisch aanpassen aan de gegevensbron waaraan hij is gekoppeld. Indien gewenst, moet deze aanpassing via code worden uitgevoerd. Als de structuur van de gegevensbron van tevoren bekend is, biedt deze component opmaakmogelijkheden waardoor hij de voorkeur kan krijgen boven de [DataGrid].

8.7.1. Toepassing

Om het gebruik van de [DataList] te illustreren, bouwen we een MVC-toepassing die vergelijkbaar is met de vorige:

De drie weergaven worden in de weergavecode van de controller [main.aspx] opgenomen in de vorm van containers. Deze applicatie heeft dus één enkele pagina: [main.aspx].

8.7.2. De businessklassen

De klasse [produits] is dezelfde als hierboven.

8.7.3. De weergaven

Wanneer de gebruiker zijn eerste verzoek aan de applicatie doet, krijgt hij de volgende weergave [résultats1] te zien:

nr.
naam
type
eigenschappen
rol
1
RadioButton1
RadioButton2
RadioButton
EnableViewState=false
Hiermee kunt u kiezen uit twee stijlen voor [DataList]
2
btnChanger
Button
EnableViewState=false
knop [submit]
3
DataList1
DataList
EnableViewState=true
weergaveveld van de gegevenslijst

Als de gebruiker stijl nr. 2 kiest, krijgt hij de volgende weergave [résultats2] te zien:

nr.
naam
type
eigenschappen
rol
1
DataList2
DataList
EnableViewState=true
weergaveveld van de gegevenslijst

De weergave [erreurs] meldt een probleem met de toegang tot de gegevensbron:

nr.
naam
type
eigenschappen
rol
1
erreursHTML
variabele
 
code HTML nodig voor het weergeven van fouten

De drie weergaven van de applicatie zijn drie verschillende containers (panelen) binnen dezelfde pagina [main.aspx]. De weergavecode is als volgt:


<%@ 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("naam") %>
                            <br>
                            prix :
                            <%# databinder.eval(Container.DataItem,"prijs","{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("naam") %>
                            , prix :
                            <%# databinder.eval(Container.DataItem,"prijs","{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. Configuratie van de componenten [DataList]

Laten we eens kijken naar de verschillende attributen van een [DataList]-component. Er zijn er heel veel en we laten hier slechts een klein deel zien. Binnen een [DataList] kunnen maximaal zeven weergavemodellen worden gedefinieerd:

HeaderTemplate
sjabloon voor de koptekst van [DataList]
ItemTemplate
sjabloon voor de regels waarin de elementen van de bijbehorende gegevenslijst worden weergegeven. Alleen dit sjabloon is verplicht.
AlternatingItemTemplate
Om de achtereenvolgens weergegeven elementen visueel van elkaar te onderscheiden, kunnen twee sjablonen worden gebruikt: ItemTemplate voor element n, AlternatingItemTemplate voor element n+1
SelectedItemTemplate
sjabloon voor het geselecteerde element in [DataList]
SeparatorTemplate
sjabloon van de scheidingsteken tussen twee elementen van het [DataList]
EditItemTemplate
een [DataList] maakt het mogelijk de weergegeven waarden te wijzigen. [EditItemTemplate] is het sjabloon van een element uit [DataList] waarvoor de "bewerkingsmodus" is geactiveerd
FooterTemplate
sjabloon van de voettekst van [DataList]

De component [DataList1] is opgebouwd met [WebMatrix]. In het eigenschappenvenster ervan is de koppeling [Mise en forme automatique] geselecteerd:

1234567

Hierboven zal het schema [Couleur 5] een [DataList] genereren met stijlen voor de volgende sjablonen: HeaderTemplate (1), ItemTemplate (2, 6), AlternatingTemplate (3, 5), SelectedItemTemplate (4), FooterTemplate (7). De gegenereerde code is als volgt:


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

Er is geen sjabloon gedefinieerd. Dat is aan ons. We definiëren de volgende sjablonen:

HeaderTemplate

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

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

Ter herinnering: het model [ItemTemplate] is het model voor de weergave van de elementen van de gegevensbron die gekoppeld is aan [DataList]. Deze gegevensbron bestaat uit een reeks gegevensregels, die elk één of meerdere waarden bevatten. De huidige regel van de gegevensbron wordt vertegenwoordigd door het object [Container.DataItem]. Zo'n rij bestaat uit kolommen. [Container.DataItem("col1")] is de waarde van de kolom "col1" van de huidige rij. Om deze waarde in de weergavecode op te nemen, schrijft men <%# Container.DataItem("col") %>. Soms wil men een element van de huidige rij in een speciale indeling weergeven. Hier willen we de kolom "prijs" van de huidige regel in euro's weergeven. We gebruiken dan de functie [DataBinder.Eval], die drie parameters accepteert:

  • de huidige regel [Container.DataItem]
  • de naam van de kolom die moet worden opgemaakt
  • de opmaakstring in de vorm {0:formaat}, waarbij [format] een van de formaten is die door de methode [string.format] worden geaccepteerd.

De code <%# DataBinder.Eval(Container.DataItem,"prijs",{0:C}) %> zorgt er dus voor dat de kolom [prix] van de huidige rij in geldwaarde wordt weergegeven (formaat C = Currency).

We krijgen dan een [DataList] die er als volgt uitziet:

Image

Hierboven zijn de gegevens met vier gegevens per regel weergegeven. Dit wordt bereikt met de volgende attributen van [DataList]:

RepeatDirection
Horizontaal
RepeatColumns
gewenst aantal kolommen

Uiteindelijk is de code van [DataList1] dezelfde als die welke iets eerder in de presentatiecode is getoond. We laten het aan de lezer over om de presentatiecode van [DataList2] te bestuderen. Net als bij de component [DataGrid] kunnen de meeste eigenschappen van [DataList] worden ingesteld met behulp van een wizard van [WebMatrix]. Hiervoor gebruik je de link [Générateur de propriétés] in het eigenschappenvenster van [DataList]:

8.7.5. De besturingselementen

De controller [global.asax, global.asax.vb] is als volgt:

[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)
        ' we maken een productobject aan
        Try
            Dim données As DataSet = New produits(ConfigurationSettings.AppSettings("OLEDBStringConnection")).getDataSet("select * from LISTE")
            ' het object wordt in de applicatie geplaatst
            Application("données") = données
            ' geen fout
            Application("erreur") = False
        Catch ex As Exception
            'er is een fout opgetreden, dit wordt genoteerd in de applicatie
            Application("erreur") = True
            Application("message") = ex.Message
        End Try
    End Sub
End Class

Wanneer de applicatie wordt gestart (Application_Start), genereren we een [dataset] op basis van de businessklasse [produits] en plaatsen we deze in de applicatie, zodat deze beschikbaar is voor alle verzoeken van alle klanten. Als er tijdens deze aanmaak een uitzondering optreedt, wordt deze in de applicatie geregistreerd. De procedure [Application_Start] wordt slechts één keer uitgevoerd. Vervolgens zal de controller [global.asax] niet meer in actie komen. Het is dan de controller [main.aspx.vb] die het werk zal doen:


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

    ' paginacomponenten
    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
    ' pagina-gegevens
    Protected erreursHTML As String

    Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        ' er wordt gecontroleerd of er een fout in de applicatie is
        If CType(Application("erreur"), Boolean) Then
            ' de applicatie is niet correct geïnitialiseerd
            Dim erreurs As New ArrayList
            erreurs.Add("Application momentanément indisponible (" + CType(Application("message"), String) + ")")
            afficheErreurs(erreurs, False)
            Exit Sub
        End If
        'eerste verzoek
        If Not IsPostBack Then
            ' de besturingselementen worden geïnitialiseerd
            With DataList1
                .DataSource = CType(Application("données"), DataSet)
                .DataBind()
            End With
            With DataList2
                .DataSource = CType(Application("données"), DataSet)
                .DataBind()
            End With
            ' het lege formulier wordt weergegeven
            afficheRésultats(True, False)
        End If
    End Sub

    Private Sub afficheErreurs(ByVal erreurs As ArrayList, ByVal afficheLien As Boolean)
        ' de foutpagina wordt weergegeven
        erreursHTML = ""
        For i As Integer = 0 To erreurs.Count - 1
            erreursHTML += "<li>" + erreurs(i).ToString + "</li>" + ControlChars.CrLf
        Next
        ' de weergave [erreurs] wordt weergegeven
        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)
        ' de weergave wordt weergegeven [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
        ' de stijl wordt gewijzigd
        afficheRésultats(RadioButton1.Checked, RadioButton2.Checked)
    End Sub
End Class

8.8. Repeater-component en gegevenskoppeling

Met de component [Repeater] kan de code HTML voor elk element van een gegevenslijst worden herhaald. Stel dat we een foutenlijst in de volgende vorm willen weergeven:

Image

We zijn dit probleem al eens tegengekomen en hebben het opgelost door in de weergavecode een variabele op te nemen in de vorm <ul><% =erreursHTML %></ul>, waarbij de waarde van erreursHTML door de controller wordt berekend. Deze waarde bevat de code HTML, die van een lijst. Dit heeft als nadeel dat als we de weergave van deze lijst HTML willen wijzigen, we gedwongen zijn om naar het controllergedeelte te gaan, wat in strijd is met de scheiding tussen controller en weergave. De component [Repeater] biedt hier een oplossing voor. Net als bij de [DataList], kunnen we de sjablonen <HeaderTemplate> voor de koptekst, <ItemTemplate> voor het huidige element in de gegevenslijst en <FooterTemplate> voor het einde van de gegevens definiëren. Hier zouden we de volgende definitie kunnen hebben voor de component [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>

Ter herinnering: [Container.DataItem] vertegenwoordigt een gegevensregel als de gegevensbron meerdere kolommen heeft. Het vertegenwoordigt één gegevenswaarde als de bron slechts één kolom heeft. Dat is hier het geval. Als voorbeeld bouwen we de volgende toepassing:

Image

De code voor de weergave van de pagina is als volgt:

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

De controlecode is als volgt:

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

     ' procedure die wordt uitgevoerd bij het laden van de pagina
    Sub page_Load(sender As Object, e As EventArgs)
        if not IsPostBack then
          ' er wordt een gegevensbron aangemaakt
          with Repeater1
              .DataSource=createDataSource
              .DataBind
          end with
        end if
    End Sub

    function createDataSource as ArrayList
      ' er wordt een arraylist aangemaakt
      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>

Bij het eerste verzoek van de klant koppelen we een object [ArrayList] aan de component [Repeater], die vermoedelijk een foutenlijst vertegenwoordigt.

8.9. Application

We nemen hier een applicatie die al met servercomponenten is verwerkt. Met de applicatie kunnen simulaties van belastingberekeningen worden uitgevoerd. Ze is gebaseerd op een klasse [impot], die we hier niet verder zullen bespreken. Deze klasse heeft gegevens nodig die ze vindt in een gegevensbron OLEDB. Voor dit voorbeeld gebruiken we een gegevensbron met de naam ACCESS. In deze nieuwe versie introduceren we de volgende vernieuwingen:

  • het gebruik van validatiecomponenten om de geldigheid van de gegevens te controleren
  • het gebruik van servercomponenten die aan gegevensbronnen zijn gekoppeld voor het weergeven van de resultaten

8.9.1. De structuur MVC van de applicatie

De structuur MVC van de applicatie is als volgt:

De drie weergaven worden als containers opgenomen in de presentatiecode van de controller [main.aspx]. Deze applicatie heeft dus één enkele pagina: [main.aspx].

8.9.2. De weergaven van de applicatie

De weergave [formulaire] is het formulier voor het invoeren van gegevens waarmee de belasting van een gebruiker kan worden berekend:

Image

De gebruiker vult het formulier in:

Image

Hij gebruikt de knop [Envoyer] om de berekening van zijn belasting aan te vragen. Hij krijgt dan de volgende weergave [simulations] te zien:

Image

Via de bovenstaande link keert hij terug naar het formulier. Hij vindt het terug in de staat waarin hij het heeft ingevuld. Hij kan invoerfouten maken:

Image

Deze worden hem gemeld in het scherm [formulaire]:

Image

De gebruiker corrigeert vervolgens zijn fouten. Hij kan nieuwe simulaties uitvoeren:

Image

Hij krijgt dan het scherm [simulations] te zien met nog een simulatie:

Image

Tot slot, als de gegevensbron niet beschikbaar is, wordt dit aan de gebruiker gemeld in de weergave [erreurs]:

Image

8.9.2.1. De weergavecode

Ter herinnering: de pagina [main.aspx] bevat alle weergaven. Het is één enkel formulier met drie containers:

  • [panelform] voor de weergave [formulaire]
  • [panelerreurs] voor de weergave [erreurs]
  • [panelsimulations] voor de weergave [simulations]

We zullen nu de componenten van deze drie containers nader toelichten. De container [panelform] ziet er als volgt uit:

nr.
naam
type
eigenschappen
rol
0
panelform
Paneel
 
formulierweergave
1
rdOui
rdNon
RadioButton
GroupName=rdmarie
keuzeknoppen
2
cvMarie
CustomValidator
ErrorMessage=U hebt uw burgerlijke staat niet opgegeven
EnableClientScript=false
controleert of het clientprogramma de verwachte burgerlijke staat heeft verzonden
3
txtEnfants
TextBox
 
aantal kinderen
4
rfvEnfants
RequiredFieldValidator
ErrorMessage=Geef het aantal kinderen op
ControlToValidate=txtEnfants
controleert of het veld [txtEnfants] niet leeg is
5
rvEnfants
RangeValidator
ErrorMessage=Voer een getal tussen 1 en 30 in
ControlToValidate=txtKinderen
controleert of het veld [txtEnfants] binnen het bereik [1,30] valt
6
txtSalaire
TextBox
EnableViewState=true
jaarsalaris
7
rfvSalaire
RequiredFieldValidator
ControlToValidate=txtSalaris
ErrorMessage=Geef het bedrag van uw salaris op
controleert of het veld [txtSalaire] niet leeg is
8
revSalaire
RegularExpressionValidator
ControlToValidate=txtSalaris
ErrorMessage=Ongeldig salaris
RegularExpression=\s*\d+\s*
controleert of het veld [txtSalaire] uit een reeks cijfers bestaat
9
btnCalculer
Button
CausesValidation=true
knop [submit] op het formulier – start de belastingberekening
10
btnEffacer
Knop
CausesValidation=false
knop [submit] van het formulier - wist het formulier

Het is misschien verrassend dat het controelement [cvMarié] moet controleren of de gebruiker inderdaad een van de twee keuzerondjes heeft aangevinkt. Dit kan immers niet anders zijn als hij het door de server verzonden formulier correct gebruikt. Aangezien dit niet met zekerheid kan worden vastgesteld, moeten alle verzonden parameters worden gecontroleerd. Let ook op het attribuut [CausesValidation=false] van de knop [btnEffacer]. Wanneer de gebruiker deze knop gebruikt, hoeven de verzonden gegevens namelijk niet te worden gecontroleerd, aangezien ze worden genegeerd.

Alle componenten van de container hebben de eigenschap [EnableViewState=false], behalve [panelForm, txtEnfants, txtSalaire, rdOui, rdNon]. De container [panelerreurs] heeft de volgende visuele weergave:

nr.
naam
type
eigenschappen
rol
0
panelerreurs
Paneel
EnableViewState=false
foutenweergave
1
rptErreurs
Repeater
EnableViewState=false
geeft een lijst met fouten weer

De component [rptErreurs] is als volgt gedefinieerd:


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

De gegevenslijst die bij de component [rptErreurs] hoort, is een object [ArrayList] dat een lijst met foutmeldingen bevat. Zo verwijst <%# Container.Dataitem%> hierboven naar de huidige foutmelding. De container [panelsimulations] ziet er als volgt uit:

nr.
naam
type
eigenschappen
rol
0
panelsimulations
Paneel
EnableViewState=false
weergave simulaties
2
lnkForm2
LinkButton
EnableViewState=false
link naar het formulier
1
dgSimulations
DataGrid
EnableViewState=false
verantwoordelijk voor het weergeven van de simulaties die in een object [DataTable] zijn geplaatst

De component [dgSimulations] is als volgt geconfigureerd onder [Webmatrix]. In het eigenschappenvenster van [dgSimulations] selecteren we de koppeling [Mise en forme automatique] en kiezen we het schema [Couleur 3]:

Vervolgens selecteren we, nog steeds in het eigenschappenvenster van [dlgSimulations], de koppeling [Générateur de propriétés]. We vragen om de kolomkoppen weer te geven:

Image

We selecteren de optie [Colonnes] om de vier kolommen van [DataGrid] te definiëren:

Image

We vinken de zin [Créer des colonnes automatiquement ...] uit. We gaan zelf de vier kolommen van het [DataGrid] definiëren. Dit wordt gekoppeld aan een object [DataTable] met vier kolommen, respectievelijk genaamd "getrouwd", "kinderen", "salaris" en "belasting". Om een kolom aan te maken in het [DataGrid], selecteren we de optie [Colonnes connexe] en gebruiken we de knop voor het aanmaken zoals hierboven aangegeven. Er wordt een kolom aangemaakt en we kunnen de kenmerken ervan definiëren. De eerste kolom van de simulatietabel bevat de kolom „getrouwd“ van het object [DataTable], dat aan het [DataGrid] wordt gekoppeld. Deze eerste kolom van het [DataGrid] wordt in de wizard als volgt gedefinieerd:

Image

Texte de l'en-tête
kolomtitel, hier „Getrouwd“
Champ de données
naam van de kolom in de gegevensbron die door deze kolom van het [DataGrid] wordt weergegeven. Hier is dat de kolom "getrouwd" van het [DataTable].

De tweede kolom is als volgt gedefinieerd:

Texte de l'en-tête
Kinderen
Champ de données
kinderen

De derde kolom is als volgt gedefinieerd:

Texte de l'en-tête
Jaarsalaris
Champ de données
salaris
Expression de mise en forme
{0:C} - valutaweergave om het euroteken weer te geven

De vierde kolom is als volgt gedefinieerd:

Texte de l'en-tête
Belastingbedrag
Champ de données
belasting
Expression de mise en forme
{0:C} - valutaweergave om het euroteken te verkrijgen

We plaatsen de weergavecode en de controlecode in twee afzonderlijke bestanden. Het eerste bestand staat in [main.aspx] en het tweede in [main.aspx.vb]. De code van [main.aspx] is als volgt:


<%@ 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. De controlecode van de applicatie

De controlecode van de applicatie is verdeeld over de bestanden [global.asax.vb] en [main.aspx.vb]. Het bestand [global.asax] is als volgt gedefinieerd:

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

Het bestand [global.asax.vb] ziet er als volgt uit:


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)
        ' we maken een Impot-object aan
        Dim objImpot As impot
        Try
            objImpot = New impot(New impotsOLEDB(ConfigurationSettings.AppSettings("chaineConnexion")))
            ' het object wordt in de applicatie geplaatst
            Application("objImpot") = objImpot
            ' geen fout
            Application("erreur") = False
        Catch ex As Exception
            'er is een fout opgetreden, dit wordt in de applicatie genoteerd
            Application("erreur") = True
            Application("message") = ex.Message
        End Try
    End Sub

    Sub Session_Start(ByVal sender As Object, ByVal e As EventArgs)
        ' begin van de sessie – er wordt een lege lijst met simulaties aangemaakt
        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

Wanneer de applicatie wordt gestart (eerste verzoek aan de applicatie), wordt de procedure [Application_Start] uitgevoerd. Deze procedure probeert een object van het type [impot] aan te maken, waarbij de gegevens uit een bron van het type OLEDB worden gehaald. De lezer wordt verzocht hoofdstuk 5 te raadplegen, waarin deze klasse is gedefinieerd, mocht hij dit vergeten zijn. Het aanmaken van het object [impot] kan mislukken als de gegevensbron niet beschikbaar is. In dat geval wordt de fout in de applicatie opgeslagen, zodat alle volgende verzoeken weten dat het object niet correct kon worden geïnitialiseerd. Als het aanmaken goed verloopt, wordt het aangemaakte object [impot] eveneens in de applicatie opgeslagen. Dit object zal worden gebruikt door alle verzoeken voor belastingberekeningen. Wanneer een klant zijn eerste verzoek indient, wordt er voor hem een sessie aangemaakt door de procedure [Application_Start]. Deze sessie is bedoeld om de verschillende simulaties van de belastingberekening die hij gaat uitvoeren op te slaan. Deze worden opgeslagen in een object [DataTable] dat is gekoppeld aan de sessiesleutel "simulaties". Bij het starten van de sessie wordt deze sleutel gekoppeld aan een leeg object [DataTable], waarvan de structuur echter al is gedefinieerd. De informatie die de applicatie nodig heeft, wordt opgeslagen in het configuratiebestand [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>

De sleutel [chaineConnexion] verwijst naar de verbindingsstring met de bron OLEDB. Het andere deel van de controlecode bevindt zich in [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

    ' lokale variabelen

    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

De eerste gebeurtenis die door de code wordt verwerkt, is [Page_Load]:


    Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        ' Allereerst wordt gekeken in welke status de applicatie zich bevindt
        If CType(Application("erreur"), Boolean) Then
            ' de applicatie kon niet worden geïnitialiseerd
            ' we geven het foutenscherm weer
            Dim erreurs As New ArrayList
            erreurs.Add("Application momentanément indisponible (" + CType(Application("message"), String) + ")")
            afficheErreurs(erreurs)
            Exit Sub
        End If
        ' geen fouten – bij het eerste verzoek wordt het formulier weergegeven
        If Not IsPostBack Then afficheFormulaire()
    End Sub

Voordat we beginnen met het verwerken van de aanvraag, controleren we of de applicatie correct is opgestart. Als dat niet het geval is, wordt de weergave [erreurs] weergegeven met de procedure [afficheErreurs]. Als dit de eerste aanvraag is (IsPostBack=false), laten we de weergave [formulaire] weergeven met [afficheFormulaire].

De procedure die de weergave [erreurs] weergeeft, is als volgt:


    Private Sub afficheErreurs(ByRef erreurs As ArrayList)
        ' de foutenlijst wordt samengesteld
        With rptErreurs
            .DataSource = erreurs
            .DataBind()
        End With
        ' de containers worden weergegeven 
        panelerreurs.Visible = True
        panelform.Visible = False
        panelsimulations.Visible = False
        Exit Sub
    End Sub

De procedure ontvangt als parameter een lijst met foutmeldingen in [erreurs] van het type [ArrayList]. We koppelen deze gegevensbron eenvoudigweg aan de component [rptErreurs], die verantwoordelijk is voor de weergave ervan.

De procedure die de weergave [formulaire] weergeeft, is als volgt:


    Private Sub afficheFormulaire()
        ' het formulier wordt weergegeven
        panelform.Visible = True
        ' de overige containers worden verborgen
        panelerreurs.Visible = False
        panelsimulations.Visible = False
    End Sub

Deze procedure zorgt er alleen voor dat de container [panelform] zichtbaar wordt gemaakt. De componenten worden weergegeven met hun geposte of vorige waarde (VIEWSTATE).

Wanneer de gebruiker op de knop [Calculer] in de weergave [formulaire] klikt, wordt een overgang van POST naar [main.aspx] uitgevoerd. De procedure [Page_Load] wordt uitgevoerd, gevolgd door de procedure [btnCalculer_Click]:


    Private Sub btnCalculer_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnCalculer.Click
        ' de geldigheid van de ingevoerde gegevens wordt gecontroleerd; als er fouten zijn, wordt dit gemeld
        If Not Page.IsValid Then
            afficheFormulaire()
            Exit Sub
        End If
        ' geen fouten – de belasting wordt berekend
        Dim impot As Long = CType(Application("objImpot"), impot).calculer( _
        rdOui.Checked, CType(txtEnfants.Text, Integer), CType(txtSalaire.Text, Long))
        ' het resultaat wordt toegevoegd aan de bestaande simulaties
        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)
        ' de simulaties worden in de sessie opgeslagen
        Session.Item("simulations") = simulations
        ' de simulatiepagina wordt weergegeven
        afficheSimulations(simulations, "Retour au formulaire")
    End Sub

De procedure begint met het controleren van de geldigheid van de pagina. Hierbij moet worden opgemerkt dat, wanneer de procedure [btnCalculer_Click] wordt uitgevoerd, de validatiecontroles hun werk al hebben gedaan en het attribuut [IsValid] van de pagina is ingesteld. Als de pagina niet geldig is, wordt de weergave [formulaire] opnieuw weergegeven en wordt de procedure beëindigd. De validatiecomponenten van de weergave [formulaire] waarvan het attribuut [IsValid] gelijk is aan [false], zullen hun attribuut [ErrorMessage] weergeven. Als de pagina geldig is, wordt het belastingbedrag berekend aan de hand van het object van het type [impot] dat bij het opstarten van de applicatie was opgeslagen. Deze nieuwe simulatie wordt toegevoegd aan de lijst met reeds uitgevoerde simulaties en opgeslagen in de sessie.

Ten slotte wordt de weergave [simulations] weergegeven door de volgende procedure [afficheSimulations]:


    Private Sub afficheSimulations(ByRef simulations As DataTable, ByRef lien As String)
        ' de datagrid wordt gekoppeld aan de bron ‘simulaties’
        With dgSimulations
            .DataSource = simulations
            .DataBind()
        End With
        ' koppeling
        lnkForm2.Text = lien
        ' de weergaven
        panelsimulations.Visible = True
        panelerreurs.Visible = False
        panelform.Visible = False
    End Sub

De procedure heeft twee parameters:

  • een lijst met simulaties in [simulations] van het type [DataTable]
  • een linktekst in [lien]

De gegevensbron [simulations] is gekoppeld aan de component die deze moet weergeven. De linktekst wordt opgeslagen in de eigenschap [Text] van het object [LinkButton] in de weergave.

Wanneer de gebruiker op de knop [Effacer] in de weergave [formulaire] klikt, wordt de procedure [btnEffacer_click] uitgevoerd (altijd na [Page_Load]):


    Private Sub btnEffacer_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnEffacer.Click
        ' het lege formulier weergeven
        razForm()
        afficheFormulaire()
    End Sub

    Private Sub razForm()
        ' wist het formulier
        rdOui.Checked = False
        rdNon.Checked = True
        txtEnfants.Text = ""
        txtSalaire.Text = ""
    End Sub

De bovenstaande code is eenvoudig genoeg om geen uitleg te behoeven. We moeten nu nog de klik op de links in de weergaven [erreurs] en [simulations] afhandelen:


    Private Sub lnkForm1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles lnkForm1.Click
        ' geeft het formulier weer
        afficheFormulaire()
    End Sub

    Private Sub lnkForm2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles lnkForm2.Click
        ' toont het formulier
        afficheFormulaire()
    End Sub

Beide procedures zorgen er alleen voor dat de weergave [formulaire] wordt weergegeven. We weten dat de velden in dit formulier een waarde krijgen die ofwel de voor hen verzonden waarde is, ofwel hun vorige waarde. Aangezien de POST van de klant in dit geval geen waarden voor de velden van het formulier verzendt, krijgen deze hun vorige waarde terug. Het formulier wordt dus weergegeven met de door de gebruiker ingevoerde waarden.

8.9.4. Tests

Alle bestanden die nodig zijn voor de applicatie worden in een map <application-path> geplaatst:
De map [bin] bevat de DLL met de klassen [impot], [impotsData] en [impotsOLEDB] die nodig zijn voor de applicatie:

De lezer kan, indien gewenst, hoofdstuk 5 nog eens doorlezen, waarin wordt uitgelegd hoe het bovenstaande bestand [impot.dll] moet worden aangemaakt. Daarna wordt de Cassini-server gestart met de parameters (<application-path>,/impots6). De URL [http://impots6/main.aspx] wordt opgevraagd met een browser:

Image

Als we het bestand ACCESS [impots.mdb] hernoemen naar [impots1.mdb], krijgen we de volgende pagina te zien:

Image

8.9.5. Conclusie

We hebben een applicatie MVC die uitsluitend gebruikmaakt van servercomponenten. Door het gebruik hiervan is het mogelijk geweest om het presentatiegedeelte van de applicatie volledig te scheiden van het besturingsgedeelte. Dit was tot nu toe nog niet mogelijk, omdat de presentatiecode variabelen bevatte die door de besturingscode werden berekend en waarvan de waarde HTML-code bevatte. Nu is dat niet meer het geval.