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:

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:

ASP.NET bietet sogenannte Validierungskomponenten, mit denen folgende Fälle überprüft werden können:
Komponente | Rolle |
prüft, ob ein Feld nicht leer ist | |
vergleicht zwei Werte miteinander | |
prüft, ob ein Wert zwischen zwei Grenzwerten liegt | |
prüft, ob ein Feld einem regulären Ausdruck entspricht | |
ermöglicht es dem Entwickler, eigene Validierungsregeln festzulegen – diese Komponente könnte alle anderen ersetzen | |
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 | TextBox | EnableViewState=true | Eingabefeld | |
2 | RequiredFieldValidator | EnableViewState=false EnableClientScript=true ErrorMessage=Das Feld [Name] ist ein Pflichtfeld | Validierungskomponente | |
3 | 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:
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. | |
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. | |
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]:

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

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:

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

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:

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:

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

Nr. | Name | Typ | Eigenschaften | Rolle |
1 | DropDownList | EnableViewState=true | Dropdown-Liste | |
2 | DropDownList | EnableViewState=true | Dropdown-Liste | |
3 | CompareValidator | EnableViewState=false EnableClientScript=true ErrorMessage=Ungültige Auswahl 1 ZuVergleichenderWert=? Operator=Nicht gleich Typ=Zeichenkette | Validierungskomponente | |
4 | CompareValidator | EnableViewState=false EnableClientScript=true ErrorMessage=Ungültige Auswahl 2 ControlToCompare=? Operator=Nicht gleich Typ=Zeichenkette | Validierungskomponente | |
5 | 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:
Feld, dessen Inhalt von der Komponente geprüft werden soll | |
Boolescher Wert – bei „wahr“ wird angegeben, dass der Inhalt des vorherigen Feldes auch auf der Client-Seite überprüft werden soll | |
die Fehlermeldung, die die Komponente im Falle eines erkannten Fehlers anzeigen soll | |
Wert, mit dem der Wert des Feldes verglichen werden soll [ControlToValidate] | |
Komponente, mit deren Wert der Wert des Feldes verglichen werden soll [ControlToValidate] | |
Vergleichsoperator zwischen den beiden Werten | |
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:

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

Nr. | Name | Typ | Eigenschaften | Rolle |
DropDownList | EnableViewState=true | Dropdown-Liste | ||
CompareValidator | EnableViewState=false EnableClientScript=true ErrorMessage=Ungültiges Diplom Operator=Nicht gleich ValueToCompare=? Typ=Zeichenkette | Validierungskomponente der Prüfung [1] | ||
TextBox | EnableViewState=false | Eingabefeld | ||
CustomValidator | EnableViewState=false EnableClientScript=true ErrorMessage=Ungültige Angabe zum Abschluss ClientValidationFunction=chkAutreDiplome | Validierungskomponente für das Feld [3] | ||
TextBox | EnableViewState=false | Eingabefeld | ||
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] | ||
RequiredFieldValidator | EnableViewState=false EnableClientScript=true ErrorMessage=Angabe des Abschlussjahres erforderlich ControlToValidate=txtAnDiplome | Validierungskomponente für das Feld [5] | ||
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:
Feld, dessen Wert von der Komponente überprüft werden soll | |
Boolescher Wert – bei „wahr“ wird der Inhalt des vorherigen Feldes auch auf der Client-Seite überprüft | |
die Fehlermeldung, die die Komponente im Falle eines erkannten Fehlers anzeigen soll | |
Mindestwert des zu prüfenden Feldes | |
Maximalwert des zu prüfenden Feldwerts | |
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:
Feld, dessen Wert von der Komponente überprüft werden muss | |
Boolescher Wert – bei „wahr“ muss der Inhalt des vorherigen Feldes ebenfalls clientseitig geprüft werden | |
die Fehlermeldung, die die Komponente im Falle eines erkannten Fehlers anzeigen soll | |
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îtrise">MaîTrise</asp:ListItem>
<asp:ListItem Value="DESS">DESS</asp:ListItem>
<asp:ListItem Value="DEA">DEA</asp:ListItem>
</asp:DropDownList>
</td>
<td>
Si [Autre], précisez</td>
<td>
<asp:TextBox id="txtAutreDiplome" runat="server" EnableViewState="False"></asp:TextBox>
</td>
</tr>
<tr>
<td>
</td>
<td>
<p>
<asp:CompareValidator id="CompareValidator2" runat="server" ErrorMessage="Diplôme invalide" ControlToValidate="cmbDiplomes" ValueToCompare="?" Operator="NotEqual" ></asp:CompareValidator>
</p>
</td>
<td>
</td>
<td>
<asp:CustomValidator id="CustomValidator1" runat="server" ErrorMessage="Précision diplôme invalide" OnServerValidate="CustomValidator1_ServerValidate_1" EnableViewState="False" ClientValidationFunction="chckAutreDiplome"></asp:CustomValidator>
</td>
</tr>
<tr>
<td>
Année d'obtention*</td>
<td colspan="3">
<asp:TextBox id="txtAnDiplome" runat="server" Columns="4"></asp:TextBox>
<asp:RangeValidator id="RangeValidator1" runat="server" ErrorMessage="Année diplôme doit être dans l'intervalle [1990,2004]" ControlToValidate="txtAnDiplome" MinimumValue="1990" MaximumValue="2004" Type="Integer"></asp:RangeValidator>
<asp:RequiredFieldValidator id="RequiredFieldValidator2" runat="server" ErrorMessage="Année diplôme requise" ControlToValidate="txtAnDiplome"></asp:RequiredFieldValidator>
</td>
</tr>
</tbody>
</table>
</fieldset>
<p>
<asp:Button id="btnEnvoyer" runat="server" Text="Envoyer"></asp:Button>
</p>
</form>
</body>
</html>
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]:

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

Nr. | Name | Typ | Eigenschaften | Rolle |
TextBox | EnableViewState=true | Eingabefeld | ||
RequiredFieldValidator | ControlToValidate=txtMel Display=Dynamic | Validierungskomponente des Steuerelements [1] | ||
RegularExpressionValidator | ControlToValidate=txtMel Display=Dynamic | Validierungskomponente des Steuerelements [1] | ||
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:
Feld, dessen Wert von der Komponente geprüft werden soll | |
Boolescher Wert – bei „wahr“ muss der Inhalt des vorherigen Feldes auch auf der Client-Seite überprüft werden | |
die Fehlermeldung, die die Komponente im Falle eines erkannten Fehlers anzeigen soll | |
der reguläre Ausdruck, mit dem der Inhalt von [ControlToValidate] verglichen wird | |
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:

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:

Nr. | Name | Typ | Eigenschaften | Rolle |
1 | ValidationSummary | HeaderText=Die folgenden Fehler sind aufgetreten, EnableClientScript=false, ShowSummary=true | zeigt die Fehler aller Validierungssteuerelemente auf der Seite an | |
2 | 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:

1
Nr. | Name | Typ | Eigenschaften | Rolle |
1 | 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:

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

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

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

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:
<option value="V">T</option> | |
<input type="checkbox" value="V">T | |
<input type="radio" value="V">T |
Die Zuordnung einer Komponente [ListControl] zu einer Datenquelle erfolgt über die folgenden Eigenschaften:
eine Datenquelle [Array], [ArrayList], [DataTable], [DataSet], [HashTable], ... | |
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. | |
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 | |
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:
[ListControl].DataSource=A Die Felder [Text] und [Value] der Elemente von [ListControl] erhalten als Werte die Elemente von A | |
[ListControl].DataSource=AL Die Felder [Text] und [Value] der Elemente von [ListControl] erhalten die Werte der Elemente von AL | |
[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 | |
[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“ | |
[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 |
Array | |
ArrayList | |
DataTable | |
DataSet | |
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:
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:
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:
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:
eine Datenquelle [Array], [ArrayList], [DataTable], [DataSet], ... | |
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:

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:

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:

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

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:

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:
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 | DataGrid | EnableViewState=true | zeigt eine Datenquelle S an | |
2 | DataGrid | EnableViewState=true | zeigt dieselbe Quelle S wie [DataGrid1] an | |
3 | 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:

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:

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 | DataGrid | EnableViewState=true | zeigt eine Datenquelle S an | |
2 | DataGrid | EnableViewState=false | zeigt dieselbe Quelle S an wie [DataGrid1] | |
3 | Schaltfläche | EnableViewState=false | Schaltfläche [submit] | |
4 | 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:

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 :
<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:
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:
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:
um den neuen Wert von [numRequête3] in der Sitzung zu speichern. Stattdessen müsste man schreiben:
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:

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 | TextBox | EnableViewState=true | Eingabefeld für die SELECT-Abfrage | |
2 | RequiredFieldValidator | EnableViewState=false | Prüft, ob 1 vorhanden ist | |
3 | TextBox | EnableViewState=true | Eingabefeld – gibt die Anzahl der Datenzeilen an, die pro Ergebnisseite angezeigt werden sollen | |
4 | RequiredFieldValidator | EnableViewState=false | prüft, ob 3 vorhanden ist | |
5 | RangeValidator | EnableViewState=false | überprüft, ob (3) im Intervall [1,30] liegt | |
6 | 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 | Bezeichnung | EnableViewState=false | Informationsfeld | |
2 | RadioButton | EnableViewState=false GroupName=rdTri | ermöglicht die Auswahl einer Sortierreihenfolge | |
3 | DataGrid | EnableViewState=true AllowPaging=true AllowSorting=true | Tabelle zur Anzeige der Ergebnisse der SELECT-Abfrage | |
4 | 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.

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

Die Ansicht [erreurs] wird angezeigt:
![]() |
Nr. | Name | Typ | Eigenschaften | Rolle |
1 | Variable | Code HTML erforderlich für die Anzeige von Fehlern | ||
3 | 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> Exemple : select id, nom, prix from LISTE
</P>
<P>
<asp:TextBox id="txtSelect" runat="server" Columns="60"></asp:TextBox></P>
<P>
<asp:RequiredFieldValidator id="RequiredFieldValidator1" runat="server" EnableViewState="False" EnableClientScript="False"
ErrorMessage="Indiquez la requête [select] à exécuter" ControlToValidate="txtSelect" Display="Dynamic"></asp:RequiredFieldValidator></P>
<P>Nombre de lignes par page :
<asp:TextBox id="txtPages" runat="server" Columns="3"></asp:TextBox></P>
<P>
<asp:RequiredFieldValidator id="RequiredFieldValidator2" runat="server" EnableViewState="False" EnableClientScript="False"
ErrorMessage="Indiquez le nombre de lignes par page désirées" ControlToValidate="txtPages" Display="Dynamic"></asp:RequiredFieldValidator>
<asp:RangeValidator id="RangeValidator1" runat="server" EnableViewState="False" EnableClientScript="False"
ErrorMessage="Vous devez indiquer un nombre entre 1 et 30" ControlToValidate="txtPages" Display="Dynamic"
Type="Integer" MinimumValue="1" MaximumValue="30"></asp:RangeValidator></P>
<P>
<asp:Button id="btnExécuter" runat="server" EnableViewState="False" Text="Exécuter"></asp:Button></P>
</asp:panel>
<asp:Panel id="vueRésultats" runat="server">
<P>Résultats de la requête
<asp:Label id="lblSelect" runat="server"></asp:Label></P>
<P>Tri
<asp:RadioButton id="rdCroissant" runat="server" Text="croissant" Checked="True" GroupName="rdTri"></asp:RadioButton>
<asp:RadioButton id="rdDécroissant" runat="server" Text="décroissant" GroupName="rdTri"></asp:RadioButton></P>
<P>
<asp:DataGrid id="DataGrid1" runat="server" BorderColor="#CC9966" BorderStyle="None" BorderWidth="1px"
BackColor="White" CellPadding="4" AllowPaging="True" PageSize="4" AllowSorting="True">
<SelectedItemStyle Font-Bold="True" ForeColor="#663399" BackColor="#FFCC66"></SelectedItemStyle>
<ItemStyle ForeColor="#330099" BackColor="White"></ItemStyle>
<HeaderStyle Font-Bold="True" ForeColor="#FFFFCC" BackColor="#990000"></HeaderStyle>
<FooterStyle ForeColor="#330099" BackColor="#FFFFCC"></FooterStyle>
<PagerStyle NextPageText="Suivant" PrevPageText="Précédent" HorizontalAlign="Center"
ForeColor="#330099" BackColor="#FFFFCC"></PagerStyle>
</asp:DataGrid></P>
<P>
<asp:LinkButton id="lnkRésultats" runat="server" EnableViewState="False">Retour au formulaire</asp:LinkButton></P>
</asp:Panel>
<asp:Panel id="vueErreurs" runat="server">
<P>Les erreurs suivantes se sont produites :</P>
<% =erreursHTML %>
<P>
<asp:LinkButton id="lnkErreurs" runat="server" EnableViewState="False">Retour vers le formulaire</asp:LinkButton></P>
</asp:Panel>
</form>
</body>
</HTML>
8.6.3. 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écédent" ...></PagerStyle>
</asp:DataGrid></P>
Paginierung zulassen | |
vier Datenzeilen pro Seite | |
Der Linktext, um zur nächsten Seite der Datenquelle zu gelangen | |
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]:

Es erscheint der folgende Assistent:

Man wählt die Option [Pagination]:

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]
[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:
auf „wahr“, wenn die überprüften Daten gültig sind, andernfalls auf „falsch“ | |
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
das Ursprungsobjekt des Ereignisses – in diesem Fall einer der Links [Suivant] oder [Précédent] | |
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
das Ursprungsobjekt des Ereignisses – in diesem Fall einer der Links [Suivant] oder [Précédent] | |
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 | RadioButton | EnableViewState=false | ermöglicht die Auswahl eines Stils für [DataList] aus zwei Optionen | |
2 | Button | EnableViewState=false | Schaltfläche [submit] | |
3 | 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 | DataList | EnableViewState=true | Anzeigefeld der Datenliste |
Die Ansicht [erreurs] meldet ein Problem beim Zugriff auf die Datenquelle:
![]() |
Nr. | Name | Typ | Eigenschaften | Rolle |
1 | 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:
Vorlage für die Kopfzeile von [DataList] | |
Vorlage für die Zeilen, in denen die Elemente der zugehörigen Datenliste angezeigt werden. Nur diese Vorlage ist obligatorisch. | |
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 | |
Vorlage für das in [DataList] ausgewählte Element | |
Vorlage für das Trennzeichen zwischen zwei Elementen in [DataList] | |
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 | |
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:
| |
|
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:

Oben wurden die Daten mit vier Datensätzen pro Zeile angeordnet. Dies wird mit den folgenden Attributen von [DataList] erreicht:
Horizontal | |
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]
[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:

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:

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:

Der Benutzer füllt das Formular aus:

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

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

Diese werden ihm in der Ansicht [formulaire] angezeigt:

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

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

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

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 |
Panel | Formularansicht | |||
RadioButton | GroupName=rdmarie | Optionsfelder | ||
CustomValidator | ErrorMessage=Sie haben Ihren Familienstand nicht angegeben EnableClientScript=false | Überprüft, ob das Client-Programm den erwarteten Familienstand gesendet hat | ||
TextBox | Anzahl der Kinder | |||
RequiredFieldValidator | ErrorMessage=Bitte geben Sie die Anzahl der Kinder an ControlToValidate=txtEnfants | Überprüft, ob das Feld [txtEnfants] nicht leer ist | ||
RangeValidator | ErrorMessage=Geben Sie eine Zahl zwischen 1 und 30 ein ControlToValidate=txtEnfants | Überprüft, ob das Feld [txtEnfants] im Bereich [1,30] liegt | ||
TextBox | EnableViewState=true | Jahresgehalt | ||
RequiredFieldValidator | ControlToValidate=txtGehalt ErrorMessage=Geben Sie die Höhe Ihres Gehalts an | Überprüfen Sie, ob das Feld [txtSalaire] nicht leer ist | ||
RegularExpressionValidator | ControlToValidate=txtSalaire ErrorMessage=Ungültiges Gehalt RegularExpression=\s*\d+\s* | überprüft, ob das Feld [txtSalaire] aus einer Folge von Ziffern besteht | ||
Button | CausesValidation=true | Schaltfläche [submit] im Formular – startet die Steuerberechnung | ||
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 |
Panel | EnableViewState=false | Fehleransicht | ||
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 |
Panel | EnableViewState=false | Ansicht „Simulationen“ | ||
LinkButton | EnableViewState=false | Link zum Formular | ||
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:

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

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:

Spaltenüberschrift, hier „Verheiratet“ | |
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:
Kinder | |
Kinder |
Die dritte Spalte ist wie folgt definiert:
Jahresgehalt | |
Gehalt | |
{0:C} – Währungsanzeige, um das Euro-Zeichen anzuzeigen |
Die vierte Spalte ist wie folgt definiert:
Steuerbetrag | |
Steuer | |
{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é" HeaderText="Marié"></asp:BoundColumn>
<asp:BoundColumn DataField="enfants" HeaderText="Enfants"></asp:BoundColumn>
<asp:BoundColumn DataField="salaire" HeaderText="Salaire annuel" DataFormatString="{0:C}"></asp:BoundColumn>
<asp:BoundColumn DataField="impôt" HeaderText="Montant de l'impôt" DataFormatString="{0:C}"></asp:BoundColumn>
</Columns>
<PagerStyle HorizontalAlign="Center" ForeColor="#8C4510" Mode="NumericPages"></PagerStyle>
</asp:DataGrid></P>
<P>
<asp:LinkButton id="lnkForm2" runat="server" EnableViewState="False">Retour au formulaire</asp:LinkButton></P>
</asp:panel>
</FORM>
</body>
</HTML>
8.9.3. 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:
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:

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

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.






















