Skip to content

8. Serverkomponenten ASP – 2

8.1. Introduction

Wir setzen unsere Arbeit an der Benutzeroberfläche fort und befassen uns mit:

  • Komponenten zur Datenvalidierung
  • die Art und Weise, wie Daten mit Serverkomponenten verknüpft werden
  • die Serverkomponenten HTML

8.2. Komponenten zur Datenvalidierung

8.2.1. Einführung

In Formularanwendungen ist es von entscheidender Bedeutung, die Gültigkeit der in die Formulare eingegebenen Daten zu überprüfen. Im Beispiel zur Steuerberechnung hatten wir das folgende Formular:

Image

Nach dem Empfang der Werte aus diesem Formular müssen wir die Gültigkeit der eingegebenen Daten überprüfen: Die Anzahl der Kinder und das Gehalt müssen positive ganze Zahlen oder Null sein. Ist dies nicht der Fall, wird das Formular so, wie es eingegeben wurde, mit Fehlermeldungen an den Kunden zurückgesendet. Wir hatten diesen Fall mit zwei Ansichten behandelt, eine für das obige Formular und eine für die Fehler:

Image

ASP.NET bietet sogenannte Validierungskomponenten, mit denen folgende Fälle überprüft werden können:

Komponente
Rolle
RequiredFieldValidator
prüft, ob ein Feld nicht leer ist
CompareValidator
vergleicht zwei Werte miteinander
RangeValidator
prüft, ob ein Wert zwischen zwei Grenzwerten liegt
RegularExpressionValidator
prüft, ob ein Feld einem regulären Ausdruck entspricht
CustomValidator
ermöglicht es dem Entwickler, eigene Validierungsregeln festzulegen – diese Komponente könnte alle anderen ersetzen
ValidationSummary
ermöglicht es, die von den vorherigen Prüfungen ausgegebenen Fehlermeldungen an einer einzigen Stelle auf der Seite zusammenzufassen

Wir werden nun jede dieser Komponenten vorstellen.

8.2.2. RequiredFieldValidator

Wir erstellen die folgende Seite [requiredfieldvalidator1.aspx]:

Nr.
Name
Typ
Eigenschaften
Rolle
1
txtNom
TextBox
EnableViewState=true
Eingabefeld
2
RequiredFieldValidator1
RequiredFieldValidator
EnableViewState=false
EnableClientScript=true
ErrorMessage=Das Feld [Name] ist ein Pflichtfeld
Validierungskomponente
3
btnEnvoyer
Schaltfläche
EnableViewState=false
CausesValidation=true
Schaltfläche [submit]

Das Feld [RequiredFieldValidator1] dient dazu, eine Fehlermeldung anzuzeigen, wenn das Feld [txtNom] leer ist oder eine Folge von Leerzeichen enthält. Es weist folgende Eigenschaften auf:

ControlToValidate
Feld, dessen Wert von der Komponente überprüft werden muss. Was bedeutet der Wert einer Komponente? Es handelt sich um den Wert des Attributs [value] des entsprechenden Tags HTML. Bei einem [TextBox] ist dies der Inhalt des Eingabefelds, bei einem [DropDownList] der Wert des ausgewählten Elements.
EnableClientScript
Boolescher Wert – „wahr“ gibt an, dass der Inhalt des vorherigen Feldes auch auf der Client-Seite überprüft werden muss. In diesem Fall wird das Formular vom Browser nur dann gesendet, wenn es keine Fehler enthält. Die Validierungsprüfungen werden jedoch auch auf dem Server durchgeführt, für den Fall, dass es sich bei dem Client beispielsweise nicht um einen Browser handelt.
ErrorMessage
Die Fehlermeldung, die die Komponente im Falle eines erkannten Fehlers anzeigen soll

Die Überprüfung der Daten auf der Seite durch die Validierungsprüfungen erfolgt nur, wenn die Schaltfläche oder der Link, der den [POST] der Seite ausgelöst hat, die Eigenschaft [CausesValidation=true] besitzt. [true] ist der Standardwert dieser Eigenschaft.

Führen wir diese Anwendung aus. Wir verwenden zunächst einen Browser mit der Eigenschaft [Mozilla]:

Image

Der von [Mozilla] empfangene Code HTML lautet wie folgt:

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

Man sieht, dass die Schaltfläche [btnEnvoyer] über ihr Attribut [onclick] mit einer JavaScript-Funktion verknüpft ist. Außerdem ist festzustellen, dass die Seite keinen Code [Javascript] enthält. Der Test [typeof(Page_ClientValidate) == 'function'] schlägt fehl und die JavaScript-Funktion wird nicht aufgerufen. Das Formular wird dann an den Server gesendet, der die Gültigkeitsprüfungen durchführt. Verwenden wir die Schaltfläche [Envoyer] ohne Angabe eines Namens. Die Antwort des Servers lautet wie folgt:

Image

Was ist passiert? Das Formular wurde an den Server gesendet. Dieser hat den Code aller auf der Seite befindlichen Validierungskomponenten ausführen lassen. Hier gibt es nur eine. Wenn mindestens eine Validierungskomponente einen Fehler feststellt, sendet der Server das Formular so zurück, wie es eingegeben wurde (genauer gesagt für die Komponenten mit [EnableViewState=true], zusätzlich mit einer Fehlermeldung für jede Validierungskomponente, die einen Fehler festgestellt hat). Diese Meldung ist das Attribut [ErrorMessage] der Validierungskomponente. Genau diesen Mechanismus sehen wir oben in Aktion. Wenn wir etwas in das Feld [nom] eingeben, erscheint die Fehlermeldung beim Absenden des Formulars nicht mehr:

Image

Verwenden wir nun den Internet Explorer und rufen wir die URL [http://localhost/requiredfieldvalidator1.aspx] auf. Wir erhalten die folgende Seite:

Image

Der von IE empfangene Code HTML lautet wie folgt:

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

Man sieht, dass dieser Code wesentlich umfangreicher ist als der von [Mozilla]. Wir werden hier nicht näher darauf eingehen. Der Unterschied rührt daher, dass der Server JavaScript-Funktionen in das gesendete Dokument HTML eingebunden hat. Warum gibt es zwei unterschiedliche HTML-Codes, obwohl die von beiden Browsern angeforderte URL dieselbe ist? Wir haben bereits erwähnt, dass die ASP.NET-Technologie bewirkt, dass der Server das an den Client gesendete Dokument HTML an die Gegebenheiten dieses Clients anpasst. Auf dem Markt gibt es verschiedene Browser, die nicht alle über die gleichen Funktionen verfügen. Die Browser von Microsoft und Netscape beispielsweise verwenden nicht dasselbe Objektmodell für das Dokument, das sie empfangen. Daher weist der JavaScript-Code zur Bearbeitung dieses Dokuments auf der Browserseite Unterschiede zwischen den beiden Browsern auf. Ebenso haben die Hersteller aufeinanderfolgende Versionen ihrer Browser entwickelt und deren Funktionen kontinuierlich verbessert. Daher kann es vorkommen, dass ein Dokument HTML, das von IE5 verstanden wird, von IE3 nicht verstanden wird. Oben haben wir ein Beispiel für diese Anpassung des Servers an seinen Client. Aus einem hier nicht näher erläuterten Grund ging der Webserver davon aus, dass der Client [Mozilla] nicht in der Lage war, den JavaScript-Code zur Validierung zu verarbeiten. Daher wurde dieser Code nicht in das an ihn gesendete Dokument HTML eingefügt, und die Validierung erfolgte serverseitig. Bei [IE6] wurde dieser JavaScript-Code, wie wir sehen können, in das gesendete Dokument HTML eingefügt. Um zu sehen, wie das funktioniert, führen wir folgendes Experiment durch:

  • Stoppen wir den Webserver
  • und nutzen wir die Schaltfläche [Envoyer], ohne das Feld [nom] auszufüllen

Wir erhalten die folgende neue Seite:

Image

Die Fehlermeldung wurde tatsächlich vom Browser angezeigt. Der Server ist nämlich angehalten. Wir können uns davon überzeugen, indem wir etwas in das Feld „[nom]“ eingeben und auf „Absenden“ klicken. Diesmal lautet die Antwort wie folgt:

Image

Was ist passiert? Der Browser hat den JavaScript-Code zur Validierung ausgeführt. Dieser Code hat festgestellt, dass die Seite gültig war. Der Browser hat das Formular daher an den Webserver gesendet, der jedoch heruntergefahren war. Der Browser hat dies bemerkt und die oben gezeigte Seite angezeigt. Wenn man den Server neu startet, funktioniert alles wieder normal.

Was lässt sich aus diesem Beispiel lernen?

  • den Nutzen des Konzepts der Validierungskomponente, die es ermöglicht, jedes fehlerhafte Formular an den Client zurückzusenden
  • den Nutzen von „[VIEWSTATE]“, wodurch dieses Formular so zurückgesendet werden kann, wie es eingegeben wurde
  • die Anpassungsfähigkeit des Servers an seinen Client. Dieser wird durch den Header HTTP [User-Agent:] identifiziert, den er an den Server sendet. Es ist also nicht der Server, der „errät“, mit wem er es zu tun hat. Diese Anpassungsfähigkeit ist für den Entwickler von großem Interesse, da er sich keine Gedanken über den Client-Typ seiner Anwendung machen muss.

8.2.3. CompareValidator

Wir erstellen die folgende Seite [comparevalidator1.aspx]:

Image

Nr.
Name
Typ
Eigenschaften
Rolle
1
cmbChoix1
DropDownList
EnableViewState=true
Dropdown-Liste
2
cmbChoix2
DropDownList
EnableViewState=true
Dropdown-Liste
3
CompareValidator1
CompareValidator
EnableViewState=false
EnableClientScript=true
ErrorMessage=Ungültige Auswahl 1
ZuVergleichenderWert=?
Operator=Nicht gleich
Typ=Zeichenkette
Validierungskomponente
4
CompareValidator2
CompareValidator
EnableViewState=false
EnableClientScript=true
ErrorMessage=Ungültige Auswahl 2
ControlToCompare=?
Operator=Nicht gleich
Typ=Zeichenkette
Validierungskomponente
5
btnEnvoyer
Schaltfläche
EnableViewState=false
CausesValidation=true
Schaltfläche [submit]

Die Komponente [CompareValidator] dient dazu, zwei Werte miteinander zu vergleichen. Die verwendbaren Operatoren sind [Equal, NotEqual, LessThan, LessThanEqual, GreaterThan, GreaterThanEqual]. Der erste Wert wird durch die Eigenschaft [ControlToValidate] festgelegt, der zweite durch [ValueToCompare], wenn der vorherige Wert mit einer Konstante verglichen werden soll, oder durch [ControlToCompare], wenn er mit dem Wert einer anderen Komponente verglichen werden soll. Die wichtigen Eigenschaften der Komponente [CompareValidator] sind folgende:

ControlToValidate
Feld, dessen Inhalt von der Komponente geprüft werden soll
EnableClientScript
Boolescher Wert – bei „wahr“ wird angegeben, dass der Inhalt des vorherigen Feldes auch auf der Client-Seite überprüft werden soll
ErrorMessage
die Fehlermeldung, die die Komponente im Falle eines erkannten Fehlers anzeigen soll
ValeurToCompare
Wert, mit dem der Wert des Feldes verglichen werden soll [ControlToValidate]
ControlToCompare
Komponente, mit deren Wert der Wert des Feldes verglichen werden soll [ControlToValidate]
Operator
Vergleichsoperator zwischen den beiden Werten
Type
Typ der zu vergleichenden Werte

Der Darstellungscode dieser Seite lautet wie folgt:

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

Die Validierungsbedingungen für die Seite lauten wie folgt:

  • Der in [cmbChoix1] ausgewählte Wert muss sich von der Zeichenfolge „?“ unterscheiden. Dies impliziert die folgenden Eigenschaften für die Komponente [CompareValidator1]: Operator=NotEqual, ValueToCompare=?, Typ=Zeichenkette
  • Der in [cmbChoix2] ausgewählte Wert muss sich von dem in [cmbChoix1] ausgewählten Wert unterscheiden. Dies impliziert die folgenden Eigenschaften für die Komponente [CompareValidator2]: Operator=NotEqual, ControlToCompare=cmbChoix1, Typ=Zeichenkette

Wir führen diese Anwendung aus. Hier ist ein Beispiel für eine Seite, die während des Client-Server-Austauschs empfangen wurde:

Image

Wird dieselbe Seite mit Internet Explorer 6 aufgerufen, ist darin JavaScript-Code enthalten, der zu einer leicht abweichenden Funktionsweise führt. Eventuelle Fehler werden gemeldet, sobald der Benutzer den Wert in einer der Dropdown-Listen ändert. Dies stellt eine Verbesserung des Benutzerkomforts dar.

8.2.4. CustomValidator, RangeValidator

Wir erstellen die folgende Seite [customvalidator1.aspx]:

Image

Nr.
Name
Typ
Eigenschaften
Rolle
1
cmbDiplomes
DropDownList
EnableViewState=true
Dropdown-Liste
2
CompareValidator2
CompareValidator
EnableViewState=false
EnableClientScript=true
ErrorMessage=Ungültiges Diplom
Operator=Nicht gleich
ValueToCompare=?
Typ=Zeichenkette
Validierungskomponente der Prüfung [1]
3
txtAutreDiplome
TextBox
EnableViewState=false
Eingabefeld
4
CustomValidator1
CustomValidator
EnableViewState=false
EnableClientScript=true
ErrorMessage=Ungültige Angabe zum Abschluss
ClientValidationFunction=chkAutreDiplome
Validierungskomponente für das Feld [3]
5
txtAnDiplome
TextBox
EnableViewState=false
Eingabefeld
6
RangeValidator1
RangeValidator
EnableViewState=false
EnableClientScript=true
ErrorMessage=Das Abschlussjahr muss im Bereich [1990,2004] liegen
MinValue=1990
MaxValue=2004
Typ=Ganzzahl
Zu validierendes Steuerelement=txtAnDiplome
Validierungskomponente für das Feld [5]
7
RequiredFieldValidator2
RequiredFieldValidator
EnableViewState=false
EnableClientScript=true
ErrorMessage=Angabe des Abschlussjahres erforderlich
ControlToValidate=txtAnDiplome
Validierungskomponente für das Feld [5]
8
btnEnvoyer
Schaltfläche
EnableViewState=false
Validierungsursachen=true
Schaltfläche [submit]

Das Feld [RangeValidator] dient dazu, zu überprüfen, ob der Wert eines Steuerelements zwischen den beiden Grenzwerten [MinValue] und [MaxValue] liegt. Es weist folgende Eigenschaften auf:

ControlToValidate
Feld, dessen Wert von der Komponente überprüft werden soll
EnableClientScript
Boolescher Wert – bei „wahr“ wird der Inhalt des vorherigen Feldes auch auf der Client-Seite überprüft
ErrorMessage
die Fehlermeldung, die die Komponente im Falle eines erkannten Fehlers anzeigen soll
MinValue
Mindestwert des zu prüfenden Feldes
MaxValue
Maximalwert des zu prüfenden Feldwerts
Type
Typ des zu prüfenden Feldwerts

Das Feld [CustomValidator] ermöglicht Validierungen, die mit den von ASP.NET angebotenen Validierungskomponenten nicht durchgeführt werden können. Diese Validierung erfolgt durch eine vom Entwickler geschriebene Funktion. Diese wird serverseitig ausgeführt. Da die Prüfung auch clientseitig erfolgen kann, muss der Entwickler unter Umständen eine JavaScript-Funktion entwickeln, die er in das Dokument HTML einbindet. Die Eigenschaften lauten wie folgt:

ControlToValidate
Feld, dessen Wert von der Komponente überprüft werden muss
EnableClientScript
Boolescher Wert – bei „wahr“ muss der Inhalt des vorherigen Feldes ebenfalls clientseitig geprüft werden
ErrorMessage
die Fehlermeldung, die die Komponente im Falle eines erkannten Fehlers anzeigen soll
ClientValidationFunction
die auf der Client-Seite auszuführende Funktion

Der Code für die Darstellung der Seite lautet wie folgt:

<%@ Page Language="VB" %>
<script runat="server">
...
</script>
<html>
<head>
</head>
<body>
    <form runat="server">
        <p align="left">
            Demande du dossier de candidature au DESS 
        </p>
        <fieldset>
            <legend>[--Votre dernier diplôme--]</legend>
            <table>
                <tbody>
                    <tr>
                        <td>
                            Diplôme*</td>
                        <td>
                            <asp:DropDownList id="cmbDiplomes" runat="server">
                                <asp:ListItem Value="?">?</asp:ListItem>
                                <asp:ListItem Value="[Autre]">[Autre]</asp:ListItem>
                                <asp:ListItem Value="Ma&#238;trise">Ma&#238;Trise</asp:ListItem>
                                <asp:ListItem Value="DESS">DESS</asp:ListItem>
                                <asp:ListItem Value="DEA">DEA</asp:ListItem>
                            </asp:DropDownList>
                        </td>
                        <td>
                            Si [Autre], précisez</td>
                        <td>
                            <asp:TextBox id="txtAutreDiplome" runat="server" EnableViewState="False"></asp:TextBox>
                        </td>
                    </tr>
                    <tr>
                        <td>
                        </td>
                        <td>
                            <p>
                                <asp:CompareValidator id="CompareValidator2" runat="server" ErrorMessage="Diplôme invalide" ControlToValidate="cmbDiplomes" ValueToCompare="?" Operator="NotEqual" ></asp:CompareValidator>
                            </p>
                        </td>
                        <td>
                        </td>
                        <td>
                            <asp:CustomValidator id="CustomValidator1" runat="server" ErrorMessage="Précision diplôme invalide" OnServerValidate="CustomValidator1_ServerValidate_1" EnableViewState="False" ClientValidationFunction="chckAutreDiplome"></asp:CustomValidator>
                        </td>
                    </tr>
                    <tr>
                        <td>
                            Année d'obtention*</td>
                        <td colspan="3">
                            <asp:TextBox id="txtAnDiplome" runat="server" Columns="4"></asp:TextBox>
                            <asp:RangeValidator id="RangeValidator1" runat="server" ErrorMessage="Année diplôme doit être dans l'intervalle [1990,2004]" ControlToValidate="txtAnDiplome" MinimumValue="1990" MaximumValue="2004" Type="Integer"></asp:RangeValidator>
                            <asp:RequiredFieldValidator id="RequiredFieldValidator2" runat="server" ErrorMessage="Année diplôme requise" ControlToValidate="txtAnDiplome"></asp:RequiredFieldValidator>
                        </td>
                    </tr>
                </tbody>
            </table>
        </fieldset>
        <p>
            <asp:Button id="btnEnvoyer" runat="server" Text="Envoyer"></asp:Button>
        </p>
    </form>
</body>
</html>

Mit dem Attribut [OnServerValidate] der Komponente [CustomValidator] lässt sich die Funktion festlegen, die für die serverseitige Validierung zuständig ist. Im obigen Beispiel ruft die Komponente [CustomValidator1] die folgende Prozedur [CustomValidator1_ServerValidate_1] auf:

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

    Sub CustomValidator1_ServerValidate_1(sender As Object, e As ServerValidateEventArgs)
        ' Das Feld [txtAutreDiplome] darf nicht leer sein, wenn [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>
....

Eine Validierungsfunktion, die einer Komponente [CustomValidator] zugeordnet ist, erhält zwei Parameter:

  • sender: das Objekt, das das Ereignis ausgelöst hat
  • e: das Ereignis. Die Prozedur muss das Attribut [e.IsValid] auf „wahr“ setzen, wenn die überprüften Daten korrekt sind, andernfalls auf „falsch“.

Hier werden folgende Prüfungen durchgeführt:

  • Die Dropdown-Liste [cmbDiplomes] darf nicht den Wert [?] annehmen. Dies wird durch die Komponente [CompareValidator2] überprüft
  • Der Benutzer wählt einen Abschluss aus der Dropdown-Liste [cmbDiplomes] aus. Wenn sein Abschluss nicht in der Liste enthalten ist, hat er die Möglichkeit, die Option [Autre] aus der Liste auszuwählen. Er muss dann seinen Abschluss im Eingabefeld [txtAutreDiplome] angeben. Wenn [Autre] in [cmbDiplomes] ausgewählt ist, darf das Feld [txtAutreDiplome] nicht leer sein. Wenn weder [Autre] noch [?] in [cmbDiplomes] ausgewählt ist, muss das Feld [txtAutreDiplome] leer sein. Dies wird durch die der Komponente [CustomValidator1] zugeordnete Funktion überprüft.
  • Das Jahr des Abschlusses muss im Bereich von [1900-2004] liegen. Dies wird durch [RangeValidator1] überprüft. Wenn der Benutzer jedoch nichts in das Feld eingibt, wird die Validierungsfunktion von [RangeValidator1] nicht verwendet. Daher wird die Komponente [RequiredFieldValidator2] hinzugefügt, um das Vorhandensein eines Inhalts zu überprüfen. Dies ist eine allgemeine Regel. Der Inhalt eines Feldes wird nicht überprüft, wenn dieses leer ist. Der einzige Fall, in dem dies geschieht, ist der, in dem es mit einer Komponente [RequiredFieldValidator] verknüpft ist.

Hier ein Beispiel für die Ausführung im Browser [Mozilla]:

Image

Wenn wir den Browser [IE6] verwenden, können wir eine clientseitige Validierungsfunktion für die Komponente [CustomValidator1] hinzufügen. Dazu verfügt diese Komponente über folgende Eigenschaften:

  • EnableClientScript=true
  • ClientValidationFunction=chkAutreDiplome

Die Funktion [chkAutreDiplome ] lautet wie folgt:

<head>
    <meta http-equiv="pragma" content="no-cache" />
    <script language="javascript">
        function chkAutreDiplome(source,args){
             // überprüft die Gültigkeit des Feldes txtAutreDiplome
            with(document.frmCandidature){
                diplome=cmbDiplomes.options[cmbDiplomes.selectedIndex].text;
                    args.IsValid= !(diplome=="[Autre]" && txtAutreDiplome.value=="")
                        && ! (diplome!="[Autre]" && diplome!="?" && txtAutreDiplome.value!="");
            }
        }
        </script>
</head>

Die Funktion [chkAutreDiplome] erhält dieselben beiden Parameter wie die Serverfunktion [CustomValidator1_ServerValidate_1]:

  • Quelle: das Objekt, das das Ereignis ausgelöst hat
  • args: das Ereignis. Dieses verfügt über das Attribut [IsValid], das von der Funktion auf „true“ gesetzt werden muss, wenn die überprüften Daten korrekt sind. Bei einem Wert von „false“ wird an der Stelle der Validierungskomponente die zugehörige Fehlermeldung angezeigt, und das Formular wird nicht an den Server gesendet.

8.2.5. RegularExpressionValidator

Wir erstellen die folgende Seite [regularexpressionvalidator1.aspx]:

Image

Nr.
Name
Typ
Eigenschaften
Rolle
1
txtMel
TextBox
EnableViewState=true
Eingabefeld
2
RequiredFieldValidator3
RequiredFieldValidator
ControlToValidate=txtMel
Display=Dynamic
Validierungskomponente des Steuerelements [1]
3
RegularExpressionValidator1
RegularExpressionValidator
ControlToValidate=txtMel
Display=Dynamic
Validierungskomponente des Steuerelements [1]
4
btnEnvoyer
Schaltfläche
EnableViewState=false
CausesValidation=true
Schaltfläche [submit]

Hier möchten wir das Format einer E-Mail-Adresse überprüfen. Dazu verwenden wir die Komponente [RegularExpressionValidator], mit der sich die Gültigkeit eines Feldes mithilfe eines regulären Ausdrucks überprüfen lässt. Zur Erinnerung: Ein regulärer Ausdruck ist ein Muster für eine Zeichenfolge. Wir überprüfen also den Inhalt eines Feldes anhand dieses Musters. Da der Inhalt eines Feldes nicht überprüft wird, wenn es leer ist, benötigen wir zusätzlich eine Komponente [RequiredFieldValidator], um sicherzustellen, dass die E-Mail-Adresse nicht leer ist. Die Klasse [RegularExpressionValidator] verfügt über ähnliche Eigenschaften wie die Klassen der bereits behandelten Komponenten:

ControlToValidate
Feld, dessen Wert von der Komponente geprüft werden soll
EnableClientScript
Boolescher Wert – bei „wahr“ muss der Inhalt des vorherigen Feldes auch auf der Client-Seite überprüft werden
ErrorMessage
die Fehlermeldung, die die Komponente im Falle eines erkannten Fehlers anzeigen soll
RegularExpression
der reguläre Ausdruck, mit dem der Inhalt von [ControlToValidate] verglichen wird
Display
Anzeigemodus: „Static“: Das Feld ist immer vorhanden, auch wenn keine Fehlermeldung angezeigt wird; „Dynamic“: Das Feld ist nur vorhanden, wenn eine Fehlermeldung vorliegt; „None“: Die Fehlermeldung wird nicht angezeigt. Dieses Feld existiert auch für die anderen Komponenten, wurde jedoch bisher nicht verwendet.

Der reguläre Ausdruck für eine E-Mail-Adresse könnte wie folgt lauten: \s*[\w-]+(\.[\w-]+)*@[\w-]+(\.[\w-]+)+\s*

Eine E-Mail-Adresse hat die Form [champ1.champ2....@champA.champB...]. Es muss mindestens ein Feld vor dem @-Zeichen und mindestens zwei Felder dahinter stehen. Diese Felder bestehen aus alphanumerischen Zeichen und dem Zeichen -. Das alphanumerische Zeichen wird durch das Symbol \w dargestellt. Die Sequenz [\w-] steht für das Zeichen \w oder das Zeichen -. Das Zeichen + hinter einer Sequenz S bedeutet, dass sich diese 1 oder mehrmals wiederholen darf, das Zeichen * bedeutet, dass sie sich 0 oder mehrmals wiederholen darf, und das Zeichen ? bedeutet, dass sie sich 0 oder 1 Mal wiederholen darf.

Ein Feld der E-Mail-Adresse entspricht dem Muster [\w-]+. Die Tatsache, dass vor dem @-Zeichen mindestens ein Feld und danach mindestens zwei Felder vorhanden sein müssen, die durch das Zeichen . getrennt sind, entspricht dem Muster: [\w-]+(\.[\w-]+)*@[\w-]+(\.[\w-]+)+. Der Benutzer kann vor und nach der Adresse Leerzeichen eingeben. Diese werden bei der Verarbeitung entfernt. Eine Folge von Leerzeichen, die auch leer sein kann, wird durch das Muster \s* dargestellt. Daraus ergibt sich der reguläre Ausdruck für die E-Mail-Adresse: \s*[\w-]+(\.[\w-]+)*@[\w-]+(\.[\w-]+)+\s*.

Der Code zur Darstellung der Seite lautet dann wie folgt:

<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

Aus ästhetischen Gründen kann es sinnvoll sein, die Fehlermeldungen an einer einzigen Stelle zusammenzufassen, wie im folgenden Beispiel [summaryvalidator1.aspx], in dem wir alle vorherigen Beispiele auf einer einzigen Seite zusammengefasst haben:

Image

Alle Validierungssteuerelemente weisen die folgenden Eigenschaften auf:

  • [Display=Dynamic], wodurch die Steuerelemente keinen Platz auf der Seite einnehmen, wenn ihre Fehlermeldung leer ist
  • [EnableClientScript=false], um jegliche clientseitige Validierung zu unterbinden
  • [Text=*]. Dies ist die Meldung, die im Fehlerfall angezeigt wird, wobei der Inhalt des Attributs [ErrorMessage] durch das unten vorgestellte Steuerelement [ValidationSummary] angezeigt wird.

Diese Gruppe von Steuerelementen befindet sich in einer Komponente mit der Bezeichnung [Panel], die den Namen [vueFormulaire] trägt. In einer weiteren Komponente [Panel] mit dem Namen [vueErreurs] fügen wir ein Steuerelement [ValidationSummary] ein:

Image

Nr.
Name
Typ
Eigenschaften
Rolle
1
ValidationSummary1
ValidationSummary
HeaderText=Die folgenden Fehler sind aufgetreten, EnableClientScript=false, ShowSummary=true
zeigt die Fehler aller Validierungssteuerelemente auf der Seite an
2
lnkErreursToFormulaire
LinkButton
CausesValidation=false
Link zurück zum Formular

Für den Link [lnkErreursToFormulaire] muss die Validierung nicht aktiviert werden, da dieser Link keine zu überprüfenden Werte übermittelt.

Wenn alle Daten gültig sind, wird dem Benutzer die folgende Ansicht [infos] angezeigt:

Image

1

Nr.
Name
Typ
Eigenschaften
Rolle
1
lblInfo
Bezeichnung
 
Informationsmeldung für den Benutzer

Der Quellcode dieser Seite lautet wie folgt:

<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 sind einige Beispiele für die erzielten Ergebnisse. Wir bestätigen die Ansicht [formulaire], ohne Werte einzugeben:

Image

Die Schaltfläche [Envoyer] liefert uns folgende Antwort:

Image

Es wurde die Ansicht [erreurs] angezeigt. Wenn wir den Link zur Rückkehr zum Formular verwenden, finden wir dieses im folgenden Zustand vor:

Image

Es handelt sich um die Ansicht [formulaire]. Beachten Sie das Zeichen [*] neben den fehlerhaften Daten. Es handelt sich um das Feld [Text] der Validierungsprüfungen, das angezeigt wurde. Wenn wir die Felder korrekt ausfüllen, erhalten wir die Ansicht [infos]:

Image

Der Steuerungscode der Seite lautet wie folgt:

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

     ' Prozedur, die beim Laden der Seite ausgeführt wird
    Sub page_Load(sender As Object, e As EventArgs)
        ' Bei der ersten Anfrage wird die Ansicht [formulaire] angezeigt
        if not ispostback then
            afficheVues(true,false,false)
        end if
    end sub

    sub afficheVues(byval formulaireVisible as boolean, _
        erreursVisible as boolean, infosVisible as boolean)
         ' Ansichtssatz
        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)
        ' zeigt die Formularansicht an
        afficheVues(true,false,false)
         ' führt die Gültigkeitsprüfungen erneut durch
        Page.validate
    End Sub

    Sub btnEnvoyer_Click(sender As Object, e As EventArgs)
        ' Ist die Seite gültig?
        if not Page.IsValid then
            ' Die Ansicht [erreurs] wird angezeigt
            afficheVues(false,true,false)
        else
             ' ansonsten die Ansicht [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 der Prozedur [Page_Load], die bei jeder Client-Anfrage ausgeführt wird, zeigen wir die Ansicht [formulaire] an, während die anderen ausgeblendet werden. Dies geschieht nur bei der ersten Anfrage. Die Prozedur ruft eine Hilfsprozedur [afficheVues] auf, an die drei boolesche Werte übergeben werden, um die drei Sichten anzuzeigen oder nicht.
  • Wenn die Prozedur [btnEnvoyer_Click] aufgerufen wird, sind die Datenprüfungen bereits durchgeführt worden. Die Schaltfläche [btnEnvoyer] mit der Eigenschaft [CausesValidation=true] erzwingt diese Datenprüfung. Alle Validierungssteuerelemente wurden ausgeführt und ihre Eigenschaft [IsValid] gesetzt. Diese gibt an, ob die vom Steuerelement überprüften Daten gültig waren oder nicht. Außerdem wurde die Eigenschaft [IsValid] der Seite selbst ebenfalls gesetzt. Sie hat nur dann den Wert [vrai], wenn die Eigenschaft [IsValid] aller Validierungsprüfungen der Seite den Wert [vrai] hat. Daher prüft die Prozedur [btnEnvoyer_Click] zunächst, ob die Seite gültig ist oder nicht. Ist sie ungültig, wird die Ansicht [erreurs] angezeigt. Diese enthält das Steuerelement [ValidationSummary], das die Attribute [ErrorMessage] aller Steuerelemente übernimmt (siehe Screenshot oben). Ist die Seite gültig, wird die Ansicht [infos] zusammen mit einer Informationsmeldung angezeigt.
  • Die Prozedur [lnkErreursToFormulaire_Click] ist dafür zuständig, die Ansicht [formulaire] in dem Zustand anzuzeigen, in dem sie validiert wurde. Bei allen Eingabefeldern der Ansicht [formulaire], die die Eigenschaft [EnableViewState=true] besitzen, wird ihr Status automatisch neu generiert. Seltsamerweise wird der Status der Validierungskomponenten jedoch nicht wiederhergestellt. Man hätte nämlich erwarten können, dass bei der Rückkehr zur Ansicht [erreurs] die fehlerhaften Steuerelemente ihr Feld [Text] anzeigen. Dies ist jedoch nicht der Fall. Daher wurde die Datenvalidierung mithilfe der Methode [Page.Validate] der Seite erzwungen. Dies muss erfolgen, sobald das Panel [vueFormulaire] sichtbar gemacht wurde. Es finden also insgesamt zwei Validierungen statt. Dies sollte in der Praxis vermieden werden. In diesem Beispiel konnten wir jedoch neue Konzepte zur Seitenvalidierung einführen.

8.3. Komponenten ListControl und Datenverknüpfung

Einige der untersuchten Serverkomponenten ermöglichen die Anzeige einer Werteliste (DropDownList, ListBox). Andere, die wir noch nicht vorgestellt haben, ermöglichen die Anzeige mehrerer Wertelisten in Tabellen (HTML). Bei allen ist es möglich, die Werte der Listen programmgesteuert einzeln der zugehörigen Komponente zuzuordnen. Es ist ebenfalls möglich, komplexere Objekte diesen Komponenten zuzuordnen, wie beispielsweise Objekte vom Typ [Array], [ArrayList], [DataSet], [HashTable], ... was den Code vereinfacht, der die Daten der Komponente zuordnet. Diese Zuordnung wird als Datenverknüpfung bezeichnet.

Alle von der Klasse [ListControl] abgeleiteten Komponenten können einer Datenliste zugeordnet werden. Es handelt sich dabei um die Komponenten [DropDownList], [ListBox], [CheckButtonList] und [RadioButtonList]. Jede dieser Komponenten kann mit einer Datenquelle verknüpft werden. Diese kann unterschiedlich sein: [Array], [ArrayList], [DataTable], [DataSet], [HashTable], …, im Allgemeinen ein Objekt, das eine der Schnittstellen IEnumerable, ICollection oder IListSource implementiert. Wir werden nur einige davon vorstellen. Ein Objekt vom Typ [DataSet] ist ein Datenbankobjekt einer relationalen Datenbank. Es handelt sich also um eine Sammlung von Tabellen, die durch Beziehungen miteinander verknüpft sind. Das Objekt [DataTable] repräsentiert eine solche Tabelle. Die Datenquelle weist jedem der Elemente [Item] des Objekts [ListControl] die Eigenschaften [Text] und [Value] zu. Wenn T der Wert von [Text] und V der Wert von [Value] ist, lautet das für jedes Element von [ListControl] generierte Tag HTML wie folgt:

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

Die Zuordnung einer Komponente [ListControl] zu einer Datenquelle erfolgt über die folgenden Eigenschaften:

DataSource
eine Datenquelle [Array], [ArrayList], [DataTable], [DataSet], [HashTable], ...
DataMember
Falls die Datenquelle ein [DataSet] ist, steht dies für den Namen der Tabelle, die als Datenquelle verwendet werden soll. Die eigentliche Datenquelle ist dann eine Tabelle.
DataTextField
falls die Datenquelle eine Tabelle ist ([DataTable], [DataSet]), steht dies für den Namen der Spalte in der Tabelle, deren Werte in das Feld [Text] der Elemente von [ListControl] übernommen werden
DataValueField
falls es sich bei der Datenquelle um eine Tabelle handelt ([DataTable],[DataSet]), steht für den Namen der Spalte in der Tabelle, deren Werte in das Feld [Value] der Elemente von [ListControl] übernommen werden

Die Zuordnung einer Komponente [ListControl] zu einer Datenquelle initialisiert die Komponente nicht mit den Werten der Datenquelle. Dies erfolgt durch den Vorgang [ListControl].DataBind.

Je nach Art der Datenquelle erfolgt die Verknüpfung dieser mit einer Komponente [ListControl] auf unterschiedliche Weise:

Array A
[ListControl].DataSource=A
Die Felder [Text] und [Value] der Elemente von [ListControl] erhalten als Werte die Elemente von A
ArrayList AL
[ListControl].DataSource=AL
Die Felder [Text] und [Value] der Elemente von [ListControl] erhalten die Werte der Elemente von AL
DataTable DT
[ListControl].DataSource=DT, [ListControl].DataTextField = „col1“, [ListControl]. DatavalueField = „col2“
wobei col1 und col2 zwei Spalten der Tabelle DT sind. Die Felder [Text] und [Value] der Elemente von [ListControl] erhalten die Werte der Spalten col1 und col2 der Tabelle DT
DataSet DS
[ListControl].DataSource=DS, [ListControl].DataSource="table", wobei „table“ der Name einer der Tabellen von DS ist.
[ListControl].DataTextField = „col1“, [ListControl]. DatavalueField = „col2“, wobei col1 und col2 zwei Spalten der Tabelle „table“ sind. Die Felder [Text] und [Value] der Elemente von [ListControl] erhalten die Werte der Spalten col1 und col2 der Tabelle „table“
HashTable HT
[ListControl].DataSource=HT, [ListControl].DataTextField="key", [ListControl]. DatavalueField ="value", wobei [key] und [value] jeweils die Schlüssel und Werte von HT sind.

Wir wenden diese Informationen am folgenden Beispiel „[databind1.aspx]“ an:

Hier haben wir fünf Datenverknüpfungen mit jeweils vier Steuerelementen vom Typ [DropDownList], [ListBox], [CheckBoxList] und [RadioButtonList]. Die fünf untersuchten Verknüpfungen unterscheiden sich durch ihre Datenquellen:

Verbindung
Datenquelle
1
Array
2
ArrayList
3
DataTable
4
DataSet
5
HashTable

8.3.1. Darstellungscode der Komponenten

Der Darstellungscode für die Steuerelemente der Verbindung 1 lautet wie folgt:

<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 Nummern der Verbindungen 2 bis 5 sind bis auf die Verbindungsnummer identisch.

8.3.2. Verbindung zu einer Datenquelle vom Typ Array

Die Verknüpfung der vier oben genannten Steuerelemente [ListBox] erfolgt in der Prozedur [Page_Load] des Steuerungscodes wie folgt:

' die globalen Daten
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

' Prozedur, die beim Laden der Seite ausgeführt wird
Sub page_Load(sender As Object, e As EventArgs)
    if not IsPostBack then
      ' Es werden die Datenquellen erstellt, die mit den Komponenten verknüpft werden sollen
      createDataSources
       ' Verknüpfung mit einem Array [Array]
      bindToArray
       ' Verknüpfung mit einer Liste [ArrayList]
      bindToArrayList
       ' Verknüpfung mit einer Tabelle [DataTable]
      bindToDataTable
       ' Verknüpfung zu einer Datengruppe [DataSet]
      bindToDataSet
       ' Verknüpfung mit einem Wörterbuch [HashTable]
      bindToHashTable
    end if
End Sub

sub createDataSources
   ' legt die Datenquellen an, die mit den Komponenten verknüpft werden
  ' ArrayList
  dim i as integer
  for i=0 to textes.length-1
    myDataListe.add(textes(i))
  next
   ' Datentabelle
   ' die beiden Spalten werden definiert
  myDataTable.Columns.Add("id",Type.GetType("System.Int32"))
  myDataTable.Columns.Add("texte",Type.GetType("System.String"))
  ' die Tabelle wird gefüllt
  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 – eine einzige Tabelle
  myDataSet.Tables.Add(myDataTable)
  ' Hashtabelle
  for i=0 to textes.length-1
    myHashTable.add(valeurs(i),textes(i))
  next
end sub

' Tabellenverknüpfung
sub bindToArray
         ' Zuordnung zu den Komponenten
        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
        ' Auswahl der Elemente
        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

Die Verknüpfung der Steuerelemente mit den Daten erfolgt hier nur bei der ersten Abfrage. Danach behalten die Steuerelemente ihre Elemente über den Mechanismus von [VIEWSTATE] bei. Die Verknüpfung erfolgt in der Prozedur [bindToArray]. Da es sich bei der Datenquelle um den Typ [Array] handelt, wird nur das Feld [DataSource] der Komponenten [ListControl] initialisiert. Das Befüllen des Steuerelements mit den Werten der zugehörigen Datenquelle erfolgt über die Methode [ListControl].DataBind. Erst danach enthalten die Objekte [ListControl] Elemente. Nun können einige davon ausgewählt werden.

8.3.3. Anbindung an eine Datenquelle vom Typ ArrayList

Die Datenquelle [myDataListe] wird in der Prozedur [createDataSources] initialisiert:

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

' Prozedur, die beim Laden der Seite ausgeführt wird
Sub page_Load(sender As Object, e As EventArgs)
    if not IsPostBack then
      ' Es werden die Datenquellen erstellt, die mit den Komponenten verknüpft werden sollen
      createDataSources
...
    end if
End Sub

sub createDataSources
   ' Erstellt die Datenquellen, die mit den Komponenten verknüpft werden
  ' Arraylist
  dim i as integer
  for i=0 to textes.length-1
    myDataListe.add(textes(i))
  next
...
end sub

Die Verknüpfung der vier Prüfungen [ListBox] der Verknüpfung 2 erfolgt wie folgt in der Prozedur [bindToArrayList] des Prüfcodes:

' Verknüpfung der ArrayList
sub bindToArrayList
         ' die Zuordnung zu den Komponenten
        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
        ' die Auswahl der Elemente
        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

Da die Datenquelle vom Typ [ArrayList] ist, wird nur das Feld [DataSource] der Komponenten [ListControl] initialisiert.

8.3.4. Datenquelle vom Typ DataTable

Die Datenquelle [myDataTable] wird in der Prozedur [createDataSources] initialisiert:

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

' Prozedur, die beim Laden der Seite ausgeführt wird
Sub page_Load(sender As Object, e As EventArgs)
    if not IsPostBack then
      ' Es werden die Datenquellen erstellt, die mit den Komponenten verknüpft werden sollen
      createDataSources
...
    end if
End Sub

sub createDataSources
   ' Erstellt die Datenquellen, die mit den Komponenten verknüpft werden
...
   ' Datentabelle
   ' Die beiden Spalten werden definiert
  myDataTable.Columns.Add("id",Type.GetType("System.Int32"))
  myDataTable.Columns.Add("texte",Type.GetType("System.String"))
  ' Die Tabelle wird gefüllt
  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

Zunächst wird ein Objekt [DataTable] mit den beiden Spalten [id] und [texte] angelegt. Die Spalte [id] füllt das Feld [Value] der Elemente von [ListControl], und die Spalte [texte] füllt deren Felder [Text]. Die Erstellung der Tabelle [DataTable] mit zwei Spalten erfolgt wie folgt:

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

Man erstellt also eine Tabelle mit zwei Spalten:

  • Die erste mit dem Namen „id“ ist vom Typ Ganzzahl
  • die zweite mit dem Namen „text“ ist vom Typ Zeichenkette

Nachdem die Tabellenstruktur erstellt wurde, kann sie mit dem folgenden Code gefüllt werden:

  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

Die Spalte [id] enthält Ganzzahlen aus [0,1,..,n], während die Spalte [texte] die Werte aus der Tabelle [data] enthält. Damit ist die Tabelle [dataListe] gefüllt. Die Verknüpfung der vier Steuerelemente [ListBox] der Verknüpfung 3 erfolgt wie folgt in der Prozedur [bindToDataTable] des Steuerungscodes:

sub bindToDataTable
         ' die Verknüpfung mit den Komponenten
        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
        ' Auswahl der Elemente
        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

Jede Komponente [ListControl] ist mit der Quelle [myDataTable] verknüpft, wobei für jede von ihnen Folgendes zugewiesen wird:

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

Die Tabelle [myDataTable] ist die Datenquelle. Die Spalte [id] dieser Tabelle füllt die Felder [Value] der Komponentenelemente, während die Spalte [texte] deren Felder [Text] füllt.

8.3.5. Datenquelle vom Typ DataSet

Die Datenquelle [myDataSet] wird in der Prozedur [createDataSources] initialisiert:

' die globalen Daten
dim myDataTable as new DataTable("table1")
dim myDataSet as new DataSet
...


' Prozedur, die beim Laden der Seite ausgeführt wird
Sub page_Load(sender As Object, e As EventArgs)
    if not IsPostBack then
      ' Es werden die Datenquellen erstellt, die mit den Komponenten verknüpft werden sollen
      createDataSources
...
    end if
End Sub

sub createDataSources
   ' Erstellt die Datenquellen, die mit den Komponenten verknüpft werden
   ' Dataset – eine einzige Tabelle
  myDataSet.Tables.Add(myDataTable)
...
end sub

Ein Objekt vom Typ [DataSet] repräsentiert eine Gruppe von Tabellen vom Typ [DataTable]. Die zuvor erstellte Tabelle [myDataTable] wird zu [DataSet] hinzugefügt. Die Verknüpfung der vier Steuerelemente [ListBox] der Verknüpfung 4 erfolgt wie folgt in der Prozedur [bindToDataSet] des Steuerungscodes:

sub bindToDataSet
         ' Zuordnung zu den Komponenten
        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
        ' Auswahl der Elemente
        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

Jede Komponente [ListControl] ist wie folgt mit der Datenquelle verknüpft:

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

Die Datengruppe [myDataSet] ist die Datenquelle. Da diese mehrere Tabellen umfassen kann, wird in [DataMember] der Name der Tabelle angegeben, die verwendet werden soll. Die Spalte [id] dieser Tabelle füllt die Felder [Value] der Komponentenelemente, während die Spalte [texte] deren Felder [Text] füllt.

8.3.6. Datenquelle vom Typ HashTable

Die Datenquelle [myHashTable] wird in der Prozedur [createDataSources] initialisiert:

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

' Prozedur, die beim Laden der Seite ausgeführt wird
Sub page_Load(sender As Object, e As EventArgs)
    if not IsPostBack then
      ' Es werden die Datenquellen erstellt, die mit den Komponenten verknüpft werden sollen
      createDataSources
...
    end if
End Sub

sub createDataSources
   ' Erstellt die Datenquellen, die mit den Komponenten verknüpft werden
...
  ' Hash-Tabelle
  for i=0 to textes.length-1
    myHashTable.add(valeurs(i),textes(i))
  next
end sub

Das Wörterbuch [myHashTable] kann als Tabelle mit zwei Spalten betrachtet werden, die „key“ und „value“ heißen. Die Spalte [key] enthält die Schlüssel des Wörterbuchs und die Spalte [value] die diesen zugeordneten Werte. Die Spalte [key] besteht hier aus dem Inhalt des Arrays [valeurs] und die Spalte [value] aus dem Inhalt des Arrays [textes]. Die Verknüpfung dieser Quelle mit den Steuerelementen erfolgt in der Prozedur [bindToHashTable]:

sub bindToHashTable
         ' Zuordnung zu den Komponenten
        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
        ' die Auswahl der Elemente
        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

Für jede der Komponenten erfolgt die Verknüpfung durch die folgenden Anweisungen:

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

Die Datenquelle ist das Dictionary [myHashTable]. Die Werte der Steuerelemente werden aus der Spalte [key] des Dictionaries bereitgestellt, die Texte aus der Spalte [value]. Das Einfügen der Dictionaries-Elemente in die Steuerelemente erfolgt in der Reihenfolge der Schlüssel, die grundsätzlich zufällig ist.

8.3.7. Anweisungen zum Importieren von Namensräumen

Eine Reihe von Namensräumen wird automatisch in eine Seite ASP.NET importiert. Dies ist bei „System.Data“ nicht der Fall, wo sich die Klassen [DataTable] und [DataSet] befinden. Daher muss diese Klasse importiert werden. Dies geschieht wie folgt:

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

8.4. Komponente DataGrid und Datenanbindung

Die Komponente [DataGrid] ermöglicht die Darstellung von Daten in Form von Tabellen, geht jedoch weit über diese einfache Darstellung hinaus:

  • Sie bietet die Möglichkeit, die „visuelle Darstellung“ der Tabelle präzise zu konfigurieren
  • sie ermöglicht die Aktualisierung der Datenquelle

Die Komponente [DataGrid] ist eine leistungsstarke und zugleich komplexe Komponente. Wir werden sie Schritt für Schritt vorstellen.

8.4.1. Anzeige einer Array-Datenquelle, ArrayList, DataTable, DataSet

Die Komponente [DataGrid] ermöglicht die Anzeige von Datenquellen vom Typ [Array], [ArrayList], [DataTable] und [DataSet] in einer Tabelle HTML anzuzeigen. Für diese vier Datentypen muss lediglich die Datenquelle der Eigenschaft [DataSource] der Komponente [DataGrid] zugeordnet werden:

DataSource
eine Datenquelle [Array], [ArrayList], [DataTable], [DataSet], ...
DataMember
Falls es sich bei der Datenquelle um ein [DataSet] handelt, gibt dies den Namen der Tabelle an, die als Datenquelle verwendet werden soll. Die eigentliche Datenquelle ist dann eine Tabelle. Ist dieses Feld nicht ausgefüllt, werden alle Tabellen des [DataSet] angezeigt.

Wir stellen nun die Seite [datagrid1.aspx] vor, die die Verknüpfung eines [DataGrid] mit vier verschiedenen Datenquellen zeigt:

Image

Die Seite enthält vier Komponenten [DataGrid], die wie folgt mit [WebMatrix] erstellt wurden. Die Komponente wird an ihrer Position auf der Registerkarte [Design] abgelegt:

Image

Anschließend wird ein generisches HTML-Raster gezeichnet. Die Eigenschaften eines [DataGrid] können beim Entwurf festgelegt werden. Genau das tun wir hier für seine Formatierungseigenschaften. Dazu wählen wir das zu konfigurierende [DataGrid] aus. Seine Eigenschaften werden in einem Fenster unten rechts angezeigt:

Image

Wir werden die beiden oben genannten Links verwenden. Über den Link [Générateur de propriétés] gelangt man zu den wichtigsten Eigenschaften des [DataGrid]:

Image

Wir deaktivieren den Eintrag [Afficher l'en-tête] für die vier Komponenten [DataGrid] und bestätigen die Seite. Über den anderen Link [Mise en forme automatique] können Sie aus mehreren Stilen für die Tabelle HTML wählen, die angezeigt wird:

Image

Wir wählen [couleur i] für das Element [DataGrid] mit der Nummer i. Diese Gestaltungsentscheidungen werden im Layout-Code der Seite umgesetzt:

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

Im Entwurfsmodus haben wir lediglich Formatierungseigenschaften festgelegt. Im Steuerungscode ordnen wir den vier Komponenten Daten zu:

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

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

        ' beim Laden der Seite ausgeführte Prozedur
        Sub page_Load(sender As Object, e As EventArgs)
            if not IsPostBack then
              ' Es werden die Datenquellen erstellt, die mit den Komponenten verknüpft werden sollen
              createDataSources
               ' Verknüpfung mit einem Array [Array]
              bindToArray
               ' Verknüpfung mit einer Liste [ArrayList]
              bindToArrayList
               ' Verknüpfung mit einer Tabelle [DataTable]
              bindToDataTable
               ' Verknüpfung mit einer Datengruppe [DataSet]
              bindToDataSet
            end if
        End Sub

        sub createDataSources
           ' legt die Datenquellen an, die mit den Komponenten verknüpft werden
          ' ArrayList
          dim i as integer
          for i=0 to textes1.length-1
            myDataListe.add(textes1(i))
          next
           ' Datentabelle
           ' die beiden Spalten werden definiert
          myDataTable.Columns.Add("id",Type.GetType("System.Int32"))
          myDataTable.Columns.Add("texte1",Type.GetType("System.String"))
          myDataTable.Columns.Add("texte2",Type.GetType("System.String"))
          ' die Tabelle wird gefüllt
          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 – eine einzige Tabelle
          myDataSet.Tables.Add(myDataTable)
        end sub

        ' Array-Verknüpfung
        sub bindToArray
          with DataGrid1
            .DataSource=textes1
            .DataBind
          end with
        end sub

        ' Arraylist-Verknüpfung
        sub bindToArrayList
          with DataGrid2
            .DataSource=myDataListe
            .DataBind
          end with
        end sub

        ' Datentabelle verknüpfen
        sub bindToDataTable
          with DataGrid3
            .DataSource=myDataTable
            .DataBind
          end with
        end sub

        ' Datenbestand verknüpfen
        sub bindToDataSet
          with DataGrid4
            .DataSource=myDataSet
            .DataBind
          end with
        end sub

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

Der Code ähnelt dem des vorherigen Beispiels, daher werden wir nicht näher darauf eingehen. Beachten Sie jedoch, wie die Datenverknüpfung erfolgt. Für jedes der vier Steuerelemente reicht die folgende Sequenz aus:

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

wobei [source de données] vom Typ [Array] oder [ArrayList] oder [DataTable] oder [DataSet] ist. Man sieht also, dass es sich hierbei um ein leistungsstarkes Werkzeug zur Darstellung von Daten in Tabellen handelt:

  • Die Formatierung erfolgt mit [WebMatrix] oder einem beliebigen anderen IDE zum Zeitpunkt der Gestaltung
  • Die Datenanbindung erfolgt im Code. Mit [WebMatrix] kann sie bereits bei der Erstellung erfolgen, wenn die Datenquelle ein SQL-Server oder eine ACCESS-Datenbank ist. In diesem Fall wird eine Komponente vom Typ [SqlDataSource] oder [AccessDataSource] auf das Blatt platziert. Diese Komponente kann zum Zeitpunkt der Entwicklung mit der physischen Datenquelle verknüpft werden, je nach Fall mit einer SQL-Server-Datenbank oder einer ACCESS-Datenbank. Wenn der Eigenschaft [DataSource] einer Komponente [DataGrid] ein Objekt [SqlDataSource] oder [AccessDataSource] zugewiesen wird, das mit einer physischen Quelle verknüpft ist, werden im Entwurfsmodus die Istdaten in der Komponente [DataGrid] an.

8.5. ViewState – Datenlistenkomponenten

Wir möchten hier den Mechanismus von [VIEWSATE] für Datenlistenkomponenten erläutern. Man kann zwischen zwei Methoden wählen, um den Zustand einer Datenlistenkomponente zwischen zwei Client-Anfragen aufrechtzuerhalten:

  • das Attribut [VIEWSTATE] auf „true“ setzen
  • das Attribut [VIEWSTATE] auf „false“ setzen und die Datenquelle in der Sitzung speichern, um die Komponente bei der nächsten Anfrage wieder mit dieser Quelle verknüpfen zu können.

Das folgende Beispiel veranschaulicht einige Aspekte des Mechanismus der Datencontainer [VIEWSTATE]. Bei der ersten Client-Anfrage zeigt die Anwendung die folgende Ansicht an:

Nr.
Name
Typ
Eigenschaften
Rolle
1
DataGrid1
DataGrid
EnableViewState=true
zeigt eine Datenquelle S an
2
DataGrid2
DataGrid
EnableViewState=true
zeigt dieselbe Quelle S wie [DataGrid1] an
3
Button1
Schaltfläche
EnableViewState=false
Schaltfläche [submit]

Die Komponente [DataGrid1] wird durch den Mechanismus von [VIEWSTATE] verwaltet. Es soll ermittelt werden, ob dieser Mechanismus, der die Anzeige von [DataGrid1] bei jeder Abfrage neu generiert, auch deren Datenquelle neu generiert. Zu diesem Zweck ist diese mit der Komponente [DataGrid2] verknüpft. Die Generierung dieser Komponente bei jeder Abfrage erfolgt über eine explizite Verknüpfung mit der Datenquelle von [DataGrid1]. Sie verfügt ebenfalls über das Attribut [EnableViewState] zu [vrai].

Der Darstellungscode [main.aspx] der Anwendung lautet wie folgt:


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

Der Controller [main.aspx.vb] lautet wie folgt:


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
        ' Bei der ersten Abfrage wird die Datenquelle definiert und mit dem ersten Datagrid verknüpft
        If Not IsPostBack Then
            'Datenquelle definieren
            With DataGrid1
                .DataSource = createDataSource()
                .DataBind()
            End With
        End If
        ' Bei jeder Abfrage wird das Datagrid2 mit der Datenquelle des ersten Datagrids verknüpft
        With Datagrid2
            .DataSource = DataGrid1.DataSource
            .DataBind()
        End With
    End Sub

    Private Function createDataSource() As DataTable
        ' Die Datenquelle wird initialisiert
        Dim thèmes As New DataTable
        ' Spalten
        With thèmes.Columns
            .Add("id", GetType(System.Int32))
            .Add("thème", GetType(System.String))
            .Add("description", GetType(System.String))
        End With
        ' Die Spalte „id“ ist der Primärschlüssel
        thèmes.Constraints.Add("cléprimaire", thèmes.Columns("id"), True)
        ' Zeilen
        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

Die Methode [createDataSource] erstellt eine Quelle S vom Typ [DataTable]. Wir werden nicht näher auf deren Code eingehen, da er nicht Gegenstand dieses Beispiels ist. Uns interessiert vielmehr die Vorgehensweise beim Aufbau der beiden Komponenten [DataGrid]:

  • Die Komponente [DataGrid1] wird bei der ersten Abfrage einmalig mit der Tabelle S verknüpft. Danach ist sie nicht mehr mit ihr verknüpft.
  • Die Komponente [DataGrid2] wird bei jeder neuen Abfrage mit der Quelle [DataGrid1.DataSource] verknüpft.

Bei der ersten Abfrage erhalten wir folgende Ansicht:

Image

Ziemlich logischerweise zeigen beide Komponenten die Datenquelle an, mit der sie verknüpft wurden. Wir verwenden die Schaltfläche [Envoyer], um eine Anfrage an den Server auszulösen. Die daraufhin angezeigte Ansicht sieht wie folgt aus:

Image

Wir stellen fest, dass die Komponente [DataGrid1] ihren Wert beibehalten hat, die Komponente [DataGrid2] jedoch nicht. Erläuterungen:

  • Noch bevor die Prozedur [Page_Load] gestartet wurde, haben die Objekte [DataGrid1] und [DataGrid2] aufgrund des Mechanismus von [viewstate] den Wert angenommen, den sie bei der vorherigen Abfrage hatten. Beide haben nämlich die Eigenschaft [EnableViewState] auf [vrai] gesetzt.
  • Die Prozedur [Page_Load] wird ausgeführt. Da es sich um eine Operation [PostBack] handelt, wird die Komponente [DataGrid1] durch [Page_Load] nicht verändert (siehe Code). Daher behält sie den durch [viewstate] abgerufenen Wert bei. Dies zeigt der obige Bildschirm.
  • Die Komponente [DataGrid2] ist ihrerseits über [DataBind] mit der Datenquelle [DataGrid1.DataSource] verbunden. Sie wird daher neu aufgebaut, und der Wert, den sie gerade über [viewstate] abgerufen hatte, geht verloren. Es wäre daher sinnvoll gewesen, wenn sie die Eigenschaft von [EnableViewState] auf [faux] gesetzt hätte, um eine unnötige Verwaltung ihres Zustands zu vermeiden. Der obige Bildschirm zeigt, dass [DataGrid2] mit einer leeren Quelle verknüpft wurde. Da es sich bei dieser Quelle um [DataGrid1.DataSource] handelt, lässt sich daraus ableiten, dass der Mechanismus von [viewstate] zwar die Anzeige der Komponente [DataGrid1] wiederherstellt, jedoch nicht deren Eigenschaften wie [DataSource].

Was lässt sich aus diesem Beispiel schließen? Man sollte vermeiden, die Eigenschaft [EnableViewState] eines Datencontainers auf [vrai] zu setzen, wenn dieser bei jeder Abfrage mit einer Datenquelle verknüpft werden soll (DataBind). Es gibt jedoch bestimmte Fälle, in denen selbst in dieser Konstellation die Eigenschaft [EnableViewState] des Containers auf [vrai] beibehalten werden muss, da sonst Ereignisse, die man verarbeiten möchte, nicht ausgelöst werden. Wir werden später ein Beispiel dafür sehen.

Häufig ändert sich die Datenquelle eines Datencontainers im Laufe der Abfragen. Daher muss der Container bei jeder Abfrage mit der Datenquelle verknüpft werden. Oft wird diese in die Sitzung aufgenommen, damit die Abfragen darauf zugreifen können. Unser zweites Beispiel veranschaulicht diesen Mechanismus. Die Anwendung stellt nur eine einzige Ansicht bereit:

Nr.
Name
Typ
Eigenschaften
Rolle
1
DataGrid1
DataGrid
EnableViewState=true
zeigt eine Datenquelle S an
2
DataGrid2
DataGrid
EnableViewState=false
zeigt dieselbe Quelle S an wie [DataGrid1]
3
Button1
Schaltfläche
EnableViewState=false
Schaltfläche [submit]
4
lblInfo1
lblInfo2
lblInfo3
Bezeichnung
EnableViewState=false
Informationstexte

Die Komponente [DataGrid1] wird nur bei der ersten Abfrage mit den Daten verknüpft. Dank des Mechanismus der Komponente [viewstate] behält sie ihren Wert über mehrere Abfragen hinweg bei. Die Komponente [DataGrid2] wird bei jeder Abfrage mit einer Datenquelle verknüpft, der bei jeder neuen Abfrage ein Element hinzugefügt wird. Daher muss die Komponente [DataGrid2] bei jeder Abfrage verknüpft werden (DataBind). Daher haben wir ihr Attribut [EnableViewState] auf [faux] gesetzt, wie zuvor empfohlen. Bei der zweiten Abfrage (über die Schaltfläche [Envoyer]) erhalten wir somit folgende Antwort:

Image

Die Komponente [DataGrid1] hat ihren ursprünglichen Wert beibehalten. Die Komponente [DataGrid2] enthält ein zusätzliches Element. Die drei Angaben [1,2,2] stellen die Abfragenummer dar. Es ist ersichtlich, dass eine der Angaben fehlerhaft ist. Wir werden versuchen, den Grund dafür zu ergründen.

Der Darstellungscode [main.aspx] der Anwendung lautet wie folgt:


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

Der Code des Controllers [main.aspx.vb] lautet wie folgt:


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
        ' Bei der ersten Abfrage wird die Datenquelle definiert und mit dem ersten Datagrid verknüpft
        If Not IsPostBack Then
            'Datenquelle definieren
            dtThèmes = createDataSource()
            With DataGrid1
                .DataSource = dtThèmes
                .DataBind()
            End With
            ' Informationen in der Sitzung speichern
            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
        ' Bei jeder Abfrage wird ein neues Thema hinzugefügt
        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)
        ': Verknüpft Datagrid2 mit der Datenquelle
        With Datagrid2
            .DataSource = dtThèmes
            .DataBind()
        End With
        ' Informationen zur Anzahl der Abfragen
        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
        ' Einige Informationen werden in der Sitzung gespeichert
        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

Wir haben den Code der Methode [createDataSource] nicht wiedergegeben. Er entspricht dem der vorherigen Anwendung, mit dem einzigen Unterschied, dass nur drei Zeilen in die Quelle eingefügt werden. Betrachten wir zunächst die Verwaltung der Datenquelle und der beiden Container:


    Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        ' Bei der ersten Abfrage wird die Datenquelle definiert und mit dem ersten Datagrid verknüpft
        If Not IsPostBack Then
            'Datenquelle definieren
            dtThèmes = createDataSource()
            With DataGrid1
                .DataSource = dtThèmes
                .DataBind()
            End With
            ' Informationen in der Sitzung speichern
            Session("source") = dtThèmes
...
        End If
        ' Bei jeder Abfrage wird ein neues Thema hinzugefügt
        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)
        ': Verknüpft Datagrid2 mit der Datenquelle
        With Datagrid2
            .DataSource = dtThèmes
            .DataBind()
        End With
...
    End Sub

Die Komponente [DataGrid1] wird nur bei der ersten Abfrage mit der Datenquelle S verknüpft (nicht IsPostBack). Diese wird dann in die Sitzung aufgenommen. Später erfolgt dies nicht mehr. Die in die Sitzung aufgenommene Datenquelle S wird bei jeder Abfrage abgerufen und um eine neue Zeile ergänzt. Die Komponente [DataGrid2] wird bei jeder Abfrage explizit mit der Datenquelle S verknüpft. Deshalb erhöht sich ihr Inhalt bei jeder Abfrage um eine Zeile. Es ist zu beachten, dass nach einer Änderung des Inhalts der Datenquelle S diese nicht explizit durch einen Vorgang wieder in die Sitzung aufgenommen wird:

            Session("source") = S

Warum? Wenn eine Abfrage startet, enthält die Sitzung ein Session-Objekt („source“) vom Typ [DataTable], das die Datenquelle in dem Zustand darstellt, in dem sie sich bei der letzten Abfrage befand. Bezeichnen wir das Session-Objekt („source“) mit S. Wenn wir schreiben:


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

sind [dtThèmes] und [S] zwei Referenzen auf dasselbe Objekt [DataTable]. Wenn also der Code von [Page_Load] ein Element zur Tabelle hinzufügt, auf die [dtThèmes] verweist, fügt er es gleichzeitig auch zur Tabelle hinzu, auf die [S] verweist. Am Ende der Ausführung der Seite werden alle in der Sitzung vorhandenen Objekte gespeichert, also das Objekt „Session(„source“)“, c.a.d. S, c.a.d und [dtThèmes]. Es wird also tatsächlich der neue Inhalt der Datenquelle gespeichert. Es war nicht notwendig, Folgendes zu schreiben:

            Session("source") = dtThèmes

um diese Sicherung durchzuführen, da Session("source") bereits den Wert [dtThèmes] hat. Dies trifft nicht mehr zu, wenn es sich bei den in die Sitzung geladenen Daten nicht um Objekte handelt, wie beispielsweise bei den Strukturen [Integer, Float, ...]. Dies zeigt die Verwaltung der Anfragedzähler:


    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
        ' Bei der ersten Abfrage wird die Datenquelle definiert und mit dem ersten Datagrid verknüpft
....
            ' Informationen in der Sitzung speichern
            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
        ' Bei jeder Abfrage wird ein neues Thema hinzugefügt
....
        ' Informationen zur Anzahl der Abfragen
        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
        ' Einige Informationen werden in der Sitzung gespeichert
        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

Die Anforderungszähler werden in drei Elementen gespeichert:

  • numRequête1 und numRequête2 vom Typ [Integer] – [Integer] ist keine Klasse, sondern eine Struktur
  • numRequête3 vom Typ [entier] – [entier] ist eine speziell für diesen Zweck definierte Klasse

Wenn man schreibt:


        numRequête1 = CType(Session("numRequête1"), Integer)
..
        numRequête2 = CType(Session("numRequête2"), Integer)
..
        numRequête3 = CType(Session("numRequête3"), entier)
..
  • Die Struktur [Session("numRequête1")] wird in [numRequête1] kopiert. Wenn also das Element [numRequête1] geändert wird, wird das Element [Session("numRequête1")] hingegen nicht geändert
  • Das Gleiche gilt für [Session("numRequête2")] und [numRequête2]
  • Die Elemente [Session("numRequête3")] und [numRequête3] sind beide Verweise auf dasselbe Objekt vom Typ [entier]. Das referenzierte Objekt kann beliebig über den einen oder den anderen Verweis geändert werden.

Daraus lässt sich ableiten, dass es unnötig ist, Folgendes zu schreiben:

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

um den neuen Wert von [numRequête3] in der Sitzung zu speichern. Stattdessen müsste man schreiben:

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

um die neuen Werte der Strukturen [numRequête1] und [numRequête2] zu speichern. Wir tun dies nur für [numRequête2], was erklärt, warum auf dem nach der zweiten Abfrage erstellten Screenshot der Zähler [numRequête1] falsch ist.

Man sollte also beachten, dass ein Datensatz, sobald er einmal in die Sitzung geladen wurde, nicht wiederholt neu geladen werden muss, wenn er durch ein Objekt repräsentiert wird. In allen anderen Fällen muss dies jedoch geschehen, wenn er geändert wurde.

8.6. Anzeige einer Datenliste mithilfe eines paginierten und sortierten DataGrid

Die Komponente [DataGrid] ermöglicht die Anzeige des Inhalts eines [DataSet]. Bisher haben wir unsere [DataSet] immer „von Hand“ erstellt. Dieses Mal verwenden wir ein [DataSet] aus einer Datenbank. Wir erstellen die folgende MVC-Anwendung:

Die drei Ansichten werden in Form von Containern in den Präsentationscode des Controllers [main.aspx] eingebunden. Daher verfügt diese Anwendung über eine einzige Seite: [main.aspx].

8.6.1. Die Fachklassen

Die Klasse [produits] ermöglicht den Zugriff auf die folgende Datenbank ACCESS:

Image

Der Code der Klasse [produits] lautet wie folgt:


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)
            ' Die Verbindungszeichenfolge wird gespeichert
            Me.chaineConnexionOLEDB = chaineConnexionOLEDB
        End Sub

        Public Function getDataSet(ByVal commande As String) As DataSet
            ' Es wird ein Objekt DataAdapter erstellt, um die Daten aus der Quelle OLEDB zu lesen
            Dim adaptateur As New OleDbDataAdapter(commande, chaineConnexionOLEDB)
            ' Es wird ein Speicherabbild des Ergebnisses der SELECT-Anweisung erstellt
            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
            ' Das Ergebnis wird ausgegeben
            Return contenu
        End Function
    End Class
End Namespace

Die Datenbank ACCESS wird über den Treiber OLEDB verwaltet. Dem Konstruktor der Klasse [produits] werden die Verbindungszeichenfolge, die Kennung sowie der Treiber OLEDB und die zu verwaltende Datenbank übergeben. Die Klasse [produits] verfügt über eine Methode [getDataSet], die ein [DataSet] zurückgibt, das durch die Ausführung voneiner Abfrage SQL [select], deren Text als Parameter übergeben wird. Im Verlauf der Methode finden mehrere Vorgänge statt: Herstellen der Verbindung zur Datenbank, Ausführen der Abfrage [select], Schließen der Verbindung. All dies kann eine Ausnahme auslösen, die hier abgefangen wird. Ein Testprogramm könnte wie folgt aussehen:

Option Explicit On 
Option Strict On

' Namensräume
Imports System
Imports System.Data
Imports Microsoft.VisualBasic

Namespace st.istia.univangers.fr

     ' Test-Seite
    Module testproduits
        Sub Main(ByVal arguments() As String)
             ' Zeigt den Inhalt einer Produkttabelle an
             ' Die Tabelle befindet sich in einer Datenbank ACCESS, deren Seite den Dateinamen erhält
            Const syntaxe1 As String = "pg bdACCESS"

             ' Überprüfung der Programmparameter
            If arguments.Length <> 1 Then
                 ' Fehlermeldung
                Console.Error.WriteLine(syntaxe1)
                 ' Ende
                Environment.Exit(1)
            End If

             ' Die Verbindungszeichenfolge wird vorbereitet
            Dim chaineConnexion As String = "Provider=Microsoft.Jet.OLEDB.4.0; Ole DB Services=-4; Data Source=" + arguments(0)

             ' Erstellung eines Produkt-Objekts
            Dim objProduits As produits = New produits(chaineConnexion)

             ' Die Produkttabelle wird in ein Dataset geladen
            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

             ' Anzeige des Inhalts
            Dim lignes As DataRowCollection = contenu.Tables(0).Rows
            For i As Integer = 0 To lignes.Count - 1
                 ' Zeile i der Tabelle
                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

Die Zusammenstellung der verschiedenen Elemente dieser Anwendung erfolgt wie folgt:

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. Die Ansichten

Nachdem wir nun die Klasse für den Datenzugriff haben, schreiben wir die Controller und Views dieser Webanwendung. Schauen wir uns zunächst einmal an, wie sie funktioniert. Die erste View sieht wie folgt aus:

Nr.
Name
Typ
Eigenschaften
Rolle
1
txtSelect
TextBox
EnableViewState=true
Eingabefeld für die SELECT-Abfrage
2
RequiredFieldValidator1
RequiredFieldValidator
EnableViewState=false
Prüft, ob 1 vorhanden ist
3
txtPages
TextBox
EnableViewState=true
Eingabefeld – gibt die Anzahl der Datenzeilen an, die pro Ergebnisseite angezeigt werden sollen
4
RequiredFieldValidator2
RequiredFieldValidator
EnableViewState=false
prüft, ob 3 vorhanden ist
5
RangeValidator1
RangeValidator
EnableViewState=false
überprüft, ob (3) im Intervall [1,30] liegt
6
btnExécuter
Schaltfläche
EnableViewState=false
Schaltfläche [submit]

Wir nennen diese Ansicht „[formulaire]“. Sie ermöglicht es dem Benutzer, eine SELECT-Abfrage (SQL) in der Datenbank ([produits.mdb]) auszuführen. Die Ausführung der Abfrage erzeugt eine neue Ansicht:

Nr.
Name
Typ
Eigenschaften
Rolle
1
lblSelect
Bezeichnung
EnableViewState=false
Informationsfeld
2
rdCroissant
rdDécroissant
RadioButton
EnableViewState=false
GroupName=rdTri
ermöglicht die Auswahl einer Sortierreihenfolge
3
DataGrid1
DataGrid
EnableViewState=true
AllowPaging=true
AllowSorting=true
Tabelle zur Anzeige der Ergebnisse der SELECT-Abfrage
4
lnkRésultats
LinkButton
EnableViewState=false
Link-Schaltfläche [submit]

Wir nennen diese Ansicht „[résultats]“. Sie enthält das Element „[DataGrid]“, das das Ergebnis des Befehls „SQL select“ anzeigt. Der Benutzer kann sich bei seiner Abfrage irren. Bestimmte Fehler werden ihm dank der Validierungsprüfungen in der Ansicht [erreurs] angezeigt.

Image

Weitere Fehler werden ihm in der Ansicht [erreurs] angezeigt:

Image

Die Ansicht [erreurs] wird angezeigt:

Nr.
Name
Typ
Eigenschaften
Rolle
1
erreursHTML
Variable
 
Code HTML erforderlich für die Anzeige von Fehlern
3
lnkForm2
LinkButton
EnableViewState=false
Schaltflächen-Link [submit]

Die drei Ansichten der Anwendung sind drei verschiedene Container (Panels) innerhalb derselben Seite [main.aspx]. Der Darstellungscode lautet wie folgt:


<%@ 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. Konfiguration von DataGrid

Werfen wir einen Blick auf die Paginierung der Komponente [DataGrid], eine Option, auf die wir hier zum ersten Mal stoßen. Im obigen Code wird diese Paginierung durch die folgenden Attribute gesteuert:


                    <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"
Paginierung zulassen
PageSize="4"
vier Datenzeilen pro Seite
NextPageText="Suivant"
Der Linktext, um zur nächsten Seite der Datenquelle zu gelangen
PrevPageText="Précédent"
Der Linktext, um zur vorherigen Seite der Datenquelle zu gelangen

Diese Informationen können direkt in die Attribute des Tags <asp:datagrid> eingegeben werden. Man kann auch [WebMatrix] verwenden. Im Eigenschaftenfenster von [DataGrid] folgt man dem Link [Générateur de propriétés]:

Image

Es erscheint der folgende Assistent:

Image

Man wählt die Option [Pagination]:

Image

Oben sehen wir die Werte der Paginierungsattribute von [DataGrid] aus dem Präsentationscode.

Außerdem ermöglichen wir die Sortierung der Daten nach einer der Spalten von [DataGrid]. Dafür gibt es verschiedene Möglichkeiten. Eine davon besteht darin, die Eigenschaft [AllowSorting=true] im Eigenschaftenfenster von [DataGrid] zu definieren. Man kann auch den Eigenschaftsgenerator verwenden. Unabhängig von der verwendeten Methode führt dies dazu, dass das Attribut [AllowSorting=true] im Tag <asp:DataGrid> der Komponente vorhanden ist:


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

8.6.4. Die Controller

Der Controller [global.asax, global.asax.vb] lautet wie folgt:

[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)
        ' Ein Produkt-Objekt wird angelegt
        Dim objProduits As produits
        Try
            objProduits = New produits(ConfigurationSettings.AppSettings("OLEDBStringConnection"))
            ' Das Objekt wird in die Anwendung eingefügt
            Application("objProduits") = objProduits
            ' kein Fehler
            Application("erreur") = False
        Catch ex As Exception
            'Es ist ein Fehler aufgetreten, der in der Anwendung vermerkt wird
            Application("erreur") = True
            Application("message") = ex.Message
        End Try
    End Sub
End Class

Beim Start der Anwendung (Application_Start) erstellen wir ein Objekt [produits] und fügen es in die Anwendung ein, damit es für alle Anfragen aller Clients verfügbar ist. Sollte bei dieser Erstellung eine Ausnahme auftreten, wird diese in der Anwendung protokolliert. Die Prozedur [Application_Start] wird nur einmal ausgeführt. Danach greift der Controller [global.asax] nicht mehr ein. Die Arbeit übernimmt dann der Controller [main.aspx.vb]:


Imports System.Collections
Imports Microsoft.VisualBasic
Imports System.Data
Imports st.istia.univangers.fr
Imports System
Imports System.Xml

Public Class main
    Inherits System.Web.UI.Page

    ' Seitenkomponenten
    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
    ' Seitendaten
    Protected erreursHTML As String

    Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        ' Es wird geprüft, ob in der Anwendung ein Fehler vorliegt
        If CType(Application("erreur"), Boolean) Then
            ' Die Anwendung wurde nicht korrekt initialisiert
            Dim erreurs As New ArrayList
            erreurs.Add("Application momentanément indisponible (" + CType(Application("message"), String) + ")")
            afficheErreurs(erreurs, False)
            Exit Sub
        End If
        'Erste Abfrage
        If Not IsPostBack Then
            ' Das leere Formular wird angezeigt
            afficheFormulaire()
        End If
    End Sub

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

    Private Sub afficheFormulaire()
        ' Die Ansicht [formulaire] wird angezeigt
        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)
        ' Die Steuerelemente werden initialisiert
        lblSelect.Text = sqlTexte
        With DataGrid1
            .DataSource = données
            .PageSize = CType(txtPages.Text, Integer)
            .CurrentPageIndex = 0
            .DataBind()
        End With
        ' Die Ansicht [résultats] wird angezeigt
        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
        ' Seite gültig?
        If Not Page.IsValid Then
            afficheFormulaire()
            Exit Sub
        End If

        ' Ausführung der Abfrage SELECT auf dem Client
        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 in Ordnung – die Ergebnisse werden angezeigt
        afficheRésultats(txtSelect.Text.Trim, données)
        ' Die Daten werden in die Sitzung geschrieben
        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
        ' Ansichtsausgabe
        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
        ' Seitenwechsel
        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
        ' Die Dataview wird sortiert
        Dim données As DataView = CType(Session("données"), DataView)
        données.Sort = e.SortExpression + " " + CType(IIf(rdCroissant.Checked, "asc", "desc"), String)
        ' Anzeige
        With DataGrid1
            .CurrentPageIndex = 0
            .DataSource = données
            .DataBind()
        End With
    End Sub
End Class

Beim Laden der Seite [Page_Load] prüfen wir zunächst, ob die Anwendung korrekt initialisiert werden konnte. Ist dies nicht der Fall, wird die Ansicht [erreurs] ohne Rückverweis zum Formular angezeigt, da dieser Link dann überflüssig ist. Tatsächlich kann nur die Ansicht [erreurs] angezeigt werden, wenn die Anwendung nicht korrekt initialisiert werden konnte. Andernfalls wird die Ansicht [formulaire] angezeigt, wenn es sich um die erste Anfrage des Kunden handelt. Im Übrigen überlassen wir es dem Leser, den Code zu verstehen. Wir gehen lediglich auf drei Prozeduren näher ein: die Prozedur [btnExécuter_Click], die ausgeführt wird, wenn der Benutzer die Ausführung der in der Ansicht [formulaire] eingegebenen Abfrage SQL angefordert hat, die Prozedur [DataGrid1_PageIndexChanged], die ausgeführt wird, wenn derBenutzer die Links [Suivant] und [Précédent] aus [DataGrid] verwendet, sowie die Prozedur [DataGrid1_SortCommand], die ausgeführt wird, wenn der Benutzer auf eine Spaltenüberschrift klickt, um die Daten in derReihenfolge dieser Spalte zu sortieren. Die Sortierrichtung – aufsteigend oder absteigend – wird durch die beiden Sortier-Optionsfelder festgelegt.

In der Prozedur [btnExécuter_Click] wird daher zunächst geprüft, ob die Seite gültig ist oder nicht. Wenn die Prozedur [btnExécuter_Click] ausgeführt wird, sind die Prüfungen im Zusammenhang mit den verschiedenen Validierungskontrollen der Seite bereits erfolgt. Für jede Validierungskontrolle wurden zwei Attribute gesetzt:

IsValid
auf „wahr“, wenn die überprüften Daten gültig sind, andernfalls auf „falsch“
ErrorMessage
die Fehlermeldung, falls sich die überprüften Daten als ungültig erwiesen haben

Für die Seite selbst wurde das Attribut [IsValid] gesetzt. Es ist nur dann auf „wahr“ gesetzt, wenn bei allen Validierungsprüfungen das Attribut [IsValid] auf „wahr“ gesetzt ist. Ist dies nicht der Fall, muss die Ansicht [formulaire] angezeigt werden. Diese enthält die Validierungsprüfungen, die ihr Attribut [errorMessage] anzeigen. Ist die Seite gültig, wird das von [Application_Start] erstellte Objekt vom Typ [produits] verwendet, um das [DataSet] zu erhalten, das der Ausführung der SELECT-Abfrage SQL entspricht. Dieses wird in ein Objekt vom Typ [DataView] umgewandelt:


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

Man hätte auch einfach mit dem Objekt [DataSet] arbeiten und schreiben können:


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

Ein Objekt vom Typ [DataSet] besteht im Grunde aus einer Reihe von Tabellen, die durch Beziehungen miteinander verknüpft sind. In unserer speziellen Anwendung enthält das aus der Klasse [produits] abgeleitete [DataSet] nur eine Tabelle, nämlich die, die aus dem Ergebnis der Anweisung [select] stammt. Eine Tabelle kann sortiert werden, während dies bei einem [DataSet] nicht möglich ist; wir sind jedoch daran interessiert, die erhaltenen Daten zu sortieren. Um mit der Ergebnistabelle von [select] zu arbeiten, hätten wir schreiben können:


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

Das Objekt [DataTable] stellt zwar eine Datenbanktabelle dar, verfügt jedoch über keine Sortiermethode. Dazu ist eine Ansicht der Tabelle erforderlich. Eine Ansicht ist ein Objekt vom Typ [DataView]. Mithilfe von Filtern lassen sich verschiedene Ansichten derselben Tabelle erstellen. Eine Tabelle verfügt über eine Standardansicht, bei der kein Filter definiert ist. Sie repräsentiert somit die gesamte Tabelle. Diese Standardansicht wird über [DataTable.DefaultView] abgerufen. Eine Ansicht kann mithilfe ihrer Eigenschaft [sort] sortiert werden, auf die wir später noch zurückkommen werden.

Wenn das Abrufen von [DataSet] aus der Klasse [produits] erfolgreich verläuft, wird die Ansicht [résultats] angezeigt, andernfalls die Ansicht [erreurs]. Die Anzeige der Ansicht [résultats] erfolgt über die Prozedur [afficheRésultats], an die zwei Parameter übergeben werden:

  • den Text, der in das Label [lblSelect] eingefügt werden soll
  • das [DataView], das mit [DataGrid1] verknüpft werden soll

Dieses Beispiel verdeutlicht die große Flexibilität der Komponente [DataGrid]. Sie erkennt die Struktur des [DataView], mit dem sie verknüpft wird, und passt sich dieser an. Schließlich speichert die Prozedur [btnExécuter_Click] das soeben erhaltene [DataView] in der Sitzung des Benutzers, um darauf zurückgreifen zu können, wenn dieser weitere Seiten desselben [DataView] anfordert.

Die Prozedur [DataGrid1_PageIndexChanged] wird ausgeführt, wenn der Benutzer die Links [Suivant] und [Précédent] des [DataGrid] verwendet. Sie erhält zwei Parameter:


    Private Sub DataGrid1_PageIndexChanged(ByVal source As Object, ByVal e As System.Web.UI.WebControls.) Handles DataGrid1.PageIndexChanged
source
das Ursprungsobjekt des Ereignisses – in diesem Fall einer der Links [Suivant] oder [Précédent]
e
Informationen zum Ereignis. Das Attribut e.NewPageIndex ist die Seiten-Nr., die angezeigt werden soll, um die Anfrage des Kunden zu beantworten

Der vollständige Code des Ereignis-Handlers lautet wie folgt:


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

Die Komponente [DataGrid] verfügt über ein Attribut [CurrentPageIndex], das die Nummer der Seite angibt, die sie anzeigt oder anzeigen wird. Diesem Attribut wird der Wert [NewPageIndex] des Parameters [e] zugewiesen. Das [DataGrid] wird anschließend über die Prozedur [btnExécuter_Click] mit dem [DataView] verknüpft, das in der Sitzung gespeichert worden war.

Man könnte sich fragen, ob das [DataGrid] das Attribut [EnableViewState=true] benötigt, da sein Inhalt bei jeder neuen Ausführung der Seite vom Code berechnet wird. Man könnte meinen, dass dies nicht der Fall ist. Wenn jedoch das [DataGrid] das Attribut [EnableViewState=false] besitzt, stellt man fest, dass das Ereignis [DataGrid1.PageIndexChanged] niemals ausgelöst wird. Aus diesem Grund wurde [EnableViewState=true] beibehalten. Wir wissen, dass dies dazu führt, dass der Inhalt von [DataGrid] in das versteckte Feld [__VIEWSTATE] der Seite eingefügt wird. Dies kann zu einer erheblichen Überlastung der Seite führen, wenn der Inhalt von [DataGrid] umfangreich ist. Sollte dies störend sein, kann man die Paginierung selbst verwalten, ohne die automatische Paginierung von [DataGrid] zu verwenden.

Die Prozedur [DataGrid1_SortCommand] wird ausgeführt, wenn der Benutzer auf den Titel einer der von [DataGrid] angezeigten Spalten klickt, um die Sortierung der Daten nach dieser Spalte anzufordern. Sie erhält zwei Parameter:


    Private Sub DataGrid1_SortCommand(ByVal source As Object, ByVal e As System.Web.UI.WebControls.DataGridSortCommandEventArgs) Handles DataGrid1.SortCommand
source
das Ursprungsobjekt des Ereignisses – in diesem Fall einer der Links [Suivant] oder [Précédent]
e
Informationen zum Ereignis. Das Attribut [e.SortExpression] ist der Name der Spalte, auf die zum Sortieren geklickt wurde

Der vollständige Code des Ereignishandlers lautet wie folgt:


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

Die Komponente [DataView], die von der Komponente [DataGrid] in der aktuellen Sitzung angezeigt wird, wird abgerufen. Sie wurde dort von der Prozedur [btnExécuter_Click] abgelegt. Die Komponente [DataView] verfügt über eine Eigenschaft [Sort], der der Sortierausdruck zugewiesen wird. Diese folgt der Syntax [select ... order by expr1, expr2, ...], wobei auf jedes [expri] das Schlüsselwort [asc] für eine aufsteigende Sortierung oder [desc] für eine absteigende Sortierung folgen kann. Der hier verwendete Ausdruck [order by] lautet [order by colonne asc/desc]. Die Eigenschaft [e.SortExpression] gibt uns den Namen der Spalte von [DataGrid] an, auf die zum Sortieren geklickt wurde. Die Zeichenfolge [asc/desc] wird anhand der Werte der Optionsfelder der Gruppe [rdTri] festgelegt. Sobald der Sortierausdruck von [DataView] festgelegt ist, wird [DataGrid] diesem zugeordnet. Das [DataGrid] wird auf seiner ersten Seite positioniert.

8.7. Komponente DataList und Datenverknüpfung

Wir wenden uns nun der Komponente [DataList] zu. Sie bietet mehr Gestaltungsmöglichkeiten als die [DataGrid], ist jedoch weniger flexibel. So kann sie sich nicht automatisch an die Datenquelle anpassen, mit der sie verknüpft ist. Diese Anpassung muss, falls gewünscht, per Code vorgenommen werden. Ist die Struktur der Datenquelle im Voraus bekannt, bietet diese Komponente Formatierungsmöglichkeiten, die sie gegenüber der Komponente [DataGrid] vorteilhaft machen können.

8.7.1. Anwendung

Um die Verwendung von [DataList] zu veranschaulichen, erstellen wir eine MVC-Anwendung analog zur vorherigen:

Die drei Ansichten werden in Form von Containern in den Präsentationscode des Controllers [main.aspx] eingebunden. Daher verfügt diese Anwendung über eine einzige Seite: [main.aspx].

8.7.2. Die Fachklassen

Die Klasse [produits] ist dieselbe wie zuvor.

8.7.3. Die Ansichten

Wenn der Benutzer seine erste Anfrage an die Anwendung stellt, erhält er die folgende Ansicht [résultats1]:

Nr.
Name
Typ
Eigenschaften
Rolle
1
RadioButton1
RadioButton2
RadioButton
EnableViewState=false
ermöglicht die Auswahl eines Stils für [DataList] aus zwei Optionen
2
btnChanger
Button
EnableViewState=false
Schaltfläche [submit]
3
DataList1
DataList
EnableViewState=true
Anzeigefeld der Datenliste

Wählt der Benutzer den Stil Nr. 2 aus, erhält er die folgende Ansicht [résultats2]:

Nr.
Name
Typ
Eigenschaften
Rolle
1
DataList2
DataList
EnableViewState=true
Anzeigefeld der Datenliste

Die Ansicht [erreurs] meldet ein Problem beim Zugriff auf die Datenquelle:

Nr.
Name
Typ
Eigenschaften
Rolle
1
erreursHTML
Variable
 
Code HTML, der für die Anzeige von Fehlern erforderlich ist

Die drei Ansichten der Anwendung sind drei verschiedene Container (Panels) innerhalb derselben Seite [main.aspx]. Der Darstellungscode lautet wie folgt:


<%@ Page src="main.aspx.vb" inherits="main" autoeventwireup="false" Language="vb" %>
<HTML>
    <HEAD>
    </HEAD>
    <body>
        <P>Liaison de données avec un DataList</P>
        <HR width="100%" SIZE="1">
        <form runat="server" ID="Form1">
            <asp:Panel Runat="server" ID="bandeau">
                <P>Choisissez votre style :
                    <asp:RadioButton id="RadioButton1" runat="server" EnableViewState="False" Text="1" GroupName="rdstyle"
                        Checked="True"></asp:RadioButton>
                    <asp:RadioButton id="RadioButton2" runat="server" EnableViewState="False" Text="2" GroupName="rdstyle"></asp:RadioButton>
                    <asp:Button id="btnChanger" runat="server" EnableViewState="False" Text="Changer"></asp:Button></P>
                <HR width="100%" SIZE="1">
            </asp:Panel>
            <asp:Panel id="vueRésultats1" runat="server">
                <P>
                    <asp:DataList id="DataList1" runat="server" BorderColor="Tan" BorderWidth="1px" BackColor="LightGoldenrodYellow"
                        CellPadding="2" RepeatDirection="Horizontal" RepeatColumns="4" ForeColor="Black">
                        <SelectedItemStyle ForeColor="GhostWhite" BackColor="DarkSlateBlue"></SelectedItemStyle>
                        <HeaderTemplate>
                            Contenu de la table [liste] de la base [produits]
                        </HeaderTemplate>
                        <AlternatingItemStyle BackColor="PaleGoldenrod"></AlternatingItemStyle>
                        <ItemTemplate>
                            nom :
                            <%# Container.DataItem("Name") %>
                            <br>
                            prix :
                            <%# databinder.eval(Container.DataItem,"Preis","{0:C}") %>
                            <br>
                        </ItemTemplate>
                        <FooterStyle BackColor="Tan"></FooterStyle>
                        <HeaderStyle Font-Bold="True" BackColor="Tan"></HeaderStyle>
                    </asp:DataList></P>
            </asp:Panel>
            <asp:Panel id="vueRésultats2" runat="server">
                <P>
                    <asp:DataList id="DataList2" runat="server">
                        <HeaderTemplate>
                            Contenu de la table [liste] de la base [produits]
                            <HR width="100%" SIZE="1">
                        </HeaderTemplate>
                        <AlternatingItemStyle BackColor="Teal"></AlternatingItemStyle>
                        <SeparatorStyle BackColor="LightSkyBlue"></SeparatorStyle>
                        <ItemStyle BackColor="#C0C000"></ItemStyle>
                        <ItemTemplate>
                            nom :
                            <%# Container.DataItem("Name") %>
                            , prix :
                            <%# databinder.eval(Container.DataItem,"Preis","{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. Konfiguration der Komponenten [DataList]

Werfen wir einen Blick auf die verschiedenen Attribute einer Komponente [DataList]. Es gibt sehr viele davon, und wir stellen hier nur einen kleinen Teil davon vor. Innerhalb einer [DataList] können bis zu sieben Anzeigemodelle definiert werden:

HeaderTemplate
Vorlage für die Kopfzeile von [DataList]
ItemTemplate
Vorlage für die Zeilen, in denen die Elemente der zugehörigen Datenliste angezeigt werden. Nur diese Vorlage ist obligatorisch.
AlternatingItemTemplate
Um die nacheinander angezeigten Elemente optisch voneinander zu unterscheiden, können zwei Vorlagen verwendet werden: ItemTemplate für das Element n, AlternatingItemTemplate für das Element n+1
SelectedItemTemplate
Vorlage für das in [DataList] ausgewählte Element
SeparatorTemplate
Vorlage für das Trennzeichen zwischen zwei Elementen in [DataList]
EditItemTemplate
Ein [DataList] ermöglicht die Änderung der angezeigten Werte. [EditItemTemplate] ist die Vorlage für ein Element des [DataList], für das der „Bearbeitungsmodus“ aktiv ist
FooterTemplate
Vorlage für die Fußzeile von [DataList]

Die Komponente [DataList1] wurde mit [WebMatrix] erstellt. In ihrem Eigenschaftenfenster wurde der Link [Mise en forme automatique] ausgewählt:

1234567

Im obigen Beispiel generiert das Schema [Couleur 5] ein [DataList] mit Stilen für die folgenden Vorlagen: HeaderTemplate (1), ItemTemplate (2, 6), AlternatingTemplate (3, 5), SelectedItemTemplate (4), FooterTemplate (7). Der generierte Code lautet wie folgt:


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

Es ist kein Modell definiert. Das müssen wir selbst tun. Wir definieren die folgenden Modelle:

HeaderTemplate

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

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

Zur Erinnerung: Das Modell [ItemTemplate] dient zur Darstellung der Elemente der Datenquelle, die mit [DataList] verknüpft ist. Diese Datenquelle besteht aus einer Reihe von Datenzeilen, von denen jede einen oder mehrere Werte enthält. Die aktuelle Zeile der Datenquelle wird durch das Objekt [Container.DataItem] dargestellt. Eine solche Zeile besteht aus Spalten. [Container.DataItem("col1")] ist der Wert der Spalte „col1“ der aktuellen Zeile. Um diesen Wert in den Darstellungscode einzufügen, schreibt man <%# Container.DataItem("col") %>. Manchmal möchte man ein Element der aktuellen Zeile in einem speziellen Format darstellen. Hier soll die Spalte „Preis“ der aktuellen Zeile in Euro angezeigt werden. Dazu verwendet man die Funktion [DataBinder.Eval], die drei Parameter akzeptiert:

  • die aktuelle Zeile [Container.DataItem]
  • den Namen der zu formatierenden Spalte
  • die Formatierungszeichenfolge in der Form {0:format}, wobei [format] eines der von der Methode [string.format] akzeptierten Formate ist.

So sorgt der Code <%# DataBinder.Eval(Container.DataItem,"Preis",{0:C}) %> dafür, dass die Spalte [prix] der aktuellen Zeile in Währungsform (Format C = Currency) angezeigt wird.

Wir erhalten also ein [DataList], das wie folgt aussieht:

Image

Oben wurden die Daten mit vier Datensätzen pro Zeile angeordnet. Dies wird mit den folgenden Attributen von [DataList] erreicht:

RepeatDirection
Horizontal
RepeatColumns
gewünschte Spaltenanzahl

Letztendlich entspricht der Code von [DataList1] dem, der im etwas weiter oben gezeigten Darstellungscode vorgestellt wurde. Wir überlassen es dem Leser, den Darstellungscode von [DataList2] zu untersuchen. Wie bei der Komponente [DataGrid] lassen sich die meisten Eigenschaften von [DataList] mithilfe eines Assistenten von [WebMatrix] festlegen. Dazu wird der Link [Générateur de propriétés] im Eigenschaftenfenster von [DataList] verwendet:

8.7.5. Die Steuerelemente

Der Controller [global.asax, global.asax.vb] lautet wie folgt:

[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)
        ' Es wird ein Produktobjekt erstellt
        Try
            Dim données As DataSet = New produits(ConfigurationSettings.AppSettings("OLEDBStringConnection")).getDataSet("select * from LISTE")
            ' Das Objekt wird in die Anwendung eingefügt
            Application("données") = données
            ' kein Fehler
            Application("erreur") = False
        Catch ex As Exception
            'Es ist ein Fehler aufgetreten, der in der Anwendung vermerkt wird
            Application("erreur") = True
            Application("message") = ex.Message
        End Try
    End Sub
End Class

Beim Start der Anwendung (Application_Start) erstellen wir aus der Geschäftsklasse [produits] ein Objekt vom Typ [dataset] und fügen es in die Anwendung ein, damit es für alle Anfragen aller Clients verfügbar ist. Tritt bei dieser Erstellung eine Ausnahme auf, wird diese in der Anwendung protokolliert. Die Prozedur [Application_Start] wird nur einmal ausgeführt. Danach greift der Controller [global.asax] nicht mehr ein. Die Arbeit übernimmt dann der Controller [main.aspx.vb]:


Imports System.Collections
Imports Microsoft.VisualBasic
Imports System.Data
Imports st.istia.univangers.fr
Imports System
Imports System.Xml

Public Class main
    Inherits System.Web.UI.Page

    ' Seitenkomponenten
    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
    ' Seitendaten
    Protected erreursHTML As String

    Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        ' Es wird geprüft, ob in der Anwendung ein Fehler vorliegt
        If CType(Application("erreur"), Boolean) Then
            ' Die Anwendung wurde nicht korrekt initialisiert
            Dim erreurs As New ArrayList
            erreurs.Add("Application momentanément indisponible (" + CType(Application("message"), String) + ")")
            afficheErreurs(erreurs, False)
            Exit Sub
        End If
        'Erste Abfrage
        If Not IsPostBack Then
            ' Die Steuerelemente werden initialisiert
            With DataList1
                .DataSource = CType(Application("données"), DataSet)
                .DataBind()
            End With
            With DataList2
                .DataSource = CType(Application("données"), DataSet)
                .DataBind()
            End With
            ' Das leere Formular wird angezeigt
            afficheRésultats(True, False)
        End If
    End Sub

    Private Sub afficheErreurs(ByVal erreurs As ArrayList, ByVal afficheLien As Boolean)
        ' Die Fehleransicht wird angezeigt
        erreursHTML = ""
        For i As Integer = 0 To erreurs.Count - 1
            erreursHTML += "<li>" + erreurs(i).ToString + "</li>" + ControlChars.CrLf
        Next
        ' Die Ansicht [erreurs] wird angezeigt
        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)
        ' Die Ansicht wird angezeigt [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
        ' Der Stil wird geändert
        afficheRésultats(RadioButton1.Checked, RadioButton2.Checked)
    End Sub
End Class

8.8. Repeater-Komponente und Datenverbindung

Die Komponente [Repeater] ermöglicht es, den Code HTML für jedes Element einer Datenliste zu wiederholen. Angenommen, man möchte eine Fehlerliste in folgender Form anzeigen:

Image

Wir sind bereits auf dieses Problem gestoßen und haben es gelöst, indem wir im Darstellungscode eine Variable in der Form <ul><% =erreursHTML %></ul> eingefügt haben, wobei der Wert von erreursHTML vom Controller berechnet wird. Dieser Wert enthält den Code HTML, der zu einer Liste gehört. Dies hat den Nachteil, dass man, wenn man die Darstellung dieser Liste HTML ändern möchte, gezwungen ist, in den Controller-Teil zu wechseln, was der Trennung von Controller und Darstellung zuwiderläuft. Die Komponente [Repeater] bietet uns eine Lösung. Wie bei [DataList] können wir die Vorlagen <HeaderTemplate> für die Kopfzeile, <ItemTemplate> für das aktuelle Element der Datenliste und <FooterTemplate> für das Ende der Daten definieren. Hier könnte die Definition für die Komponente [Repeater] wie folgt lauten:

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

Zur Erinnerung: [Container.DataItem] stellt eine Datenzeile dar, wenn die Datenquelle mehrere Spalten hat. Sie stellt einen einzelnen Datensatz dar, wenn die Quelle nur eine Spalte hat. Dies ist hier der Fall. Als Beispiel erstellen wir die folgende Anwendung:

Image

Der Code für die Darstellung der Seite lautet wie folgt:

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

Der Prüfcode lautet wie folgt:

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

     ' Prozedur, die beim Laden der Seite ausgeführt wird
    Sub page_Load(sender As Object, e As EventArgs)
        if not IsPostBack then
          ' Es wird eine Datenquelle erstellt
          with Repeater1
              .DataSource=createDataSource
              .DataBind
          end with
        end if
    End Sub

    function createDataSource as ArrayList
      ' Erstellt eine ArrayList
      dim erreurs as new ArrayList
      dim i as integer
      for i=0 to 5
        erreurs.add("erreur-"+i.ToString)
      next
      return erreurs
    end function

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

Bei der ersten Anfrage des Kunden ordnen wir der Komponente [Repeater], die vermutlich eine Fehlerliste darstellt, ein Objekt [ArrayList] zu.

8.9. Application

Wir greifen hier eine bereits mit Serverkomponenten bearbeitete Anwendung wieder auf. Die Anwendung ermöglicht die Simulation von Steuerberechnungen. Sie stützt sich auf eine Klasse [impot], auf die wir hier nicht näher eingehen werden. Diese Klasse benötigt Daten, die sie in einer Datenquelle OLEDB findet. Für dieses Beispiel wird es sich um die Datenquelle ACCESS handeln. In dieser neuen Version führen wir folgende Neuerungen ein:

  • die Verwendung von Validierungskomponenten zur Überprüfung der Gültigkeit der Daten
  • die Verwendung von Serverkomponenten, die mit Datenquellen verknüpft sind, zur Anzeige der Ergebnisse

8.9.1. Die Struktur MVC der Anwendung

Die Struktur MVC der Anwendung sieht wie folgt aus:

Die drei Ansichten werden in Form von Containern in den Präsentationscode des Controllers [main.aspx] eingebunden. Daher verfügt diese Anwendung über eine einzige Seite: [main.aspx].

8.9.2. Die Ansichten der Anwendung

Die Ansicht [formulaire] ist das Formular zur Eingabe der Informationen, anhand derer die Steuer eines Benutzers berechnet wird:

Image

Der Benutzer füllt das Formular aus:

Image

Er nutzt die Schaltfläche [Envoyer], um die Berechnung seiner Steuer anzufordern. Daraufhin wird die folgende Ansicht [simulations] angezeigt:

Image

Über den obigen Link kehrt er zum Formular zurück. Er findet es in dem Zustand vor, in dem er es ausgefüllt hat. Dabei können ihm Eingabefehler unterlaufen:

Image

Diese werden ihm in der Ansicht [formulaire] angezeigt:

Image

Der Benutzer korrigiert daraufhin seine Fehler. Er kann neue Simulationen durchführen:

Image

Er erhält daraufhin die Ansicht [simulations] mit einer weiteren Simulation:

Image

Ist die Datenquelle schließlich nicht verfügbar, wird dies dem Benutzer in der Ansicht [erreurs] angezeigt:

Image

8.9.2.1. Der Darstellungscode

Zur Erinnerung: Die Seite [main.aspx] fasst alle Ansichten zusammen. Es handelt sich um ein einziges Formular mit drei Containern:

  • [panelform] für die Ansicht [formulaire]
  • [panelerreurs] für die Ansicht [erreurs]
  • [panelsimulations] für die Ansicht [simulations]

Im Folgenden werden die Komponenten dieser drei Container näher erläutert. Der Container [panelform] hat folgende visuelle Darstellung:

Nr.
Name
Typ
Eigenschaften
Rolle
0
panelform
Panel
 
Formularansicht
1
rdOui
rdNon
RadioButton
GroupName=rdmarie
Optionsfelder
2
cvMarie
CustomValidator
ErrorMessage=Sie haben Ihren Familienstand nicht angegeben
EnableClientScript=false
Überprüft, ob das Client-Programm den erwarteten Familienstand gesendet hat
3
txtEnfants
TextBox
 
Anzahl der Kinder
4
rfvEnfants
RequiredFieldValidator
ErrorMessage=Bitte geben Sie die Anzahl der Kinder an
ControlToValidate=txtEnfants
Überprüft, ob das Feld [txtEnfants] nicht leer ist
5
rvEnfants
RangeValidator
ErrorMessage=Geben Sie eine Zahl zwischen 1 und 30 ein
ControlToValidate=txtEnfants
Überprüft, ob das Feld [txtEnfants] im Bereich [1,30] liegt
6
txtSalaire
TextBox
EnableViewState=true
Jahresgehalt
7
rfvSalaire
RequiredFieldValidator
ControlToValidate=txtGehalt
ErrorMessage=Geben Sie die Höhe Ihres Gehalts an
Überprüfen Sie, ob das Feld [txtSalaire] nicht leer ist
8
revSalaire
RegularExpressionValidator
ControlToValidate=txtSalaire
ErrorMessage=Ungültiges Gehalt
RegularExpression=\s*\d+\s*
überprüft, ob das Feld [txtSalaire] aus einer Folge von Ziffern besteht
9
btnCalculer
Button
CausesValidation=true
Schaltfläche [submit] im Formular – startet die Steuerberechnung
10
btnEffacer
Schaltfläche
CausesValidation=false
Schaltfläche [submit] im Formular – löscht das Formular

Man mag sich über die Überprüfung [cvMarié] wundern, die sicherstellen soll, dass der Benutzer tatsächlich eines der beiden Optionsfelder angekreuzt hat. Es kann nämlich gar nicht anders sein, wenn er das vom Server gesendete Formular korrekt verwendet. Da dies jedoch nicht garantiert werden kann, müssen alle übermittelten Parameter überprüft werden. Zu beachten ist auch das Attribut [CausesValidation=false] der Schaltfläche [btnEffacer]. Wenn der Benutzer diese Schaltfläche verwendet, dürfen die übermittelten Daten nämlich nicht überprüft werden, da sie ignoriert werden.

Alle Komponenten des Containers haben die Eigenschaft [EnableViewState=false], mit Ausnahme von [panelForm, txtEnfants, txtSalaire, rdOui, rdNon]. Der Container [panelerreurs] hat folgende visuelle Darstellung:

Nr.
Name
Typ
Eigenschaften
Rolle
0
panelerreurs
Panel
EnableViewState=false
Fehleransicht
1
rptErreurs
Repeater
EnableViewState=false
zeigt eine Fehlerliste an

Die Komponente [rptErreurs] ist wie folgt definiert:


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

Die mit der Komponente [rptErreurs] verknüpfte Datenliste ist ein Objekt vom Typ [ArrayList], das eine Liste von Fehlermeldungen enthält. Im obigen Beispiel bezeichnet <%# Container.Dataitem%> die aktuelle Fehlermeldung. Der Container [panelsimulations] hat folgende visuelle Darstellung:

Nr.
Name
Typ
Eigenschaften
Rolle
0
panelsimulations
Panel
EnableViewState=false
Ansicht „Simulationen“
2
lnkForm2
LinkButton
EnableViewState=false
Link zum Formular
1
dgSimulations
DataGrid
EnableViewState=false
dient zur Anzeige der Simulationen, die in einem Objekt [DataTable] abgelegt sind

Die Komponente [dgSimulations] ist unter [Webmatrix] wie folgt konfiguriert. Im Eigenschaftenfenster von [dgSimulations] wählen wir den Link [Mise en forme automatique] aus und wählen das Schema [Couleur 3] aus:

Anschließend wählen wir im Eigenschaftenfenster von [dlgSimulations] den Link [Générateur de propriétés] aus. Wir lassen die Spaltenüberschriften anzeigen:

Image

Wir wählen die Option [Colonnes] aus, um die vier Spalten von [DataGrid] festzulegen:

Image

Wir deaktivieren den Eintrag [Créer des colonnes automatiquement ...]. Wir werden die vier Spalten des [DataGrid] selbst definieren. Dieses wird einem Objekt [DataTable] mit vier Spalten zugeordnet, die jeweils „verheiratet“, „Kinder“, „Gehalt“ und „Steuer“ heißen. Um eine Spalte im [DataGrid] anzulegen, wählen wir die Option [Colonnes connexe] aus und verwenden die Schaltfläche zum Anlegen wie oben beschrieben. Es wird eine Spalte angelegt, deren Eigenschaften wir nun festlegen können. Die erste Spalte der Simulationstabelle enthält die Spalte „verheiratet“ des Objekts [DataTable], das mit dem Objekt [DataGrid] verknüpft wird. Diese erste Spalte des Objekts [DataGrid] wird im Assistenten wie folgt definiert:

Image

Texte de l'en-tête
Spaltenüberschrift, hier „Verheiratet“
Champ de données
Name der Spalte in der Datenquelle, die durch diese Spalte des [DataGrid] angezeigt wird. Hier ist es die Spalte „verheiratet“ des [DataTable].

Die zweite Spalte ist wie folgt definiert:

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

Die dritte Spalte ist wie folgt definiert:

Texte de l'en-tête
Jahresgehalt
Champ de données
Gehalt
Expression de mise en forme
{0:C} – Währungsanzeige, um das Euro-Zeichen anzuzeigen

Die vierte Spalte ist wie folgt definiert:

Texte de l'en-tête
Steuerbetrag
Champ de données
Steuer
Expression de mise en forme
{0:C} – Währungsanzeige, um das Euro-Zeichen zu erhalten

Wir speichern den Darstellungscode und den Prüfcode in zwei separaten Dateien. Die erste befindet sich in [main.aspx] und die zweite in [main.aspx.vb]. Der Code von [main.aspx] lautet wie folgt:


<%@ 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. Der Steuerungscode der Anwendung

Der Anwendungsprüfcode ist auf die Dateien [global.asax.vb] und [main.aspx.vb] verteilt. Die Datei [global.asax] ist wie folgt definiert:

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

Die Datei [global.asax.vb] lautet wie folgt:


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)
        ' Es wird ein Impot-Objekt erstellt
        Dim objImpot As impot
        Try
            objImpot = New impot(New impotsOLEDB(ConfigurationSettings.AppSettings("chaineConnexion")))
            ' Das Objekt wird in die Anwendung eingefügt
            Application("objImpot") = objImpot
            ' kein Fehler
            Application("erreur") = False
        Catch ex As Exception
            'Es ist ein Fehler aufgetreten, der in der Anwendung vermerkt wird
            Application("erreur") = True
            Application("message") = ex.Message
        End Try
    End Sub

    Sub Session_Start(ByVal sender As Object, ByVal e As EventArgs)
        ' Sitzungsbeginn – es wird eine leere Simulationsliste erstellt
        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

Beim Start der Anwendung (erste Anfrage an die Anwendung) wird die Prozedur [Application_Start] ausgeführt. Sie versucht, ein Objekt vom Typ [impot] anzulegen, dessen Daten aus einer Quelle vom Typ OLEDB stammen. Der Leser wird gebeten, Kapitel 5 zu lesen, in dem diese Klasse definiert wurde, falls er dies vergessen hat. Die Erstellung des Objekts [impot] kann fehlschlagen, wenn die Datenquelle nicht verfügbar ist. In diesem Fall wird der Fehler in der Anwendung gespeichert, damit alle nachfolgenden Abfragen wissen, dass diese nicht korrekt initialisiert werden konnte. Wenn die Erstellung erfolgreich verläuft, wird das erstellte Objekt [impot] ebenfalls in der Anwendung gespeichert. Es wird von allen Abfragen zur Steuerberechnung verwendet. Wenn ein Kunde seine erste Abfrage stellt, wird für ihn durch die Prozedur [Application_Start] eine Sitzung angelegt. Diese Sitzung dient dazu, die verschiedenen Steuerberechnungssimulationen zu speichern, die er durchführen wird. Diese werden in einem Objekt [DataTable] gespeichert, das dem Sitzungsschlüssel „simulations“ zugeordnet ist. Zu Beginn der Sitzung wird dieser Schlüssel einem leeren Objekt [DataTable] zugeordnet, dessen Struktur jedoch bereits definiert wurde. Die für die Anwendung erforderlichen Informationen werden in dessen Konfigurationsdatei [wenConfig] abgelegt:


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

Der Schlüssel [chaineConnexion] bezeichnet die Verbindungszeichenfolge zur Quelle OLEDB. Der andere Teil des Prüfcodes befindet sich 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 Variablen

    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

Das erste vom Code verarbeitete Ereignis ist [Page_Load]:


    Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        ' Zunächst wird geprüft, in welchem Zustand sich die Anwendung befindet
        If CType(Application("erreur"), Boolean) Then
            ' Die Anwendung konnte nicht initialisiert werden
            ' Die Fehleransicht wird angezeigt
            Dim erreurs As New ArrayList
            erreurs.Add("Application momentanément indisponible (" + CType(Application("message"), String) + ")")
            afficheErreurs(erreurs)
            Exit Sub
        End If
        ' Keine Fehler – bei der ersten Anfrage wird das Formular angezeigt
        If Not IsPostBack Then afficheFormulaire()
    End Sub

Bevor wir mit der Bearbeitung der Anfrage beginnen, stellen wir sicher, dass die Anwendung ordnungsgemäß initialisiert werden konnte. Ist dies nicht der Fall, wird die Ansicht [erreurs] mit der Prozedur [afficheErreurs] angezeigt. Handelt es sich um die erste Anfrage (IsPostBack=false), lassen wir die Ansicht [formulaire] mit [afficheFormulaire] anzeigen.

Die Prozedur zur Anzeige der Ansicht [erreurs] lautet wie folgt:


    Private Sub afficheErreurs(ByRef erreurs As ArrayList)
        ' Die Fehlerliste wird erstellt
        With rptErreurs
            .DataSource = erreurs
            .DataBind()
        End With
        ' Anzeige der Container 
        panelerreurs.Visible = True
        panelform.Visible = False
        panelsimulations.Visible = False
        Exit Sub
    End Sub

Die Prozedur erhält als Parameter eine Liste von Fehlermeldungen in [erreurs] vom Typ [ArrayList]. Wir verknüpfen diese Datenquelle lediglich mit der Komponente [rptErreurs], die für die Anzeige zuständig ist.

Die Prozedur zur Anzeige der Ansicht [formulaire] lautet wie folgt:


    Private Sub afficheFormulaire()
        ' zeigt das Formular an
        panelform.Visible = True
        ' Die anderen Container werden ausgeblendet
        panelerreurs.Visible = False
        panelsimulations.Visible = False
    End Sub

Dieses Verfahren macht lediglich den Container [panelform] sichtbar. Die Komponenten werden mit ihrem gebuchten oder vorherigen Wert (VIEWSTATE) angezeigt.

Wenn der Benutzer in der Ansicht [formulaire] auf die Schaltfläche [Calculer] klickt, wird ein Übergang von POST zu [main.aspx] durchgeführt. Die Prozedur [Page_Load] wird ausgeführt, anschließend die Prozedur [btnCalculer_Click]:


    Private Sub btnCalculer_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnCalculer.Click
        ' Die Gültigkeit der eingegebenen Daten wird überprüft; falls Fehler vorliegen, werden diese gemeldet
        If Not Page.IsValid Then
            afficheFormulaire()
            Exit Sub
        End If
        ' keine Fehler – die Steuer wird berechnet
        Dim impot As Long = CType(Application("objImpot"), impot).calculer( _
        rdOui.Checked, CType(txtEnfants.Text, Integer), CType(txtSalaire.Text, Long))
        ' Das Ergebnis wird zu den bestehenden Simulationen hinzugefügt
        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)
        ' Die Simulationen werden in die Sitzung übernommen
        Session.Item("simulations") = simulations
        ' Die Seite mit den Simulationen wird angezeigt
        afficheSimulations(simulations, "Retour au formulaire")
    End Sub

Der Vorgang beginnt mit der Überprüfung der Gültigkeit der Seite. An dieser Stelle sei daran erinnert, dass bei der Ausführung des Vorgangs [btnCalculer_Click] die Gültigkeitsprüfungen bereits durchgeführt wurden und das Attribut [IsValid] der Seite gesetzt wurde. Ist die Seite nicht gültig, wird die Ansicht [formulaire] erneut angezeigt und der Vorgang beendet. Die Validierungskomponenten der Ansicht [formulaire], deren Attribut [IsValid] einen Wert zwischen [false] und [ErrorMessage] hat, zeigen ihr Attribut [ErrorMessage] an. Ist die Seite gültig, wird der Steuerbetrag anhand des Objekts vom Typ [impot] berechnet, das beim Start der Anwendung gespeichert wurde. Diese neue Simulation wird der Liste der bereits durchgeführten Simulationen hinzugefügt und in der Sitzung gespeichert.

Schließlich wird die Ansicht [simulations] durch die folgende Prozedur [afficheSimulations] angezeigt:


    Private Sub afficheSimulations(ByRef simulations As DataTable, ByRef lien As String)
        ' Das Datagrid wird mit der Simulationsquelle verknüpft
        With dgSimulations
            .DataSource = simulations
            .DataBind()
        End With
        ' Verknüpfung
        lnkForm2.Text = lien
        ' die Ansichten
        panelsimulations.Visible = True
        panelerreurs.Visible = False
        panelform.Visible = False
    End Sub

Die Prozedur hat zwei Parameter:

  • eine Liste von Simulationen in [simulations] vom Typ [DataTable]
  • einen Linktext in [lien]

Die Datenquelle [simulations] ist mit der Komponente verknüpft, die für ihre Anzeige zuständig ist. Der Linktext wird in der Eigenschaft [Text] des Objekts [LinkButton] der Ansicht hinterlegt.

Wenn der Benutzer auf die Schaltfläche [Effacer] in der Ansicht [formulaire] klickt, wird die Prozedur [btnEffacer_click] ausgeführt (immer nach [Page_Load]):


    Private Sub btnEffacer_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnEffacer.Click
        ' zeigt das leere Formular an
        razForm()
        afficheFormulaire()
    End Sub

    Private Sub razForm()
        ' leert das Formular
        rdOui.Checked = False
        rdNon.Checked = True
        txtEnfants.Text = ""
        txtSalaire.Text = ""
    End Sub

Der obige Code ist so einfach, dass er keiner Erläuterung bedarf. Nun müssen wir noch den Klick auf die Links in den Ansichten [erreurs] und [simulations] behandeln:


    Private Sub lnkForm1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles lnkForm1.Click
        ' zeigt das Formular an
        afficheFormulaire()
    End Sub

    Private Sub lnkForm2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles lnkForm2.Click
        ' zeigt das Formular an
        afficheFormulaire()
    End Sub

Beide Prozeduren sorgen lediglich dafür, dass die Ansicht [formulaire] angezeigt wird. Wir wissen, dass die Felder dieser Ansicht entweder den für sie übermittelten Wert oder ihren vorherigen Wert erhalten. Da in diesem Fall das Formular POST des Kunden keine Werte für die Formularfelder übermittelt, erhalten diese ihren vorherigen Wert zurück. Das Formular wird daher mit den vom Benutzer eingegebenen Werten angezeigt.

8.9.4. Tests

Alle für die Anwendung erforderlichen Dateien befinden sich in einem Ordner <application-path>:
Der Ordner [bin] enthält die DLL mit den für die Anwendung erforderlichen Klassen [impot], [impotsData] und [impotsOLEDB]:

Der Leser kann, falls gewünscht, noch einmal Kapitel 5 nachlesen, in dem erklärt wird, wie die oben genannte Datei [impot.dll] erstellt wird. Anschließend wird der Cassini-Server mit den Parametern (<application-path>,/impots6) gestartet. Die URL [http://impots6/main.aspx] wird mit einem Browser aufgerufen:

Image

Wenn man die Datei ACCESS [impots.mdb] in [impots1.mdb] umbenennt, erhält man die folgende Seite:

Image

8.9.5. Fazit

Wir haben eine Anwendung MVC, die ausschließlich Serverkomponenten verwendet. Durch deren Einsatz konnte der Präsentationsteil der Anwendung vollständig vom Steuerungsteil getrennt werden. Bislang war dies noch nicht möglich, da der Präsentationscode Variablen enthielt, die vom Steuerungscode berechnet wurden und deren Wert HTML-Code enthielt. Dies ist nun nicht mehr der Fall.