8. ASP-Serverkomponenten – 2
8.1. Einführung
Wir setzen unsere Arbeit an der Benutzeroberfläche fort und befassen uns mit:
- Komponenten zur Datenvalidierung
- wie man Daten an Serverkomponenten bindet
- HTML-Serverkomponenten
8.2. alle Datenvalidierungskomponenten
8.2.1. Einführung
In formularbasierten Anwendungen ist es unerlässlich, die Gültigkeit der 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 zusammen mit Fehlermeldungen unverändert an den Client zurückgesendet. Wir haben dieses Szenario mit zwei Ansichten umgesetzt, eine für das obige Formular und die andere für die Fehler:

ASP.NET bietet sogenannte Validierungskomponenten, mit denen Sie Folgendes überprüfen können:
Komponente | Rolle |
prüft, ob ein Feld nicht leer ist | |
vergleicht zwei Werte miteinander | |
prüft, ob ein Wert zwischen zwei Grenzen liegt | |
prüft, ob ein Feld einem regulären Ausdruck entspricht | |
ermöglicht es dem Entwickler, eigene Validierungsregeln zu definieren – diese Komponente könnte alle anderen ersetzen | |
ermöglicht es Ihnen, die von den vorherigen Steuerelementen generierten 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 | Textfeld | EnableViewState=true | Eingabefeld | |
2 | RequiredFieldValidator | EnableViewState=false Client-Skript aktivieren=true ErrorMessage=Das Feld [name] ist erforderlich | Validierungskomponente | |
3 | Schaltfläche | EnableViewState=false ValidationReasons=true | [submit]-Schaltfläche |
Das Feld [RequiredFieldValidator1] wird verwendet, um eine Fehlermeldung anzuzeigen, wenn das Feld [txtName] leer ist oder eine Zeichenfolge aus Leerzeichen enthält. Seine Eigenschaften sind wie folgt:
Das Feld, dessen Wert von der Komponente validiert werden muss. Was bedeutet der Wert einer Komponente? Es handelt sich um den Wert des Attributs [value] des entsprechenden HTML-Tags. Bei einem [TextBox] ist dies der Inhalt des Eingabefelds; bei einem [DropDownList] ist es der Wert des ausgewählten Elements. | |
Boolean – Wenn „true“, gibt dies an, dass der Inhalt des vorherigen Feldes auch auf der Client-Seite validiert werden muss. In diesem Fall wird das Formular vom Browser nur übermittelt, wenn es keine Fehler enthält. Validierungsprüfungen werden jedoch auch auf dem Server durchgeführt, falls der Client beispielsweise kein Browser ist. | |
Die Fehlermeldung, die die Komponente anzeigen muss, wenn ein Fehler erkannt wird |
Die Datenvalidierung auf der Seite wird nur durchgeführt, wenn die Schaltfläche oder der Link, der den [POST] der Seite ausgelöst hat, die Eigenschaft [CausesValidation=true] besitzt. [true] ist der Standardwert für diese Eigenschaft.
Lassen Sie uns diese Anwendung ausführen. Zunächst verwenden wir einen [Mozilla]-Browser:

Der von [Mozilla] empfangene HTML-Code 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>
Wir sehen, dass die Schaltfläche [btnEnvoyer] über ihr [onclick]-Attribut mit einer JavaScript-Funktion verknüpft ist. Wir sehen auch, dass die Seite keinen [JavaScript]-Code 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 übermittelt, der die Validierungsprüfungen durchführt. Verwenden wir die Schaltfläche [Submit], ohne einen Namen einzugeben. Die Antwort des Servers lautet wie folgt:

Was ist passiert? Das Formular wurde an den Server gesendet. Der Server hat den Code für alle Validierungskomponenten auf der Seite ausgeführt. Hier gibt es nur eine. Wenn mindestens eine Validierungskomponente einen Fehler feststellt, gibt der Server das Formular so zurück, wie es eingegeben wurde (tatsächlich enthält es bei Komponenten mit [EnableViewState=true] auch eine Fehlermeldung für jede Validierungskomponente, die einen Fehler festgestellt hat). Diese Meldung ist das [ErrorMessage]-Attribut der Validierungskomponente. Dies ist der Mechanismus, den wir oben in Aktion sehen. Wenn wir etwas in das Feld [name] eingeben, erscheint die Fehlermeldung nicht mehr, wenn das Formular gesendet wird:

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

Der vom IE empfangene HTML-Code 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>
Wir sehen, dass dieser Code viel länger ist als der von [Mozilla] empfangene. Wir werden nicht auf die Details eingehen. Der Unterschied rührt daher, dass der Server JavaScript-Funktionen in das gesendete HTML-Dokument eingebunden hat. Warum gibt es zwei verschiedene HTML-Codes, obwohl die von beiden Browsern angeforderte URL identisch ist? Wir haben bereits erwähnt, dass die ASP.NET-Technologie bewirkt, dass der Server das an den Client gesendete HTML-Dokument an die spezifische Umgebung dieses Clients anpasst. Es gibt verschiedene Browser auf dem Markt, und nicht alle verfügen über die gleichen Funktionen. Microsoft- und Netscape-Browser verwenden beispielsweise nicht dasselbe Objektmodell für das empfangene Dokument. Folglich unterscheidet sich der JavaScript-Code, der zur Bearbeitung dieses Dokuments auf der Client-Seite verwendet wird, zwischen den beiden Browsern. Ebenso haben Browser-Anbieter sukzessive neue Versionen ihrer Browser veröffentlicht und deren Funktionen kontinuierlich verbessert. Daher kann ein HTML-Dokument, das IE5 auswerten kann, von IE3 möglicherweise nicht verstanden werden. Oben ist ein Beispiel für diese serverseitige Anpassung an den Client dargestellt. Aus einem hier nicht näher untersuchten Grund stellte der Webserver fest, dass dem Client [Mozilla] die Fähigkeit fehlte, den JavaScript-Code zur Validierung zu verarbeiten. Daher wurde dieser Code nicht in das an ihn gesendete HTML-Dokument aufgenommen, und die Validierung wurde auf der Serverseite durchgeführt. Für [IE6] wurde dieser JavaScript-Code, wie wir sehen können, in das gesendete HTML-Dokument aufgenommen. Um dies in Aktion zu sehen, führen wir folgendes Experiment durch:
- Stoppen Sie den Webserver
- klicken Sie auf die Schaltfläche [Absenden], ohne das Feld [Name] auszufüllen
Wir erhalten die folgende neue Seite:

Es ist tatsächlich der Browser, der die Fehlermeldung angezeigt hat. Das liegt daran, dass der Server angehalten ist. Wir können dies überprüfen, indem wir etwas in das Feld [Name] eingeben und absenden. Diesmal lautet die Antwort wie folgt:

Was ist passiert? Der Browser hat den JavaScript-Validierungscode ausgeführt. Dieser Code stellte fest, dass die Seite gültig war. Der Browser hat das Formular dann an den Webserver gesendet, der jedoch angehalten war. Der Browser hat dies erkannt und die oben gezeigte Seite angezeigt. Wenn wir den Server neu starten, kehrt alles zum Normalzustand zurück.
Was können wir aus diesem Beispiel lernen?
- den Wert des Konzepts der Validierungskomponente, das es ermöglicht, jedes fehlerhafte Formular an den Client zurückzusenden
- den Wert von [VIEWSTATE], wodurch das Formular genau so zurückgegeben werden kann, wie es eingegeben wurde
- die Fähigkeit des Servers, sich an seinen Client anzupassen. Der Client wird durch den HTTP-Header [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 für seine 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 Client-Skript aktivieren=true Fehlermeldung=Ungültige Auswahl 1 Zu vergleichender Wert=? Operator=Nicht gleich Typ=Zeichenkette | Validierungskomponente | |
4 | CompareValidator | ViewState aktivieren=false Client-Skript aktivieren=true Fehlermeldung=Ungültige Auswahl 2 Zu vergleichendes Steuerelement=? Operator=Nicht gleich Typ=Zeichenkette | Validierungskomponente | |
5 | Schaltfläche | EnableViewState=false ValidationReasons=true | [submit]-Schaltfläche |
Die Komponente [CompareValidator] dient zum Vergleichen zweier Werte. Die verfügbaren Operatoren sind [Equal, NotEqual, LessThan, LessThanEqual, GreaterThan, GreaterThanEqual]. Der erste Wert wird durch die Eigenschaft [ControlToValidate] festgelegt, der zweite durch [ValueToCompare], wenn der erste 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 wie folgt:
Feld, dessen Inhalt von der Komponente validiert werden muss | |
Boolean – wenn true, gibt an, dass der Inhalt des vorangehenden Feldes auch auf der Client-Seite validiert werden muss | |
die Fehlermeldung, die die Komponente anzeigen soll, wenn ein Fehler erkannt wird | |
der Wert, mit dem der Wert des Feldes [ControlToValidate] verglichen werden muss | |
die Komponente, mit deren Wert der Wert des Feldes [ControlToValidate] verglichen werden muss | |
Vergleichsoperator zwischen den beiden Werten | |
Typ der zu vergleichenden Werte |
Der HTML-Code für diese 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=?, Type=string
- 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, Type=string
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 von Internet Explorer 6 aufgerufen, enthält sie JavaScript-Code, der zu einem leicht abweichenden Verhalten führt. Etwaige Fehler werden gemeldet, sobald der Benutzer einen Wert in einer der Dropdown-Listen ändert. Dies verbessert die Benutzererfahrung.
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 Client-Skript aktivieren=true Fehlermeldung=Ungültiges Diplom Operator=Nicht gleich ZuVergleichenderWert=? Typ=Zeichenkette | Validierungskomponente des Steuerelements [1] | ||
Textfeld | EnableViewState=false | Eingabefeld | ||
CustomValidator | EnableViewState=false Client-Skript aktivieren=true ErrorMessage=Ungültige Angabe des Abschlusses ClientValidationFunction=chkOtherDegree | Validierungskomponente für Feld [3] | ||
Textfeld | EnableViewState=false | Eingabefeld | ||
Bereichsprüfung | EnableViewState=false Client-Skript aktivieren=true ErrorMessage=Das Abschlussjahr muss im Bereich [1990,2004] liegen MinValue=1990 MaxValue=2004 Typ=Ganzzahl ControlToValidate=txtAnDiplome | Feldvalidierungskomponente [5] | ||
RequiredFieldValidator | EnableViewState=false Client-Skript aktivieren=true ErrorMessage=Abschlussjahr erforderlich Zu validierendes Steuerelement=txtAnDiplome | Feldvalidierungskomponente [5] | ||
Schaltfläche | EnableViewState=false ValidationReasons=true | [submit]-Schaltfläche |
Das Feld [RangeValidator] dient dazu, zu überprüfen, ob der Wert eines Steuerelements zwischen den beiden Grenzwerten [MinValue] und [MaxValue] liegt. Seine Eigenschaften sind wie folgt:
Feld, dessen Wert von der Komponente validiert werden muss | |
Boolean – Wenn „true“, gibt dies an, dass der Inhalt des vorherigen Feldes auch auf der Client-Seite validiert werden muss | |
Die Fehlermeldung, die die Komponente anzeigen soll, wenn ein Fehler erkannt wird | |
Mindestwert des zu validierenden Feldes | |
Maximalwert des zu prüfenden Feldes | |
Typ des zu validierenden Feldwerts |
Das Feld [CustomValidator] ermöglicht es Ihnen, Validierungen durchzuführen, die mit den von ASP.NET bereitgestellten Validierungskomponenten nicht möglich sind. Diese Validierung wird durch eine vom Entwickler geschriebene Funktion durchgeführt. Diese Funktion wird serverseitig ausgeführt. Da die Validierung auch clientseitig durchgeführt werden kann, muss der Entwickler möglicherweise eine JavaScript-Funktion entwickeln, die in das HTML-Dokument eingebunden wird. Die Eigenschaften lauten wie folgt:
Das Feld, dessen Wert von der Komponente validiert werden muss | |
Boolean – Wenn „true“, gibt dies an, dass der Inhalt des vorherigen Feldes auch auf der Clientseite validiert werden muss | |
Die Fehlermeldung, die die Komponente anzeigen soll, wenn ein Fehler erkannt wird | |
Die Funktion, die auf der Clientseite ausgeführt werden soll |
Der Code der Seitenvorlage 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] können Sie die Funktion angeben, 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)
' field [txtAutreDiplome] must be non-empty if [cmbDiplomes]=[other]
e.isvalid=not (cmbDiplomes.selecteditem.text="[Autre]" and txtAutreDiplome.text.trim="") _
and not (cmbDiplomes.selecteditem.text<>"[Autre]" and cmbDiplomes.selecteditem.text<>"?" and txtAutreDiplome.text.trim<>"")
End Sub
</script>
....
Eine Validierungsfunktion, die einer [CustomValidator]-Komponente zugeordnet ist, erhält zwei Parameter:
- sender: das Objekt, das das Ereignis ausgelöst hat
- e: das Ereignis. Die Prozedur muss die Eigenschaft [e.IsValid] auf „true“ setzen, wenn die validierten Daten korrekt sind, andernfalls auf „false“.
Hier werden die folgenden Prüfungen durchgeführt:
- Die Dropdown-Liste [cmbDiplomes] darf nicht den Wert [?] enthalten. Dies wird von der Komponente [CompareValidator2] überprüft
- Der Benutzer wählt einen Abschluss aus der Dropdown-Liste [cmbDiplomes] aus. Wenn sein Abschluss nicht in der Liste vorhanden ist, kann er die Option [Other] aus der Liste auswählen. Er muss dann seinen Abschluss in das Eingabefeld [txtAutreDiplome] eingeben. Wenn in [cmbDiplomes] die Option [Other] ausgewählt ist, darf das Feld [txtAutreDiplome] nicht leer sein. Wenn in [cmbDiplomes] weder [Other] noch [?] ausgewählt ist, muss das Feld [txtAutreDiplome] leer sein. Dies wird durch die mit der Komponente [CustomValidator1] verknüpfte Funktion überprüft.
- Das Jahr, in dem der Abschluss erworben wurde, muss im Bereich [1900-2004] liegen. Dies wird durch [RangeValidator1] überprüft. Wenn der Benutzer das Feld jedoch leer lässt, wird die Validierungsfunktion von [RangeValidator1] nicht verwendet. Daher fügen wir die Komponente [RequiredFieldValidator2] zu [ ] hinzu, um das Vorhandensein von Inhalt zu prüfen. Dies ist eine allgemeine Regel. Der Inhalt eines Feldes wird nicht geprüft, wenn es leer ist. Der einzige Fall, in dem er geprüft wird, ist, wenn er mit einer [RequiredFieldValidator]-Komponente verknüpft ist.
Hier ist ein Beispiel für die Ausführung im [Mozilla]-Browser:

Wenn wir den [IE6]-Browser verwenden, können wir eine clientseitige Validierungsfunktion für die Komponente [CustomValidator1] hinzufügen. Dazu verfügt diese Komponente über die folgenden 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){
// vérifie la validité du champ txtAutreDiplome
with(document.frmCandidature){
diplome=cmbDiplomes.options[cmbDiplomes.selectedIndex].text;
args.IsValid= !(diplome=="[Autre]" && txtAutreDiplome.value=="")
&& ! (diplome!="[Autre]" && diplome!="?" && txtAutreDiplome.value!="");
}
}
</script>
</head>
Die Funktion [chkAutreDiplome] erhält dieselben zwei Parameter wie die Serverfunktion [CustomValidator1_ServerValidate_1]:
- source: das Objekt, das das Ereignis ausgelöst hat
- args: das Ereignis. Dieses verfügt über ein [IsValid]-Attribut, das von der Funktion auf „true“ gesetzt werden muss, wenn die validierten Daten korrekt sind. Bei einem Wert von „false“ wird die zugehörige Fehlermeldung an der Stelle der Validierungskomponente angezeigt, und das Formular wird nicht an den Server übermittelt.
8.2.5. RegularExpressionValidator
Wir erstellen die folgende Seite [regularexpressionvalidator1.aspx]:

Nr. | name | Typ | Eigenschaften | Rolle |
Textfeld | EnableViewState=true | Eingabefeld | ||
RequiredFieldValidator | Zu validierendes Steuerelement=txtMel Anzeige=Dynamisch | Steuerelement-Validierungskomponente [1] | ||
RegularExpressionValidator | Zu validierendes Steuerelement=txtMel Anzeige=Dynamisch | Komponente zur Steuerelementvalidierung [1] | ||
Schaltfläche | EnableViewState=false CausesValidation=true | [submit]-Schaltfläche |
Hier möchten wir das Format einer E-Mail-Adresse validieren. Dazu verwenden wir eine [RegularExpressionValidator]-Komponente, mit der wir ein Feld anhand eines regulären Ausdrucks validieren können. Denken Sie daran, dass ein regulärer Ausdruck ein Muster aus Zeichen ist. Wir prüfen daher den Inhalt eines Feldes anhand eines Musters. Da der Inhalt eines Feldes nicht geprüft wird, wenn es leer ist, benötigen wir zusätzlich eine [RequiredFieldValidator]-Komponente, um sicherzustellen, dass die E-Mail-Adresse nicht leer ist. Die [RegularExpressionValidator]-Klasse verfügt über Eigenschaften, die denen der bereits behandelten Komponentenklassen ähneln:
Feld, dessen Wert von der Komponente validiert werden muss | |
boolescher Wert – wenn „true“, gibt dies an, dass der Inhalt des vorherigen Feldes ebenfalls auf der Clientseite validiert werden muss | |
die Fehlermeldung, die die Komponente anzeigen soll, wenn ein Fehler erkannt wird | |
der reguläre Ausdruck, mit dem der Inhalt von [ControlToValidate] verglichen wird | |
Anzeigemodus: Statisch: Das Feld ist immer vorhanden, auch wenn keine Fehlermeldung angezeigt wird; Dynamisch: Das Feld ist nur vorhanden, wenn eine Fehlermeldung vorliegt; Keine: Die Fehlermeldung wird nicht angezeigt. Dieses Feld existiert auch für andere Komponenten, wurde jedoch bisher nicht verwendet. |
Das reguläre Ausdrucksmuster 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...]. Vor dem @-Zeichen muss mindestens ein Feld und danach mindestens zwei Felder vorhanden sein. Diese Felder bestehen aus alphanumerischen Zeichen und dem Zeichen -. Ein alphanumerisches Zeichen wird durch das Symbol \w dargestellt. Die Sequenz [\w-] bedeutet das Zeichen \w oder das Zeichen -. Das +-Zeichen nach einer Sequenz S bedeutet, dass diese 1 oder mehrmals wiederholt werden kann; das *-Zeichen bedeutet, dass sie 0 oder mehrmals wiederholt werden kann; das ?-Zeichen bedeutet, dass sie 0 oder 1 Mal wiederholt werden kann.
Ein Feld in der E-Mail-Adresse entspricht dem Muster [\w-]+. Die Tatsache, dass vor dem @-Zeichen mindestens ein Feld und danach mindestens zwei Felder stehen müssen, die durch das .-Zeichen getrennt sind, entspricht dem Muster: [\w-]+(\.[\w-]+)*@[\w-]+(\.[\w-]+)+. Wir können dem Benutzer erlauben, Leerzeichen vor und nach der Adresse einzufügen. Diese werden bei der Verarbeitung entfernt. Eine Folge von Leerzeichen, die leer sein kann, wird durch das Muster \s* dargestellt. Daher lautet der reguläre Ausdruck für die E-Mail-Adresse: \s*[\w-]+(\.[\w-]+)*@[\w-]+(\.[\w-]+)+\s*.
Der Code für das Seitenlayout 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 möchten Sie Fehlermeldungen möglicherweise an einer einzigen Stelle zusammenfassen, wie im folgenden Beispiel [summaryvalidator1.aspx], in dem wir alle vorherigen Beispiele auf einer einzigen Seite zusammengefasst haben:

Alle Validierungssteuerelemente verfügen über die folgenden Eigenschaften:
- [Display=Dynamic], wodurch sichergestellt wird, dass die Steuerelemente keinen Platz auf der Seite beanspruchen, wenn ihre Fehlermeldung leer ist
- [EnableClientScript=false], um die gesamte clientseitige Validierung zu deaktivieren
- [Text=*]. Dies ist die Meldung, die im Fehlerfall angezeigt wird, während der Inhalt des Attributs [ErrorMessage] durch das unten gezeigte [ValidationSummary]-Steuerelement angezeigt wird.
Diese Steuerelemente werden in einer [Panel]-Komponente namens [vueFormulaire] platziert. In einer weiteren [Panel]-Komponente namens [vueErreurs] platzieren wir ein [ValidationSummary]-Steuerelement:

Nr. | name | Typ | Eigenschaften | Rolle |
1 | Validierungszusammenfassung | HeaderText=Die folgenden Fehler sind aufgetreten, EnableClientScript=false, ShowSummary=true | zeigt Fehler aus allen Validierungssteuerelementen auf der Seite an | |
2 | LinkButton | ValidationCauses=false | Link zurück zum Formular |
Für den Link [lnkErrorsToForm] muss die Validierung nicht aktiviert werden, da dieser Link keine zu prüfenden Werte übermittelt.
Wenn alle Daten gültig sind, wird dem Benutzer die folgende [info]-Ansicht angezeigt:

1
Nr. | Name | Typ | Eigenschaften | Rolle |
1 | Beschriftung | Informationsmeldung für den Benutzer |
Der HTML-Code für diese 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 senden die [Formular]-Ansicht ab, ohne Werte einzugeben:

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

Die Ansicht [errors] wurde angezeigt. Wenn wir den Link verwenden, um zum Formular zurückzukehren, finden wir es in folgendem Zustand vor:

Dies ist die Ansicht [form]. Beachten Sie das Zeichen [*] neben den fehlerhaften Daten. Dies ist das Feld [Text] der Validierungssteuerelemente, das angezeigt wurde. Wenn wir die Felder korrekt ausfüllen, erhalten wir die Ansicht [info]:

Der Code für das Seitensteuerelement lautet wie folgt:
<%@ Page Language="VB" %>
<script runat="server">
' procedure executed when the page is loaded
Sub page_Load(sender As Object, e As EventArgs)
' on the 1st request, we present the [form] view
if not ispostback then
afficheVues(true,false,false)
end if
end sub
sub afficheVues(byval formulaireVisible as boolean, _
erreursVisible as boolean, infosVisible as boolean)
' set of views
vueFormulaire.visible=formulaireVisible
vueErreurs.visible=erreursVisible
vueInfos.visible=infosVisible
end sub
Sub CustomValidator1_ServerValidate(sender As Object, e As ServerValidateEventArgs)
...
End Sub
Sub CustomValidator2_ServerValidate(sender As Object, e As ServerValidateEventArgs)
...
End Sub
Sub CustomValidator1_ServerValidate_1(sender As Object, e As ServerValidateEventArgs)
...
End Sub
Sub lnkErreursToFormulaire_Click(sender As Object, e As EventArgs)
' displays the form view
afficheVues(true,false,false)
' redo validity checks
Page.validate
End Sub
Sub btnEnvoyer_Click(sender As Object, e As EventArgs)
' is the page valid?
if not Page.IsValid then
' the [errors] view is displayed
afficheVues(false,true,false)
else
' otherwise the view [infos]
lblInfo.Text="Le dossier de candidature au DESS IAIE a été envoyé à l'adresse ["+ _
txtMel.Text + "]. Nous vous en souhaitons bonne réception.<br><br>Le secrétariat du DESS."
afficheVues(false,false,true)
end if
end sub
</script>
<html>
...
</html>
- In der Prozedur [Page_Load], die bei jeder Client-Anfrage ausgeführt wird, zeigen wir die Ansicht [form] an, während die anderen ausgeblendet werden. Dies geschieht nur bei der ersten Anfrage. Die Prozedur ruft eine Hilfsprozedur [displayViews] auf, an die wir drei boolesche Werte übergeben, um zu bestimmen, ob die drei Ansichten angezeigt werden sollen oder nicht.
- Wenn die Prozedur [btnEnvoyer_Click] aufgerufen wird, wurde die Datenvalidierung bereits durchgeführt. Die Schaltfläche [btnEnvoyer] verfügt über die Eigenschaft [CausesValidation=true], die diese Datenvalidierung auslöst. Alle Validierungssteuerelemente wurden ausgeführt, und ihre Eigenschaft [IsValid] wurde gesetzt. Diese Eigenschaft gibt an, ob die vom Steuerelement validierten Daten gültig waren oder nicht. Darüber hinaus wurde auch die Eigenschaft [IsValid] der Seite selbst gesetzt. Sie ist nur dann [true], wenn die Eigenschaft [IsValid] aller Validierungssteuerelemente auf der Seite den Wert [true] hat. Daher beginnt die Prozedur [btnEnvoyer_Click] damit, zu prüfen, ob die Seite gültig ist oder nicht. Ist sie ungültig, wird die Ansicht [errors] angezeigt. Diese Ansicht enthält das Steuerelement [ValidationSummary], das die [ErrorMessage]-Attribute aller Steuerelemente auflistet (siehe Screenshot oben). Ist die Seite gültig, wird die Ansicht [info] zusammen mit einer Informationsmeldung angezeigt.
- Die Prozedur [lnkErrorsToForm_Click] ist dafür zuständig, die Ansicht [form] in dem Zustand anzuzeigen, in dem sie validiert wurde. Da alle Eingabefelder in der Ansicht [form] die Eigenschaft [EnableViewState=true] haben, wird ihr Zustand automatisch neu generiert. Seltsamerweise wird der Zustand der Validierungskomponenten nicht wiederhergestellt. Man könnte erwarten, dass bei der Rückkehr zur Ansicht [errors] die ungültigen Steuerelemente ihr Feld [Text] anzeigen. Dies ist jedoch nicht der Fall. Wir haben daher die Datenvalidierung mithilfe der [Page.Validate]-Methode der Seite erzwungen. Dies muss erfolgen, sobald das [formView]-Panel sichtbar gemacht wurde. Es gibt somit insgesamt zwei Validierungen. Dies sollte in der Praxis vermieden werden. An dieser Stelle ermöglichte uns das Beispiel, neue Konzepte zur Seitenvalidierung vorzustellen.
8.3. ListControl-Komponenten und Datenbindung
Einige der behandelten Serverkomponenten ermöglichen es Ihnen, eine Liste von Werten anzuzeigen (DropDownList, ListBox). Andere, die wir noch nicht behandelt haben, ermöglichen es Ihnen, mehrere Listen von Werten in HTML-Tabellen anzuzeigen. Bei allen ist es möglich, die Werte in den Listen programmgesteuert einzeln mit der entsprechenden Komponente zu verknüpfen. Es ist auch möglich, komplexere Objekte mit diesen Komponenten zu verknüpfen, wie z. B. Objekte vom Typ [Array], [ArrayList], [DataSet], [HashTable] usw., was den Code vereinfacht, der die Daten mit der Komponente verknüpft. Diese Verknüpfung wird als Datenbindung bezeichnet.
Alle von der Klasse [ListControl] abgeleiteten Komponenten können mit einer Datenliste verknüpft werden. Dazu gehören die Komponenten [DropDownList], [ListBox], [CheckButtonList] und [RadioButtonList]. Jede dieser Komponenten kann an eine Datenquelle gebunden werden. Dies kann verschiedene Formen annehmen: [Array], [ArrayList], [DataTable], [DataSet], [HashTable], … im Allgemeinen ein Objekt, das eine der Schnittstellen IEnumerable, ICollection oder IListSource implementiert. Wir werden hier nur einige davon vorstellen. Ein [DataSet]-Objekt ist eine Darstellung einer relationalen Datenbank. Es handelt sich also um eine Menge von Tabellen, die durch Beziehungen miteinander verknüpft sind. Das [DataTable]-Objekt repräsentiert eine solche Tabelle. Die Datenquelle legt die Eigenschaften [Text] und [Value] jedes [Item] im [ListControl]-Objekt fest. Wenn T der Wert von [Text] und V der Wert von [Value] ist, lautet der für jedes Element von [ListControl] generierte HTML-Tag wie folgt:
<option value="V">T</option> | |
<input type="checkbox" value="V">T | |
<input type="radio" value="V">T |
Eine [ListControl]-Komponente wird über die folgenden Eigenschaften mit einer Datenquelle verknüpft:
eine Datenquelle [Array], [ArrayList], [DataTable], [DataSet], [HashTable], ... | |
Wenn die Datenquelle ein [DataSet] ist, stellt dies den Namen der Tabelle dar, die als Datenquelle verwendet werden soll. Die eigentliche Datenquelle ist dann eine Tabelle. | |
Wenn die Datenquelle eine Tabelle ist ([DataTable], [DataSet]), stellt dies den Namen der Tabellenspalte dar, die Werte für das [Text]-Feld der [ListControl]-Elemente bereitstellt | |
Wenn die Datenquelle eine Tabelle ist ([DataTable], [DataSet]), steht dies für den Namen der Tabellenspalte, die Werte für das [Value]-Feld der [ListControl]-Elemente bereitstellt |
Das Binden einer [ListControl]-Komponente an eine Datenquelle initialisiert die Komponente nicht mit den Werten aus der Datenquelle. Dies erfolgt durch die Operation [ListControl].DataBind.
Je nach Art der Datenquelle erfolgt die Bindung an eine [ListControl]-Komponente auf unterschiedliche Weise:
[ListControl].DataSource=A Die Felder [Text] und [Value] der [ListControl]-Elemente enthalten die Werte der Elemente in A | |
[ListControl].DataSource=AL Die Felder [Text] und [Value] der [ListControl]-Elemente enthalten die Werte der Elemente in AL | |
[ListControl].DataSource = DT, [ListControl].DataTextField = "col1", [ListControl].DataValueField = "col2" wobei col1 und col2 zwei Spalten in der DT-Tabelle sind. Die Felder [Text] und [Value] der [ListControl]-Elemente enthalten die Werte der Spalten col1 und col2 in der DT-Tabelle | |
[ListControl].DataSource=DS, [ListControl].DataSource="table", wobei „table“ der Name einer der Tabellen in DS ist. [ListControl].DataTextField = „col1“, [ListControl].DataValueField = „col2“, wobei col1 und col2 zwei Spalten der Tabelle „table“ sind. Die Felder [Text] und [Value] der [ListControl]-Elemente enthalten die Werte der Spalten col1 und col2 der Tabelle „table“ | |
[ListControl].DataSource = HT, [ListControl].DataTextField = "key", [ListControl].DataValueField = "value", wobei [key] und [value] die Schlüssel bzw. Werte von HT sind. |
Wir wenden diese Informationen auf das folgende Beispiel [databind1.aspx] an:
![]() |
Hier haben wir fünf Datenbindungen, jede mit vier Steuerelementen der Typen [DropDownList], [ListBox], [CheckBoxList] und [RadioButtonList]. Die fünf untersuchten Bindungen unterscheiden sich in ihren Datenquellen:
Bindung | Datenquelle |
Array | |
ArrayList | |
DataTable | |
DataSet | |
HashTable |
8.3.1. Code zur Darstellung der Komponente
Der Präsentationscode für die Steuerelemente in Bindung 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 Bindung für die Bindungen 2 bis 5 ist bis auf die Bindungsnummer identisch.
8.3.2. Bindung an eine Array-Datenquelle
Die Bindung der vier oben genannten [ListBox]-Steuerelemente erfolgt wie folgt in der [Page_Load]-Prozedur des Steuerelementcodes:
' global data
dim textes() as string={"un","deux","trois","quatre"}
dim valeurs() as string={"1","2","3","4"}
dim myDataListe as new ArrayList
dim myDataTable as new DataTable("table1")
dim myDataSet as new DataSet
dim myHashTable as new HashTable
' procedure executed when the page is loaded
Sub page_Load(sender As Object, e As EventArgs)
if not IsPostBack then
' create the data sources to be linked to the components
createDataSources
' link to an array [Array]
bindToArray
' link to a list [ArrayList]
bindToArrayList
' link to a table [DataTable]
bindToDataTable
' link to a data group [DataSet]
bindToDataSet
' link to a dictionary [HashTable]
bindToHashTable
end if
End Sub
sub createDataSources
' creates data sources to be linked to components
' arraylist
dim i as integer
for i=0 to textes.length-1
myDataListe.add(textes(i))
next
' datatable
' we define its two columns
myDataTable.Columns.Add("id",Type.GetType("System.Int32"))
myDataTable.Columns.Add("texte",Type.GetType("System.String"))
' fill the table
dim ligne as DataRow
for i=0 to textes.length-1
ligne=myDataTable.NewRow
ligne("id")=i
ligne("texte")=textes(i)
myDataTable.Rows.Add(ligne)
next
' dataset - a single table
myDataSet.Tables.Add(myDataTable)
' hashtable
for i=0 to textes.length-1
myHashTable.add(valeurs(i),textes(i))
next
end sub
' panel connection
sub bindToArray
' association with components
with DropDownList1
.DataSource=textes
.DataBind
end with
with ListBox1
.DataSource=textes
.DataBind
end with
with CheckBoxList1
.DataSource=textes
.DataBind
end with
with RadioButtonList1
.DataSource=textes
.DataBind
end with
' item selection
ListBox1.Items(1).Selected=true
ListBox1.Items(3).Selected=true
CheckBoxList1.Items(0).Selected=true
CheckBoxList1.Items(3).Selected=true
DropDownList1.SelectedIndex=2
RadioButtonList1.SelectedIndex=1
end sub
sub bindToArrayList
....
end sub
sub bindToDataTable
...
end sub
sub bindToDataSet
...
end sub
Die Steuerelemente werden hier nur bei der ersten Anforderung an die Daten gebunden. Danach behalten die Steuerelemente ihre Elemente über den [VIEWSTATE]-Mechanismus bei. Die Bindung erfolgt in der Prozedur [bindToArray]. Da die Datenquelle vom Typ [Array] ist, wird nur das Feld [DataSource] der [ListControl]-Komponenten initialisiert. Das Steuerelement wird mithilfe der Methode [ListControl].DataBind mit Werten aus der zugehörigen Datenquelle gefüllt. Erst dann verfügen die [ListControl]-Objekte über Elemente. Sie können dann einige davon auswählen.
8.3.3. Bindung an eine ArrayList-Datenquelle
Die Datenquelle [myDataList] wird in der Prozedur [createDataSources] initialisiert:
' global data
dim textes() as string={"un","deux","trois","quatre"}
dim myDataListe as new ArrayList
..
' procedure executed when the page is loaded
Sub page_Load(sender As Object, e As EventArgs)
if not IsPostBack then
' create the data sources to be linked to the components
createDataSources
...
end if
End Sub
sub createDataSources
' creates data sources to be linked to components
' arraylist
dim i as integer
for i=0 to textes.length-1
myDataListe.add(textes(i))
next
...
end sub
Die Bindung der vier [ListBox]-Steuerelemente in Bindung 2 erfolgt wie folgt in der Prozedur [bindToArrayList] des Steuerelementcodes:
' liaison arraylist
sub bindToArrayList
' l'association aux composants
with DropDownList2
.DataSource=myDataListe
.DataBind
end with
with ListBox2
.DataSource=myDataListe
.DataBind
end with
with CheckBoxList2
.DataSource=myDataListe
.DataBind
end with
with RadioButtonList2
.DataSource=myDataListe
.DataBind
end with
' la sélection des éléments
ListBox2.Items(1).Selected=true
ListBox2.Items(3).Selected=true
CheckBoxList2.Items(0).Selected=true
CheckBoxList2.Items(3).Selected=true
DropDownList2.SelectedIndex=2
RadioButtonList2.SelectedIndex=1
end sub
Da die Datenquelle vom Typ [ArrayList] ist, wird nur das Feld [DataSource] der [ListControl]-Komponenten initialisiert.
8.3.4. Datenquelle vom Typ DataTable
Die Datenquelle [myDataTable] wird in der Prozedur [createDataSources] initialisiert:
' global data
dim textes() as string={"un","deux","trois","quatre"}
dim myDataTable as new DataTable("table1")
...
' procedure executed when the page is loaded
Sub page_Load(sender As Object, e As EventArgs)
if not IsPostBack then
' create the data sources to be linked to the components
createDataSources
...
end if
End Sub
sub createDataSources
' creates data sources to be linked to components
...
' datatable
' we define its two columns
myDataTable.Columns.Add("id",Type.GetType("System.Int32"))
myDataTable.Columns.Add("texte",Type.GetType("System.String"))
' fill the table
dim ligne as DataRow
for i=0 to textes.length-1
ligne=myDataTable.NewRow
ligne("id")=i
ligne("texte")=textes(i)
myDataTable.Rows.Add(ligne)
next
...
end sub
Wir beginnen mit der Erstellung eines [DataTable]-Objekts mit zwei Spalten: [id] und [text]. Die Spalte [id] füllt das Feld [Value] der [ListControl]-Elemente, und die Spalte [text] füllt deren [Text]-Felder. Die [DataTable] mit zwei Spalten wird wie folgt erstellt:
myDataTable.Columns.Add("id",Type.GetType("System.Int32"))
myDataTable.Columns.Add("texte",Type.GetType("System.String"))
Wir erstellen somit eine Tabelle mit zwei Spalten:
- Die erste, „id“ genannt, ist vom Typ Integer
- die zweite, „text“ genannt, ist vom Typ String
Nachdem die Tabellenstruktur nun erstellt wurde, können wir sie mit dem folgenden Code füllen:
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 die Ganzzahlen [0,1,..,n], während die Spalte [text] die Werte aus dem Array [data] enthält. Sobald dies geschehen ist, wird die Tabelle [dataList] gefüllt. Die Bindung der vier [ListBox]-Steuerelemente in Bindung 3 erfolgt wie folgt in der Prozedur [bindToDataTable] des Steuerelementcodes:
sub bindToDataTable
' l'association aux composants
with DropDownList3
.DataSource=myDataTable
.DataValueField="id"
.DataTextField="texte"
.DataBind
end with
with ListBox3
.DataSource=myDataTable
.DataValueField="id"
.DataTextField="texte"
.DataBind
end with
with CheckBoxList3
.DataSource=myDataTable
.DataValueField="id"
.DataTextField="texte"
.DataBind
end with
with RadioButtonList3
.DataSource=myDataTable
.DataValueField="id"
.DataTextField="texte"
.DataBind
end with
' la sélection des éléments
ListBox3.Items(1).Selected=true
ListBox3.Items(3).Selected=true
CheckBoxList3.Items(0).Selected=true
CheckBoxList3.Items(3).Selected=true
DropDownList3.SelectedIndex=2
RadioButtonList3.SelectedIndex=1
end sub
Jede [ListControl]-Komponente wird an die Datenquelle [myDataTable] gebunden, indem für jede Komponente Folgendes festgelegt wird:
Die Tabelle [myDataTable] ist die Datenquelle. Die Spalte [id] dieser Tabelle füllt die [Value]-Felder der Komponentenelemente, während die Spalte [text] deren [Text]-Felder füllt.
8.3.5. Datenquelle vom Typ DataSet
Die Datenquelle [myDataSet] wird in der Prozedur [createDataSources] initialisiert:
' global data
dim myDataTable as new DataTable("table1")
dim myDataSet as new DataSet
...
' procedure executed when the page is loaded
Sub page_Load(sender As Object, e As EventArgs)
if not IsPostBack then
' create the data sources to be linked to the components
createDataSources
...
end if
End Sub
sub createDataSources
' creates data sources to be linked to components
' dataset - a single table
myDataSet.Tables.Add(myDataTable)
...
end sub
Ein [DataSet]-Objekt stellt eine Sammlung von [DataTable]-Tabellen dar. Wir fügen die zuvor erstellte [myDataTable] zum [DataSet] hinzu. Die Bindung der vier [ListBox]-Steuerelemente in Bindung 4 erfolgt wie folgt in der Prozedur [bindToDataSet] des Steuerelementcodes:
sub bindToDataSet
' l'association aux composants
with DropDownList4
.DataSource=myDataSet
.DataMember="table1"
.DataValueField="id"
.DataTextField="texte"
.DataBind
end with
with ListBox4
.DataSource=myDataSet
.DataMember="table1"
.DataValueField="id"
.DataTextField="texte"
.DataBind
end with
with CheckBoxList4
.DataSource=myDataSet
.DataMember="table1"
.DataValueField="id"
.DataTextField="texte"
.DataBind
end with
with RadioButtonList4
.DataSource=myDataSet
.DataMember="table1"
.DataValueField="id"
.DataTextField="texte"
.DataBind
end with
' la sélection des éléments
ListBox4.Items(1).Selected=true
ListBox4.Items(3).Selected=true
CheckBoxList4.Items(0).Selected=true
CheckBoxList4.Items(3).Selected=true
DropDownList4.SelectedIndex=2
RadioButtonList4.SelectedIndex=1
end sub
Jede [ListControl]-Komponente ist wie folgt mit der Datenquelle verknüpft:
Der Datensatz [myDataSet] ist die Datenquelle. Da er mehrere Tabellen enthalten kann, geben wir in [DataMember] den Namen der zu verwendenden Tabelle an. Die Spalte [id] dieser Tabelle füllt die [Value]-Felder der Komponentenelemente, während die Spalte [text] deren [Text]-Felder füllt.
8.3.6. HashTable-Datenquelle
Die Datenquelle [myHashTable] wird in der Prozedur [createDataSources] initialisiert:
' global data
dim textes() as string={"un","deux","trois","quatre"}
dim valeurs() as string={"1","2","3","4"}
dim myHashTable as new HashTable
...
' procedure executed when the page is loaded
Sub page_Load(sender As Object, e As EventArgs)
if not IsPostBack then
' create the data sources to be linked to the components
createDataSources
...
end if
End Sub
sub createDataSources
' creates data sources to be linked to components
...
' hashtable
for i=0 to textes.length-1
myHashTable.add(valeurs(i),textes(i))
next
end sub
Das Wörterbuch [myHashTable] kann als Tabelle mit zwei Spalten betrachtet werden, die „key“ und „value“ heißen. Die Spalte [key] stellt die Schlüssel des Wörterbuchs dar, und die Spalte [value] stellt die ihnen zugeordneten Werte dar. Hier besteht die Spalte [key] aus dem Inhalt des Arrays [values], und die Spalte [value] besteht aus dem Inhalt des Arrays [texts]. Die Bindung dieser Quelle an die Steuerelemente erfolgt in der Prozedur [bindToHashTable]:
sub bindToHashTable
' l'association aux composants
with DropDownList5
.DataSource=myHashTable
.DataValueField="key"
.DataTextField="value"
.DataBind
end with
with ListBox5
.DataSource=myHashTable
.DataValueField="key"
.DataTextField="value"
.DataBind
end with
with CheckBoxList5
.DataSource=myHashTable
.DataValueField="key"
.DataTextField="value"
.DataBind
end with
with RadioButtonList5
.DataSource=myHashTable
.DataValueField="key"
.DataTextField="value"
.DataBind
end with
' la sélection des éléments
ListBox5.Items(1).Selected=true
ListBox5.Items(3).Selected=true
CheckBoxList5.Items(0).Selected=true
CheckBoxList5.Items(3).Selected=true
DropDownList5.SelectedIndex=2
RadioButtonList5.SelectedIndex=1
end sub
Für jede Komponente wird die Bindung mit den folgenden Anweisungen hergestellt:
Die Datenquelle ist das Wörterbuch [myHashTable]. Die Steuerelementwerte werden von der Spalte [key] des Wörterbuchs bereitgestellt, der Text von der Spalte [value]. Die Wörterbuchelemente werden in der Reihenfolge der Schlüssel in die Steuerelemente eingefügt, die anfangs zufällig ist.
8.3.7. Anweisungen zum Importieren von Namespaces
Eine Reihe von Namespaces wird automatisch in eine ASP.NET-Seite importiert. Dies gilt jedoch nicht für „System.Data“, 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. DataGrid-Komponente und Datenbindung
Die [DataGrid]-Komponente ermöglicht es Ihnen, Daten in Tabellenform darzustellen, geht jedoch weit über eine einfache Anzeige hinaus:
- sie bietet die Möglichkeit, die „visuelle Darstellung“ der Tabelle präzise zu konfigurieren
- sie ermöglicht es Ihnen, die Datenquelle zu aktualisieren
Die [DataGrid]-Komponente ist sowohl leistungsstark als auch komplex. Wir werden sie Schritt für Schritt vorstellen.
8.4.1. Anzeigen einer Datenquelle vom Typ Array, ArrayList, DataTable oder DataSet
Mit der [DataGrid]-Komponente können Sie Datenquellen vom Typ [Array], [ArrayList], [DataTable] und [DataSet] in einer HTML-Tabelle anzeigen. Für diese vier Datentypen verknüpfen Sie die Quelle einfach mit der [DataSource]-Eigenschaft der [DataGrid]-Komponente:
eine Datenquelle [Array], [ArrayList], [DataTable], [DataSet], ... | |
Wenn die Datenquelle ein [DataSet] ist, stellt dies den Namen der Tabelle dar, die als Datenquelle verwendet werden soll. Die eigentliche Datenquelle ist dann eine Tabelle. Wenn dieses Feld leer gelassen wird, werden alle Tabellen im [DataSet] angezeigt. |
Wir stellen nun die Seite [datagrid1.aspx] vor, die ein [DataGrid] zeigt, das mit vier verschiedenen Datenquellen verknüpft ist:

Die Seite enthält vier [DataGrid]-Komponenten, die wie folgt mit [WebMatrix] erstellt wurden. Wir ziehen die Komponente an ihre Position auf der Registerkarte [Design]:

Anschließend wird eine generische HTML-Tabelle gezeichnet. Die Eigenschaften eines [DataGrid] können zur Entwurfszeit definiert 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 verwenden die beiden oben genannten Links. Der Link [Property Generator] bietet Zugriff auf die wichtigsten Eigenschaften des [DataGrid]:

Wir deaktivieren die Option [Show Header] für die vier [DataGrid]-Komponenten und speichern die Seite. Der andere Link, [Auto Format], ermöglicht es Ihnen, aus mehreren Stilen für die anzuzeigende HTML-Tabelle auszuwählen:

Wir wählen [color i] für [DataGrid] #i aus. Diese Designentscheidungen spiegeln sich im Darstellungscode der Seite wider:
<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 Steuerelementcode verknüpfen wir die Daten mit den vier Komponenten:
<%@ Page Language="VB" %>
<%@ import Namespace="system.data" %>
<script runat="server">
' global data
dim textes1() as string={"un","deux","trois","quatre"}
dim textes2() as string={"one","two","three","for"}
dim valeurs() as string={"1","2","3","4"}
dim myDataListe as new ArrayList
dim myDataTable as new DataTable("table1")
dim myDataSet as new DataSet
' procedure executed when the page is loaded
Sub page_Load(sender As Object, e As EventArgs)
if not IsPostBack then
' create the data sources to be linked to the components
createDataSources
' link to an array [Array]
bindToArray
' link to a list [ArrayList]
bindToArrayList
' link to a table [DataTable]
bindToDataTable
' link to a data group [DataSet]
bindToDataSet
end if
End Sub
sub createDataSources
' creates data sources to be linked to components
' arraylist
dim i as integer
for i=0 to textes1.length-1
myDataListe.add(textes1(i))
next
' datatable
' we define its two columns
myDataTable.Columns.Add("id",Type.GetType("System.Int32"))
myDataTable.Columns.Add("texte1",Type.GetType("System.String"))
myDataTable.Columns.Add("texte2",Type.GetType("System.String"))
' fill the table
dim ligne as DataRow
for i=0 to textes1.length-1
ligne=myDataTable.NewRow
ligne("id")=valeurs(i)
ligne("texte1")=textes1(i)
ligne("texte2")=textes2(i)
myDataTable.Rows.Add(ligne)
next
' dataset - a single table
myDataSet.Tables.Add(myDataTable)
end sub
' panel connection
sub bindToArray
with DataGrid1
.DataSource=textes1
.DataBind
end with
end sub
' arraylist link
sub bindToArrayList
with DataGrid2
.DataSource=myDataListe
.DataBind
end with
end sub
' datatable link
sub bindToDataTable
with DataGrid3
.DataSource=myDataTable
.DataBind
end with
end sub
' dataset link
sub bindToDataSet
with DataGrid4
.DataSource=myDataSet
.DataBind
end with
end sub
</script>
<html>
...
</html>
Der Code ähnelt stark dem im vorherigen Beispiel, daher werden wir nicht speziell darauf eingehen. Beachten Sie jedoch, wie die Datenbindung erfolgt. Für jedes der vier Steuerelemente reicht die folgende Sequenz aus:
wobei [Datenquelle] vom Typ [Array], [ArrayList], [DataTable] oder [DataSet] ist. Wir sehen also, dass dies ein leistungsstarkes Werkzeug zur Darstellung von Daten in Tabellen ist:
- Das Layout wird während der Entwurfsphase mit [WebMatrix] oder einer anderen IDE erstellt
- Die Datenbindung erfolgt im Code. Mit [WebMatrix] kann dies zur Entwurfszeit erfolgen, wenn es sich bei der Datenquelle um eine SQL Server-Datenbank oder eine Access-Datenbank handelt. In diesem Fall wird eine [SqlDataSource]- oder [AccessDataSource]-Komponente auf dem Formular platziert. Diese Komponente kann zur Entwurfszeit mit der physischen Datenquelle verknüpft werden, je nach Bedarf entweder mit einer SQL Server-Datenbank oder einer Access-Datenbank. Wenn Sie der [DataSource]-Eigenschaft einer [DataGrid]-Komponente ein mit einer physischen Quelle verknüpftes [SqlDataSource]- oder [AccessDataSource]-Objekt zuweisen, werden die tatsächlichen Daten im Entwurfsmodus in der [DataGrid]-Komponente angezeigt.
8.5. ViewState von Datenlistenkomponenten
Hier möchten wir den [VIEWSTATE]-Mechanismus für Datenlistenkomponenten hervorheben. Sie haben die Wahl zwischen zwei Methoden, um den Zustand einer Datenlistenkomponente zwischen zwei Client-Anfragen beizubehalten:
- das [VIEWSTATE]-Attribut auf „true“ setzen
- das [VIEWSTATE]-Attribut auf „false“ setzen und die Datenquelle in der Sitzung speichern, damit die Komponente bei der nächsten Anfrage mit dieser Quelle verknüpft werden kann.
Das folgende Beispiel veranschaulicht bestimmte Aspekte des [VIEWSTATE]-Mechanismus für Datencontainer. Bei der ersten Anfrage des Clients zeigt die Anwendung die folgende Ansicht an:
![]() |
Nr. | Name | Typ | Eigenschaften | Rolle |
1 | DataGrid | EnableViewState=true | zeigt eine Datenquelle S | |
2 | DataGrid | EnableViewState=true | zeigt dieselbe Datenquelle S an wie [DataGrid1] | |
3 | Button | EnableViewState=false | [Senden]-Schaltfläche |
Die Komponente [DataGrid1] wird durch den [VIEWSTATE]-Mechanismus verwaltet. Wir möchten feststellen, ob dieser Mechanismus, der die Anzeige von [DataGrid1] bei jeder Anfrage neu generiert, auch dessen Datenquelle neu generiert. Dazu wird die Datenquelle mit der Komponente [DataGrid2] verknüpft. Deren Generierung bei jeder Anfrage erfolgt über eine explizite Bindung an die Datenquelle von [DataGrid1]. Ihr Attribut [EnableViewState] ist ebenfalls auf [true] gesetzt.
Der Präsentationscode der Anwendung [main.aspx] 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] sieht wie folgt aus:
Imports System.Data
Public Class main
Inherits System.Web.UI.Page
Protected WithEvents DataGrid1 As System.Web.UI.WebControls.DataGrid
Protected WithEvents Datagrid2 As System.Web.UI.WebControls.DataGrid
Protected WithEvents Button1 As System.Web.UI.WebControls.Button
Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
' on the 1st query, the data source is defined and linked to the 1st datagrid
If Not IsPostBack Then
'define data source
With DataGrid1
.DataSource = createDataSource()
.DataBind()
End With
End If
' for each query, datagrid2 is linked to the source of the 1st datagrid
With Datagrid2
.DataSource = DataGrid1.DataSource
.DataBind()
End With
End Sub
Private Function createDataSource() As DataTable
' initialize the data source
Dim thèmes As New DataTable
' columns
With thèmes.Columns
.Add("id", GetType(System.Int32))
.Add("thème", GetType(System.String))
.Add("description", GetType(System.String))
End With
' column id will be primary key
thèmes.Constraints.Add("cléprimaire", thèmes.Columns("id"), True)
' lines
Dim ligne As DataRow
For i As Integer = 0 To 4
ligne = thèmes.NewRow
ligne.Item("id") = i.ToString
ligne.Item("thème") = "thème" + i.ToString
ligne.Item("description") = "description du thème " + i.ToString
thèmes.Rows.Add(ligne)
Next
Return thèmes
End Function
Private Sub InitializeComponent()
End Sub
End Class
Die Methode [createDataSource] erstellt eine Datenquelle S vom Typ [DataTable]. Wir werden nicht näher auf den Code eingehen, da er nicht im Mittelpunkt dieses Beispiels steht. Dies ist die Methode, mit der die beiden für uns interessanten [DataGrid]-Komponenten erstellt werden:
- Die [DataGrid1]-Komponente wird einmalig während der ersten Abfrage an die Tabelle S gebunden. Danach ist sie nicht mehr gebunden.
- Die Komponente [DataGrid2] wird bei jeder neuen Abfrage an die Quelle [DataGrid1.DataSource] gebunden.
Bei der ersten Abfrage erhalten wir folgende Ansicht:

Logischerweise zeigen beide Komponenten die Datenquelle an, mit der sie verknüpft wurden. Wir verwenden die Schaltfläche [Submit], um einen [PostBack] an den Server auszulösen. Die resultierende Ansicht sieht dann wie folgt aus:

Wir stellen fest, dass die [DataGrid1]-Komponente ihren Wert beibehalten hat, die [DataGrid2]-Komponente jedoch nicht. Erklärung:
- Noch bevor die [Page_Load]-Prozedur startet, haben die Objekte [DataGrid1] und [DataGrid2] aufgrund des [viewstate]-Mechanismus die Werte abgerufen, die sie bei der vorherigen Anfrage hatten. Tatsächlich ist bei beiden die Eigenschaft [EnableViewState] auf [true] gesetzt.
- Die [Page_Load]-Prozedur wird ausgeführt. Da es sich um einen [PostBack]-Vorgang handelt, wird die [DataGrid1]-Komponente durch [Page_Load] nicht verändert (siehe Code). Daher behält sie den über [viewstate] abgerufenen Wert bei. Dies zeigt der obige Bildschirm.
- Die Komponente [DataGrid2] hingegen ist über [DataBind] an die Datenquelle [DataGrid1.DataSource] gebunden. Sie wird daher neu aufgebaut, und der Wert, den sie gerade über [viewstate] abgerufen hatte, geht verloren. Es wäre daher hier von Vorteil gewesen, wenn ihre Eigenschaft [EnableViewState] auf [false] gesetzt worden wäre, um unnötige Zustandsverwaltung zu vermeiden. Der obige Bildschirm zeigt, dass [DataGrid2] an eine leere Quelle gebunden wurde. Da es sich bei dieser Quelle um [DataGrid1.DataSource] handelt, können wir daraus schließen, dass der [viewstate]-Mechanismus zwar die Anzeige der [DataGrid1]-Komponente erfolgreich wiederherstellt, jedoch nicht deren Eigenschaften wie [DataSource].
Was können wir aus diesem Beispiel schließen? Sie sollten es vermeiden, die Eigenschaft [EnableViewState] eines Datencontainers auf [true] zu setzen, wenn dieser bei jeder Anfrage an eine Datenquelle gebunden (DataBind) werden muss. Es gibt jedoch bestimmte Fälle, in denen selbst in diesem Szenario die Eigenschaft [EnableViewState] des Containers auf [true] gesetzt bleiben muss; andernfalls werden Ereignisse, die Sie behandeln möchten, nicht ausgelöst. Ein Beispiel hierfür werden wir später sehen.
Häufig ändert sich die Datenquelle eines Datencontainers im Laufe der Anfragen. Daher muss der Container bei jeder Anfrage an die Datenquelle gebunden werden. Es ist üblich, dass die Datenquelle auf die Sitzung beschränkt ist, damit Anfragen 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 | |
2 | DataGrid | EnableViewState=false | zeigt dieselbe Datenquelle S an wie [DataGrid1] | |
3 | Button | EnableViewState=false | [submit]-Schaltfläche | |
4 | Beschriftung | EnableViewState=false | Informationstext |
Die Komponente [DataGrid1] wird nur bei der ersten Anfrage an die Daten gebunden. Dank des [viewstate]-Mechanismus behält sie ihren Wert über mehrere Anfragen hinweg bei. Die Komponente [DataGrid2] wird bei jeder Anfrage an eine Datenquelle gebunden, zu der bei jeder neuen Anfrage ein Element hinzugefügt wird. Daher muss die Komponente [DataGrid2] bei jeder Anfrage gebunden (DataBind) werden. Wir haben daher ihr Attribut [EnableViewState] wie zuvor empfohlen auf [false] gesetzt. So erhalten wir bei der zweiten Anfrage (über die Schaltfläche [Submit]) die folgende Antwort:

Die [DataGrid1]-Komponente hat ihren ursprünglichen Wert beibehalten. Die [DataGrid2]-Komponente enthält ein weiteres Element. Die drei Werte [1,2,2] stellen die Abfragenummer dar. Wir können sehen, dass einer der Werte falsch ist. Wir werden versuchen zu verstehen, warum.
Der Präsentationscode der Anwendung [main.aspx] 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 Controller-Code [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
' on the 1st query, the data source is defined and linked to the 1st datagrid
If Not IsPostBack Then
'define data source
dtThèmes = createDataSource()
With DataGrid1
.DataSource = dtThèmes
.DataBind()
End With
' store information in the session
Session("source") = dtThèmes
numRequête1 = 0 : Session("numRequête1") = numRequête1
numRequête2 = 0 : Session("numRequête2") = numRequête2
numRequête3.valeur = 0 : Session("numRequête3") = numRequête3
End If
' a new theme is added to each query
dtThèmes = CType(Session("source"), DataTable)
Dim nbThèmes = dtThèmes.Rows.Count
Dim ligne As DataRow = dtThèmes.NewRow
With ligne
.Item("id") = nbThèmes.ToString
.Item("thème") = "thème" + nbThèmes.ToString
.Item("description") = "description du thème " + nbThèmes.ToString
End With
dtThèmes.Rows.Add(ligne)
'links datagrid2 with the data source
With Datagrid2
.DataSource = dtThèmes
.DataBind()
End With
' info no. of requests
numRequête1 = CType(Session("numRequête1"), Integer)
numRequête1 += 1
lblInfo1.Text = numRequête1.ToString
numRequête2 = CType(Session("numRequête2"), Integer)
numRequête2 += 1
lblInfo2.Text = numRequête2.ToString
numRequête3 = CType(Session("numRequête3"), entier)
numRequête3.valeur += 1
lblInfo3.Text = numRequête3.valeur.ToString
' store some information in the session
Session("numRequête2") = numRequête2
End Sub
Private Function createDataSource() As DataTable
....
End Function
End Class
Public Class entier
Private _valeur As Integer
Public Property valeur() As Integer
Get
Return _valeur
End Get
Set(ByVal Value As Integer)
_valeur = Value
End Set
End Property
End Class
Wir haben den Code für die Methode [createDataSource] nicht wiedergegeben. Er entspricht dem der vorherigen Anwendung, mit der Ausnahme, dass der Quellcode nur drei Zeilen umfasst. Schauen wir uns zunächst an, wie die Datenquelle und die beiden Container verwaltet werden:
Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
' on the 1st query, the data source is defined and linked to the 1st datagrid
If Not IsPostBack Then
'define data source
dtThèmes = createDataSource()
With DataGrid1
.DataSource = dtThèmes
.DataBind()
End With
' store information in the session
Session("source") = dtThèmes
...
End If
' a new theme is added to each query
dtThèmes = CType(Session("source"), DataTable)
Dim nbThèmes = dtThèmes.Rows.Count
Dim ligne As DataRow = dtThèmes.NewRow
With ligne
.Item("id") = nbThèmes.ToString
.Item("thème") = "thème" + nbThèmes.ToString
.Item("description") = "description du thème " + nbThèmes.ToString
End With
dtThèmes.Rows.Add(ligne)
'links datagrid2 with the data source
With Datagrid2
.DataSource = dtThèmes
.DataBind()
End With
...
End Sub
Die Komponente [DataGrid1] wird nur während der ersten Abfrage (nicht bei IsPostBack) an die Datenquelle S gebunden. Anschließend wird sie in die Sitzung aufgenommen. Danach wird sie nicht erneut dort abgelegt. Die in der Sitzung abgelegte Datenquelle S wird bei jeder Anfrage abgerufen, und eine neue Zeile wird hinzugefügt. Die Komponente [DataGrid2] wird bei jeder Anfrage explizit an die Quelle S gebunden. Deshalb erhöht sich ihr Inhalt bei jeder Anfrage um eine Zeile. Beachten Sie, dass die Quelle S nach einer Änderung ihres Inhalts nicht explizit über eine Operation wieder in die Sitzung zurückgelegt wird:
Warum? Zu Beginn einer Abfrage enthält die Sitzung ein Session("source")-Objekt vom Typ [DataTable], das der Datenquelle entspricht, wie sie bei der letzten Abfrage vorlag. Nennen wir das Session("source")-Objekt S. Wenn wir schreiben:
dtThèmes = CType(Session("source"), DataTable)
sind [dtThèmes] und [S] zwei Verweise auf dasselbe [DataTable]-Objekt. Wenn also der Code in [Page_Load] ein Element zur Tabelle hinzufügt, auf die [dtThèmes] verweist, fügt er es gleichzeitig zur Tabelle hinzu, auf die [S] verweist. Am Ende der Ausführung der Seite werden alle Objekte in der Sitzung gespeichert, einschließlich des Objekts Session("source"), d. h. S, d. h. [dtThemes]. Somit wird tatsächlich der neue Inhalt der Datenquelle gespeichert. Es war nicht notwendig zu schreiben:
um diese Speicherung durchzuführen, da Session("source") bereits gleich [dtThèmes] ist. Dies gilt nicht mehr, wenn die in der Sitzung platzierten Daten keine Objekte sind, wie beispielsweise die Strukturen [Integer, Float, ...]. Dies wird durch die Verwaltung des Abfragezählers veranschaulicht:
Dim numRequête1 As Integer
Dim numRequête2 As Integer
Dim numRequête3 As New entier
Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
' on the 1st query, the data source is defined and linked to the 1st datagrid
....
' store information in the session
Session("source") = dtThèmes
numRequête1 = 0 : Session("numRequête1") = numRequête1
numRequête2 = 0 : Session("numRequête2") = numRequête2
numRequête3.valeur = 0 : Session("numRequête3") = numRequête3
End If
' a new theme is added to each query
....
' info no. of requests
numRequête1 = CType(Session("numRequête1"), Integer)
numRequête1 += 1
lblInfo1.Text = numRequête1.ToString
numRequête2 = CType(Session("numRequête2"), Integer)
numRequête2 += 1
lblInfo2.Text = numRequête2.ToString
numRequête3 = CType(Session("numRequête3"), entier)
numRequête3.valeur += 1
lblInfo3.Text = numRequête3.valeur.ToString
' store some information in the session
Session("numRequête2") = numRequête2
End Sub
Private Function createDataSource() As DataTable
....
End Function
Private Sub InitializeComponent()
End Sub
End Class
Public Class entier
Private _valeur As Integer
Public Property valeur() As Integer
Get
Return _valeur
End Get
Set(ByVal Value As Integer)
_valeur = Value
End Set
End Property
Wir speichern die Anforderungszähler in drei Elementen:
- numRequest1 und numRequest2 vom Typ [Integer] – [Integer] ist keine Klasse, sondern eine Struktur
- numRequest3 vom Typ [integer] – [integer] ist eine für diesen Zweck definierte Klasse
Wenn wir schreiben:
numRequête1 = CType(Session("numRequête1"), Integer)
..
numRequête2 = CType(Session("numRequête2"), Integer)
..
numRequête3 = CType(Session("numRequête3"), entier)
..
- Die Struktur [Session("numRequest1")] wird in [numRequest1] kopiert. Wenn also das Element [numRequest1] geändert wird, wird das Element [Session("numRequest1")] selbst nicht
- Das Gleiche gilt für [Session("numRequest2")] und [numRequest2]
- Die Elemente [Session("numRequête3")] und [numRequête3] sind beide Verweise auf dasselbe Objekt vom Typ [integer]. Das referenzierte Objekt kann über jeden der beiden Verweise geändert werden.
Daraus lässt sich schließen, dass es unnötig ist, Folgendes zu schreiben:
um den neuen Wert von [numRequest3] in der Sitzung zu speichern. Stattdessen sollten Sie 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 im Screenshot nach der zweiten Abfrage der Zähler [numRequête1] falsch ist.
Es ist daher zu beachten, dass Daten, sobald sie einer Sitzung hinzugefügt wurden, nicht wiederholt hinzugefügt werden müssen, wenn sie durch ein Objekt repräsentiert werden. In anderen Fällen müssen sie hinzugefügt werden, wenn sie geändert wurden.
8.6. Anzeigen einer Datenliste mithilfe eines paginierten und sortierten DataGrid
Die [DataGrid]-Komponente ermöglicht es Ihnen, den Inhalt eines [DataSet] anzuzeigen. Bisher haben wir unsere [DataSets] immer „von Hand“ erstellt. Dieses Mal verwenden wir ein [DataSet] aus einer Datenbank. Wir erstellen die folgende MVC-Anwendung:
![]() |
Die drei Ansichten werden als Container in den Präsentationscode des [main.aspx]-Controllers eingebunden. Daher besteht diese Anwendung aus einer einzigen Seite, [main.aspx].
8.6.1. Die Business-Klassen
Die Klasse [products] bietet Zugriff auf die folgende ACCESS-Datenbank:

Der Code für die Klasse [products] 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)
' save the connection string
Me.chaineConnexionOLEDB = chaineConnexionOLEDB
End Sub
Public Function getDataSet(ByVal commande As String) As DataSet
' create a DataAdapter object to read data from source OLEDB
Dim adaptateur As New OleDbDataAdapter(commande, chaineConnexionOLEDB)
' create a memory image of the select result
Dim contenu As New DataSet
Try
adaptateur.Fill(contenu)
Catch e As Exception
Throw New Exception("Erreur d'accès à la base de données (" + e.Message + ")")
End Try
' we return the result
Return contenu
End Function
End Class
End Namespace
Die ACCESS-Datenbank wird über einen OLEDB-Treiber verwaltet. Wir übergeben dem Konstruktor der Klasse [products] die Verbindungszeichenfolge, den OLEDB-Treiber und die zu verwaltende Datenbank. Die Klasse [products] verfügt über eine Methode [getDataSet], die ein [DataSet] zurückgibt, das durch die Ausführung einer SQL-[select]-Abfrage erhalten wird, deren Text als Parameter übergeben wird. Während der Methode finden mehrere Vorgänge statt: Herstellen der Verbindung zur Datenbank, Ausführen der [select]-Abfrage und Schließen der Verbindung. All dies kann eine Ausnahme auslösen, die hier behandelt wird. Ein Testprogramm könnte wie folgt aussehen:
Option Explicit On
Option Strict On
' namespaces
Imports System
Imports System.Data
Imports Microsoft.VisualBasic
Namespace st.istia.univangers.fr
' test pg
Module testproduits
Sub Main(ByVal arguments() As String)
' displays the contents of a product table
' the table is in a ACCESS database whose pg receives the file name
Const syntaxe1 As String = "pg bdACCESS"
' checking program parameters
If arguments.Length <> 1 Then
' error msg
Console.Error.WriteLine(syntaxe1)
' end
Environment.Exit(1)
End If
' prepare the connection chain
Dim chaineConnexion As String = "Provider=Microsoft.Jet.OLEDB.4.0; Ole DB Services=-4; Data Source=" + arguments(0)
' creation of a product object
Dim objProduits As produits = New produits(chaineConnexion)
' retrieve the product table from a dataset
Dim contenu As DataSet
Try
contenu = objProduits.getDataSet("select id,nom,prix from liste")
Catch ex As Exception
Console.Error.WriteLine(("L'erreur suivante s'est produite : " + ex.Message))
Environment.Exit(2)
End Try
' display its contents
Dim lignes As DataRowCollection = contenu.Tables(0).Rows
For i As Integer = 0 To lignes.Count - 1
' table line i
Console.Out.WriteLine(lignes(i).Item("id").ToString + "," + lignes(i).Item("nom").ToString + _
"," + lignes(i).Item("prix").ToString)
Next
End Sub
End Module
End Namespace
Die verschiedenen Komponenten dieser Anwendung werden wie folgt kompiliert:
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 Datenzugriffsklasse haben, schreiben wir die Controller und Ansichten für diese Webanwendung. Schauen wir uns zunächst an, wie das funktioniert. Die erste Ansicht sieht wie folgt aus:
![]() |
Nr. | name | Typ | Eigenschaften | Rolle |
1 | Textfeld | EnableViewState=true | Eingabefeld für Select-Abfrage | |
2 | RequiredFieldValidator | EnableViewState=false | prüft auf das Vorhandensein von 1 | |
3 | TextBox | EnableViewState=true | Eingabefeld – gibt die Anzahl der Datenzeilen an, die pro Ergebnisseite angezeigt werden sollen | |
4 | RequiredFieldValidator | EnableViewState=false | prüft auf das Vorhandensein von 3 | |
5 | RangeValidator | EnableViewState=false | prüft, ob (3) im Bereich [1,30] liegt | |
6 | Schaltfläche | EnableViewState=false | [submit]-Schaltfläche |
Wir nennen diese Ansicht die [form]-Ansicht. Sie ermöglicht es dem Benutzer, eine SQL-SELECT-Abfrage in der Datenbank [products.mdb] auszuführen. Durch die Ausführung der Abfrage wird eine neue Ansicht erstellt:
![]() |
Nr. | Name | Typ | Eigenschaften | Rolle |
1 | Beschriftung | EnableViewState=false | Informationsfeld | |
2 | RadioButton | EnableViewState=false GroupName=rdSort | ermöglicht die Auswahl einer Sortierreihenfolge | |
3 | DataGrid | EnableViewState=true AllowPaging=true Sortierung zulassen=true | Tabelle mit den Ergebnissen der Auswahl | |
4 | LinkButton | EnableViewState=false | [submit]-Schaltfläche |
Wir nennen diese Ansicht die [results]-Ansicht. Sie enthält das [DataGrid], das die Ergebnisse der SQL-SELECT-Anweisung anzeigt. Der Benutzer kann bei seiner Abfrage einen Fehler machen. Einige Fehler werden ihm dank Validierungssteuerelementen in der [errors]-Ansicht gemeldet.

Andere Fehler werden ihm über die [errors]-Ansicht gemeldet:

Die Ansicht [errors] wird angezeigt:
![]() |
Nr. | Name | Typ | Eigenschaften | Rolle |
1 | Variable | HTML-Code, der zur Anzeige von Fehlern erforderlich ist | ||
3 | LinkButton | EnableViewState=false | [submit]-Schaltfläche |
Die drei Ansichten der Anwendung sind drei verschiedene Container (Panels) innerhalb derselben Seite [main.aspx]. Der Präsentationscode 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. Konfigurieren des DataGrid
Sehen wir uns die Paginierung der [DataGrid]-Komponente, eine Funktion, auf die wir hier zum ersten Mal stoßen, einmal genauer an. 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>
aktiviert die Paginierung | |
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 den Attributen des <asp:datagrid>-Tags eingegeben werden. Sie können auch [WebMatrix] verwenden. Klicken Sie im Eigenschaftenfenster von [DataGrid] auf den Link [Property Generator]:

Der folgende Assistent wird angezeigt:

Wählen Sie die Option [Pagination] aus:

Oben sehen wir die Werte der Paginierungsattribute für das [DataGrid] im Präsentationscode.
Darüber hinaus ermöglichen wir die Sortierung der Daten in einer der [DataGrid]-Spalten. Hierfür gibt es mehrere Möglichkeiten. Eine davon besteht darin, die Eigenschaft [AllowSorting=true] im Eigenschaftenfenster von [DataGrid] festzulegen. Sie können auch den Eigenschaftsgenerator verwenden. Unabhängig von der gewählten Methode führt dies dazu, dass das Attribut [AllowSorting=true] im <asp:DataGrid>-Tag 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] sieht wie folgt aus:
[global.asax]
[global.asax.vb]
Imports st.istia.univangers.fr
Imports System.Configuration
Public Class Global
Inherits System.Web.HttpApplication
Sub Application_Start(ByVal sender As Object, ByVal e As EventArgs)
' create a product object
Dim objProduits As produits
Try
objProduits = New produits(ConfigurationSettings.AppSettings("OLEDBStringConnection"))
' put the object in the application
Application("objProduits") = objProduits
' no error
Application("erreur") = False
Catch ex As Exception
'there has been an error, we note it in the application
Application("erreur") = True
Application("message") = ex.Message
End Try
End Sub
End Class
Beim Start der Anwendung (Application_Start) erstellen wir ein [products]-Objekt und speichern es in der Anwendung, damit es für alle Anfragen aller Clients verfügbar ist. Tritt während dieser Erstellung eine Ausnahme auf, wird diese in der Anwendung protokolliert. Die Prozedur [Application_Start] wird nur einmal ausgeführt. Danach ist der Controller [global.asax] nicht mehr beteiligt. Der Controller [main.aspx.vb] übernimmt dann den Rest:
Imports System.Collections
Imports Microsoft.VisualBasic
Imports System.Data
Imports st.istia.univangers.fr
Imports System
Imports System.Xml
Public Class main
Inherits System.Web.UI.Page
' components page
Protected WithEvents txtSelect As System.Web.UI.WebControls.TextBox
Protected WithEvents RequiredFieldValidator1 As System.Web.UI.WebControls.RequiredFieldValidator
Protected WithEvents txtPages As System.Web.UI.WebControls.TextBox
Protected WithEvents RequiredFieldValidator2 As System.Web.UI.WebControls.RequiredFieldValidator
Protected WithEvents RangeValidator1 As System.Web.UI.WebControls.RangeValidator
Protected WithEvents btnExécuter As System.Web.UI.WebControls.Button
Protected WithEvents vueFormulaire As System.Web.UI.WebControls.Panel
Protected WithEvents lblSelect As System.Web.UI.WebControls.Label
Protected WithEvents DataGrid1 As System.Web.UI.WebControls.DataGrid
Protected WithEvents lnkRésultats As System.Web.UI.WebControls.LinkButton
Protected WithEvents vueRésultats As System.Web.UI.WebControls.Panel
Protected WithEvents lnkErreurs As System.Web.UI.WebControls.LinkButton
Protected WithEvents vueErreurs As System.Web.UI.WebControls.Panel
Protected WithEvents rdCroissant As System.Web.UI.WebControls.RadioButton
Protected WithEvents rdDécroissant As System.Web.UI.WebControls.RadioButton
' data page
Protected erreursHTML As String
Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
' check for application errors
If CType(Application("erreur"), Boolean) Then
' the application has not initialized correctly
Dim erreurs As New ArrayList
erreurs.Add("Application momentanément indisponible (" + CType(Application("message"), String) + ")")
afficheErreurs(erreurs, False)
Exit Sub
End If
'1st request
If Not IsPostBack Then
' the empty form is displayed
afficheFormulaire()
End If
End Sub
Private Sub afficheErreurs(ByVal erreurs As ArrayList, ByVal afficheLien As Boolean)
' displays the error view
erreursHTML = ""
For i As Integer = 0 To erreurs.Count - 1
erreursHTML += "<li>" + erreurs(i).ToString + "</li>" + ControlChars.CrLf
Next
lnkErreurs.Visible = afficheLien
' the [errors] view is displayed
vueErreurs.Visible = True
vueFormulaire.Visible = False
vueRésultats.Visible = False
End Sub
Private Sub afficheFormulaire()
' the [form] view is displayed
vueFormulaire.Visible = True
vueErreurs.Visible = False
vueRésultats.Visible = False
End Sub
Private Sub afficheRésultats(ByVal sqlTexte As String, ByVal données As DataView)
' initialize controls
lblSelect.Text = sqlTexte
With DataGrid1
.DataSource = données
.PageSize = CType(txtPages.Text, Integer)
.CurrentPageIndex = 0
.DataBind()
End With
' the [results] view is displayed
vueRésultats.Visible = True
vueFormulaire.Visible = False
vueErreurs.Visible = False
End Sub
Private Sub btnExécuter_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnExécuter.Click
' valid page?
If Not Page.IsValid Then
afficheFormulaire()
Exit Sub
End If
' execute query SELECT customer
Dim données As DataView
Try
données = CType(Application("objProduits"), produits).getDataSet(txtSelect.Text.Trim).Tables(0).DefaultView
Catch ex As Exception
Dim erreurs As New ArrayList
erreurs.Add("erreur d'accès à la base de données (" + ex.Message + ")")
afficheErreurs(erreurs, True)
Exit Sub
End Try
' all's well - the results are in
afficheRésultats(txtSelect.Text.Trim, données)
' put the data in the session
Session("données") = données
End Sub
Private Sub retourFormulaire(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles lnkErreurs.Click, lnkRésultats.Click
' set of views
vueErreurs.Visible = False
vueFormulaire.Visible = True
vueRésultats.Visible = False
End Sub
Private Sub DataGrid1_PageIndexChanged(ByVal source As Object, ByVal e As System.Web.UI.WebControls.DataGridPageChangedEventArgs) Handles DataGrid1.PageIndexChanged
' change page
With DataGrid1
.CurrentPageIndex = e.NewPageIndex
.DataSource = CType(Session("données"), DataView)
.DataBind()
End With
End Sub
Private Sub DataGrid1_SortCommand(ByVal source As Object, ByVal e As System.Web.UI.WebControls.DataGridSortCommandEventArgs) Handles DataGrid1.SortCommand
' sort the dataview
Dim données As DataView = CType(Session("données"), DataView)
données.Sort = e.SortExpression + " " + CType(IIf(rdCroissant.Checked, "asc", "desc"), String)
' we display it
With DataGrid1
.CurrentPageIndex = 0
.DataSource = données
.DataBind()
End With
End Sub
End Class
Wenn die Seite geladen wird [Page_Load], prüfen wir zunächst, ob die Anwendung korrekt initialisiert werden konnte. Ist dies nicht der Fall, zeigen wir die Ansicht [errors] ohne Link zurück zum Formular an, da dieser Link dann überflüssig ist. Tatsächlich kann nur die Ansicht [errors] angezeigt werden, wenn die Anwendung nicht korrekt initialisiert werden konnte. Andernfalls zeigen wir die Ansicht [form] an, sofern dies die erste Anfrage des Clients ist. Im Übrigen überlassen wir es dem Leser, den Code zu verstehen. Wir konzentrieren uns nur auf drei Prozeduren: die Prozedur [btnExecute_Click], die ausgeführt wird, wenn der Benutzer die Ausführung der in der Ansicht [form] eingegebenen SQL-Abfrage anfordert, die Prozedur [DataGrid1_PageIndexChanged], die ausgeführt wird, wenn der Benutzer die Links [Next] und [Previous] im [DataGrid] verwendet, sowie die Prozedur [DataGrid1_SortCommand], die ausgeführt wird, wenn der Benutzer auf eine Spaltenüberschrift klickt, um die Daten in dieser Reihenfolge zu sortieren. Die Sortierreihenfolge – aufsteigend oder absteigend – wird durch die beiden Sortier-Optionsfelder bestimmt.
In der Prozedur [btnExécuter_Click] prüfen wir daher zunächst, ob die Seite gültig ist oder nicht. Wenn die Prozedur [btnExécuter_Click] ausgeführt wird, sind die Prüfungen in Bezug auf die verschiedenen Validierungssteuerelemente der Seite bereits durchgeführt worden. Für jedes Validierungssteuerelement wurden zwei Attribute festgelegt:
wird auf „true“ gesetzt, wenn die überprüften Daten gültig sind, andernfalls auf „false“ | |
die Fehlermeldung, wenn die überprüften Daten ungültig sind |
Für die Seite selbst wurde ein [IsValid]-Attribut gesetzt. Es ist nur dann „true“, wenn bei allen Validierungssteuerelementen das [IsValid]-Attribut auf „true“ gesetzt ist. Ist dies nicht der Fall, muss die Ansicht [form] angezeigt werden. Diese Ansicht enthält die Validierungssteuerelemente, die ihr Attribut [errorMessage] anzeigen. Ist die Seite gültig, verwenden wir das von [Application_Start] erstellte Objekt [products], um das [DataSet] abzurufen, das der Ausführung der SQL-SELECT-Abfrage entspricht. Wir konvertieren dies in ein [DataView]-Objekt:
Dim données As DataView
Try
données = CType(Application("objProduits"), produits).getDataSet(txtSelect.Text.Trim).Tables(0).DefaultView
...
Wir hätten einfach mit dem [DataSet] arbeiten und schreiben können:
Dim données As DataSet
Try
données = CType(Application("objProduits"), produits).getDataSet(txtSelect.Text.Trim)
...
Ein [DataSet]-Objekt ist im Wesentlichen eine Sammlung von Tabellen, die durch Beziehungen miteinander verknüpft sind. In unserer konkreten Anwendung enthält das aus der Klasse [products] abgerufene [DataSet] nur eine einzige Tabelle, nämlich diejenige, die aus der [select]-Anweisung resultiert. Eine Tabelle kann sortiert werden, ein [DataSet] hingegen nicht; wir sind jedoch daran interessiert, die abgerufenen Daten zu sortieren. Um mit der Ergebnistabelle aus der [select]-Anweisung 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 [DataTable]-Objekt stellt zwar eine Datenbanktabelle dar, verfügt jedoch nicht über eine Sortiermethode. Dazu benötigen Sie eine Ansicht der Tabelle. Eine Ansicht ist ein Objekt vom Typ [DataView]. Mithilfe von Filtern können Sie verschiedene Ansichten derselben Tabelle erstellen. Eine Tabelle verfügt über eine Standardansicht, bei der keine Filter definiert sind. Sie repräsentiert daher die gesamte Tabelle. Diese Standardansicht wird über [DataTable.DefaultView] abgerufen. Sie können eine Ansicht mithilfe ihrer [sort]-Eigenschaft sortieren, auf die wir später noch eingehen werden.
Wenn das Abrufen des [DataSet] aus der Klasse [products] erfolgreich ist, wird die Ansicht [results] angezeigt; andernfalls wird die Ansicht [errors] angezeigt. Die Ansicht [results] wird über die Prozedur [displayResults] angezeigt, an die zwei Parameter übergeben werden:
- den Text, der in das [lblSelect]-Label eingefügt werden soll
- die [DataView], die an [DataGrid1] gebunden werden soll
Dieses Beispiel veranschaulicht die große Flexibilität der [DataGrid]-Komponente. Sie kann die Struktur der [DataView] erkennen, an die sie gebunden ist, und sich daran anpassen. Schließlich speichert die Prozedur [btnExécuter_Click] die soeben erhaltene [DataView] in der Sitzung des Benutzers, damit sie verfügbar ist, wenn der Benutzer andere Seiten aus derselben [DataView] anfordert.
Die Prozedur [DataGrid1_PageIndexChanged] wird ausgeführt, wenn der Benutzer auf die Links [Next] und [Previous] im [DataGrid] klickt. Sie erhält zwei Parameter:
Private Sub DataGrid1_PageIndexChanged(ByVal source As Object, ByVal e As System.Web.UI.WebControls.) Handles DataGrid1.PageIndexChanged
das Objekt, das das Ereignis ausgelöst hat – in diesem Fall einer der Links [Weiter] oder [Zurück] | |
Informationen zum Ereignis. Die Eigenschaft e.NewPageIndex ist die Seitenzahl, die als Antwort auf die Anfrage des Clients angezeigt werden soll |
Der vollständige Code für den Ereignishandler lautet wie folgt:
Private Sub DataGrid1_PageIndexChanged(ByVal source As Object, ByVal e As System.Web.UI.WebControls.DataGridPageChangedEventArgs) Handles DataGrid1.PageIndexChanged
' change page
With DataGrid1
.CurrentPageIndex = e.NewPageIndex
.DataSource = CType(Session("données"), DataView)
.DataBind()
End With
End Sub
Die [DataGrid]-Komponente verfügt über ein [CurrentPageIndex]-Attribut, das die Seitenzahl angibt, die gerade angezeigt wird oder angezeigt werden soll. Wir weisen diesem Attribut den [NewPageIndex]-Wert des Parameters [e] zu. Das [DataGrid] wird dann an das [DataView] gebunden, das von der Prozedur [btnExécuter_Click] in der Sitzung gespeichert wurde.
Man könnte sich fragen, ob das [DataGrid] das Attribut [EnableViewState=true] benötigt, da sein Inhalt bei jedem Neuladen der Seite vom Code berechnet wird. Man könnte meinen, dass dies nicht der Fall ist. Wenn das [DataGrid] jedoch das Attribut [EnableViewState=false] hat, stellen wir fest, dass das Ereignis [DataGrid1.PageIndexChanged] nie ausgelöst wird. Aus diesem Grund haben wir [EnableViewState=true] beibehalten. Wir wissen, dass dies dazu führt, dass der Inhalt des [DataGrid] im versteckten Feld [__VIEWSTATE] der Seite gespeichert wird. Dies kann die Seite erheblich verlangsamen, wenn das [DataGrid] groß ist. Sollte dies ein Problem darstellen, können Sie die Paginierung selbst verwalten, ohne die automatische Paginierung des [DataGrid] zu verwenden.
Die Prozedur [DataGrid1_SortCommand] wird ausgeführt, wenn der Benutzer auf die Überschrift einer der vom [DataGrid] angezeigten Spalten klickt, um die Sortierung der Daten in der Reihenfolge 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 Objekt, das das Ereignis ausgelöst hat – in diesem Fall einer der Links [Weiter] oder [Zurück] | |
Informationen zum Ereignis. Die Eigenschaft [e.SortExpression] ist der Name der Spalte, auf die zum Sortieren geklickt wurde |
Der vollständige Code für den Ereignishandler lautet wie folgt:
Private Sub DataGrid1_SortCommand(ByVal source As Object, ByVal e As System.Web.UI.WebControls.DataGridSortCommandEventArgs) Handles DataGrid1.SortCommand
' sort the dataview
Dim données As DataView = CType(Session("données"), DataView)
données.Sort = e.SortExpression + " " + CType(IIf(rdCroissant.Checked, "asc", "desc"), String)
' we display it
With DataGrid1
.CurrentPageIndex = 0
.DataSource = données
.DataBind()
End With
End Sub
Wir rufen die [DataView] ab, die vom [DataGrid] in der aktuellen Sitzung angezeigt wird. Sie wurde dort von der Prozedur [btnExécuter_Click] platziert. Die [DataView]-Komponente verfügt über eine [Sort]-Eigenschaft, der wir den Sortierausdruck zuweisen. Dies folgt der Syntax [select ... order by expr1, expr2, ...], wobei jedem [expr] das Schlüsselwort [asc] für aufsteigende Sortierung oder [desc] für absteigende Sortierung folgen kann. Der hier verwendete [order by]-Ausdruck lautet [order by column asc/desc]. Die Eigenschaft [e.SortExpression] liefert uns den Namen der [DataGrid]-Spalte, auf die zum Sortieren geklickt wurde. Die Zeichenfolge [asc/desc] wird basierend auf den Werten der Optionsfelder in der Gruppe [rdTri] festgelegt. Sobald der Sortierausdruck der [DataView] festgelegt ist, wird das [DataGrid] daran gebunden. Wir positionieren das [DataGrid] auf seiner ersten Seite.
8.7. DataList-Komponente und Datenbindung
Wir konzentrieren uns nun auf die [DataList]-Komponente. Sie bietet mehr Formatierungsoptionen als das [DataGrid], ist jedoch weniger flexibel. Daher kann sie sich nicht automatisch an die Datenquelle anpassen, mit der sie verknüpft ist. Diese Anpassung muss bei Bedarf über Code erfolgen. Wenn die Struktur der Datenquelle im Voraus bekannt ist, bietet diese Komponente Formatierungsoptionen, die sie gegenüber dem [DataGrid] vorteilhaft machen können.
8.7.1. Anwendung
Um die Verwendung der [DataList] zu veranschaulichen, erstellen wir eine MVC-Anwendung, die der vorherigen ähnelt:
![]() |
Die drei Ansichten werden als Container in den Präsentationscode des Controllers [main.aspx] eingebunden. Daher besteht diese Anwendung aus einer einzigen Seite [main.aspx].
8.7.2. Geschäftsklassen
Die Klasse [products] ist dieselbe wie zuvor.
8.7.3. Die Ansichten
Wenn der Benutzer seine erste Anfrage an die Anwendung stellt, sieht er die folgende Ansicht [results1]:
![]() |
Nr. | Name | Typ | Eigenschaften | Rolle |
1 | RadioButton | EnableViewState=false | ermöglicht es Ihnen, einen von zwei [DataList]-Stilen auszuwählen | |
2 | Button | EnableViewState=false | [submit]-Schaltfläche | |
3 | DataList | EnableViewState=true | Anzeigefeld der Datenliste |
Wenn der Benutzer Stil Nr. 2 auswählt, sieht er die folgende Ansicht [results2]:
![]() |
Nr. | Name | Typ | Eigenschaften | Rolle |
1 | DataList | EnableViewState=true | Anzeigefeld der Datenliste |
Die Ansicht [Fehler] weist auf ein Problem beim Zugriff auf die Datenquelle hin:
![]() |
Nr. | Name | Typ | Eigenschaften | Rolle |
1 | Variable | HTML-Code, der zur Anzeige von Fehlern erforderlich ist |
Die drei Ansichten der Anwendung sind drei verschiedene Container (Panels) innerhalb derselben Seite [main.aspx]. Der Präsentationscode 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("nom") %>
<br>
prix :
<%# databinder.eval(Container.DataItem,"prix","{0:C}") %>
<br>
</ItemTemplate>
<FooterStyle BackColor="Tan"></FooterStyle>
<HeaderStyle Font-Bold="True" BackColor="Tan"></HeaderStyle>
</asp:DataList></P>
</asp:Panel>
<asp:Panel id="vueRésultats2" runat="server">
<P>
<asp:DataList id="DataList2" runat="server">
<HeaderTemplate>
Contenu de la table [liste] de la base [produits]
<HR width="100%" SIZE="1">
</HeaderTemplate>
<AlternatingItemStyle BackColor="Teal"></AlternatingItemStyle>
<SeparatorStyle BackColor="LightSkyBlue"></SeparatorStyle>
<ItemStyle BackColor="#C0C000"></ItemStyle>
<ItemTemplate>
nom :
<%# Container.DataItem("nom") %>
, prix :
<%# databinder.eval(Container.DataItem,"prix","{0:C}") %>
<BR>
</ItemTemplate>
<SeparatorTemplate>
<HR width="100%" SIZE="1">
</SeparatorTemplate>
<HeaderStyle BackColor="#C0C0FF"></HeaderStyle>
</asp:DataList></P>
</asp:Panel>
<asp:Panel id="vueErreurs" runat="server">
<P>Les erreurs suivantes se sont produites :</P>
<%= erreursHTML %>
</asp:Panel>
</form>
</body>
</HTML>
8.7.4. Konfigurieren von [DataList]-Komponenten
Werfen wir einen Blick auf die verschiedenen Attribute einer [DataList]-Komponente. Es gibt viele davon, und wir werden hier nur eine kleine Auswahl behandeln. Sie können innerhalb einer [DataList] bis zu sieben Anzeigevorlagen definieren:
[DataList]-Kopfzeilenvorlage | |
Vorlage für die Zeilen, in denen die Elemente der zugehörigen Datenliste angezeigt werden. Nur diese Vorlage ist erforderlich. | |
Um visuell zwischen aufeinanderfolgenden angezeigten Elementen zu unterscheiden, können zwei Vorlagen verwendet werden: ItemTemplate für Element n, AlternatingItemTemplate für Element n+1 | |
Vorlage für das ausgewählte Element in der [DataList] | |
Vorlage für das Trennzeichen zwischen zwei Elementen in der [DataList] | |
Eine [DataList] ermöglicht es Ihnen, die angezeigten Werte zu bearbeiten. [EditItemTemplate] ist die Vorlage für ein Element in der [DataList], das sich derzeit im „Bearbeitungsmodus“ befindet | |
Vorlage für die Fußzeile der [DataList] |
Die Komponente [DataList1] wurde mit [WebMatrix] erstellt. In ihrem Eigenschaftenfenster wurde der Link [AutoFormat] ausgewählt:
![]() | 1234567 ![]() |
Oben generiert das Schema [Color 5] eine [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 wurden keine Vorlagen definiert. Das müssen wir selbst tun. Wir definieren die folgenden Vorlagen:
| |
|
Beachten Sie, dass die Vorlage [ItemTemplate] dazu dient, die Elemente aus der mit [DataList] verknüpften Datenquelle anzuzeigen. Diese Datenquelle ist eine Sammlung von Datenzeilen, von denen jede einen oder mehrere Werte enthält. Die aktuelle Zeile in der Datenquelle wird durch das Objekt [Container.DataItem] dargestellt. Eine solche Zeile enthält Spalten. [Container.DataItem("col1")] ist der Wert der Spalte „col1“ in der aktuellen Zeile. Um diesen Wert in den Präsentationscode einzufügen, schreiben wir <%# Container.DataItem("col") %>. Manchmal möchten wir ein Element der aktuellen Zeile in einem speziellen Format anzeigen. Hier möchten wir die Spalte „price“ der aktuellen Zeile in Euro anzeigen. Wir verwenden die Funktion [DataBinder.Eval], die drei Parameter benötigt:
- 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.
Somit zeigt der Code <%# DataBinder.Eval(Container.DataItem,"price",{0:C}) %> die Spalte [price] der aktuellen Zeile im Währungsformat an (Format C = Währung).
Wir erhalten somit eine [DataList], die wie folgt aussieht:

Oben wurden die Daten mit vier Datenelementen pro Zeile angeordnet. Dies wird mithilfe der folgenden [DataList]-Attribute erreicht:
Horizontal | |
gewünschte Anzahl von Spalten |
Letztendlich entspricht der Code für [DataList1] dem im obigen Codeausschnitt dargestellten. Wir überlassen es dem Leser, den Präsentationscode für [DataList2] zu studieren. Wie bei der [DataGrid]-Komponente können die meisten [DataList]-Eigenschaften mithilfe eines [WebMatrix]-Assistenten festgelegt werden. Verwenden Sie dazu den Link [Property Generator] im Eigenschaftenfenster von [DataList]:
![]() | ![]() |
8.7.5. Die Controller
Der Controller [global.asax, global.asax.vb] sieht wie folgt aus:
[global.asax]
[global.asax.vb]
Imports System
Imports System.Web
Imports System.Web.SessionState
Imports st.istia.univangers.fr
Imports System.Configuration
Imports System.Data
Imports System.Collections
Public Class Global
Inherits System.Web.HttpApplication
Sub Application_Start(ByVal sender As Object, ByVal e As EventArgs)
' create a product object
Try
Dim données As DataSet = New produits(ConfigurationSettings.AppSettings("OLEDBStringConnection")).getDataSet("select * from LISTE")
' put the object in the application
Application("données") = données
' no error
Application("erreur") = False
Catch ex As Exception
'there has been an error, we note it in the application
Application("erreur") = True
Application("message") = ex.Message
End Try
End Sub
End Class
Beim Start der Anwendung (Application_Start) erstellen wir ein [dataset] aus der Business-Klasse [products] und fügen es der Anwendung hinzu, damit es für alle Anfragen aller Clients verfügbar ist. Tritt während dieser Erstellung eine Ausnahme auf, wird diese in der Anwendung protokolliert. Die Prozedur [Application_Start] wird nur einmal ausgeführt. Danach ist der Controller [global.asax] nicht mehr beteiligt. Der Controller [main.aspx.vb] übernimmt dann die Arbeit:
Imports System.Collections
Imports Microsoft.VisualBasic
Imports System.Data
Imports st.istia.univangers.fr
Imports System
Imports System.Xml
Public Class main
Inherits System.Web.UI.Page
' components page
Protected WithEvents vueErreurs As System.Web.UI.WebControls.Panel
Protected WithEvents DataList1 As System.Web.UI.WebControls.DataList
Protected WithEvents DataList2 As System.Web.UI.WebControls.DataList
Protected WithEvents vueRésultats1 As System.Web.UI.WebControls.Panel
Protected WithEvents vueRésultats2 As System.Web.UI.WebControls.Panel
Protected WithEvents RadioButton1 As System.Web.UI.WebControls.RadioButton
Protected WithEvents RadioButton2 As System.Web.UI.WebControls.RadioButton
Protected WithEvents btnChanger As System.Web.UI.WebControls.Button
Protected WithEvents bandeau As System.Web.UI.WebControls.Panel
' data page
Protected erreursHTML As String
Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
' check for application errors
If CType(Application("erreur"), Boolean) Then
' the application has not initialized correctly
Dim erreurs As New ArrayList
erreurs.Add("Application momentanément indisponible (" + CType(Application("message"), String) + ")")
afficheErreurs(erreurs, False)
Exit Sub
End If
'1st request
If Not IsPostBack Then
' initialize controls
With DataList1
.DataSource = CType(Application("données"), DataSet)
.DataBind()
End With
With DataList2
.DataSource = CType(Application("données"), DataSet)
.DataBind()
End With
' the empty form is displayed
afficheRésultats(True, False)
End If
End Sub
Private Sub afficheErreurs(ByVal erreurs As ArrayList, ByVal afficheLien As Boolean)
' displays the error view
erreursHTML = ""
For i As Integer = 0 To erreurs.Count - 1
erreursHTML += "<li>" + erreurs(i).ToString + "</li>" + ControlChars.CrLf
Next
' the [errors] view is displayed
vueErreurs.Visible = True
vueRésultats1.Visible = False
vueRésultats2.Visible = False
bandeau.Visible = False
End Sub
Private Sub afficheRésultats(ByVal visible1 As Boolean, ByVal visible2 As Boolean)
' the [results] view is displayed
vueRésultats1.Visible = visible1
vueRésultats2.Visible = visible2
vueErreurs.Visible = False
End Sub
Private Sub btnChanger_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnChanger.Click
' change the style
afficheRésultats(RadioButton1.Checked, RadioButton2.Checked)
End Sub
End Class
8.8. Repeater-Komponente und Datenbindung
Mit der [Repeater]-Komponente können Sie den HTML-Code für jedes Element in einer Datenliste wiederholen. Angenommen, wir möchten eine Liste von Fehlern im folgenden Format anzeigen:

Wir sind bereits auf dieses Problem gestoßen und haben es gelöst, indem wir eine Variable in den Präsentationscode in der Form <% =erreursHTML %> eingefügt haben, wobei der Wert von erreursHTML vom Controller berechnet wird. Dieser Wert enthält HTML-Code, insbesondere den einer Liste. Der Nachteil ist, dass man, wenn man die Darstellung dieser HTML-Liste ändern möchte, in den Controller-Bereich gehen muss, was der Trennung von Controller und Präsentation zuwiderläuft. Die [Repeater]-Komponente bietet eine Lösung. Wie bei der [DataList] können wir <HeaderTemplate> für die Kopfzeile, <ItemTemplate> für das aktuelle Element in der Datenliste und <FooterTemplate> für das Ende der Daten definieren. Hier könnten wir die folgende Definition für die [Repeater]-Komponente haben:
<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>
Beachten Sie, dass [Container.DataItem] eine Datenzeile darstellt, wenn die Datenquelle mehrere Spalten enthält. Es stellt einen einzelnen Datenpunkt dar, wenn die Quelle nur eine Spalte enthält. Dies ist hier der Fall. Wir erstellen beispielsweise die folgende Anwendung:

Der Code für das Seitenlayout 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 Steuerungscode lautet wie folgt:
<%@ Page Language="VB" %>
<script runat="server">
' procedure executed when the page is loaded
Sub page_Load(sender As Object, e As EventArgs)
if not IsPostBack then
' create a data source
with Repeater1
.DataSource=createDataSource
.DataBind
end with
end if
End Sub
function createDataSource as ArrayList
' create an arraylist
dim erreurs as new ArrayList
dim i as integer
for i=0 to 5
erreurs.add("erreur-"+i.ToString)
next
return erreurs
end function
</script>
<html>
...
</html>
Bei der ersten Anfrage des Clients verknüpfen wir ein [ArrayList]-Objekt mit der [Repeater]-Komponente, das eine Liste von Fehlern darstellen soll.
8.9. Anwendung
Hier greifen wir eine Anwendung wieder auf, die zuvor mit serverseitigen Komponenten implementiert wurde. Die Anwendung ermöglicht es Benutzern, Steuerberechnungen zu simulieren. Sie stützt sich auf eine [impot]-Klasse, auf die wir hier nicht näher eingehen werden. Diese Klasse benötigt Daten, die sie aus einer OLEDB-Datenquelle abruft. Für dieses Beispiel verwenden wir eine ACCESS-Datenquelle. In dieser Version führen wir die folgenden neuen Funktionen ein:
- die Verwendung von Validierungskomponenten zur Überprüfung der Datenvalidität
- die Verwendung von Serverkomponenten, die mit Datenquellen verknüpft sind, zur Anzeige der Ergebnisse
8.9.1. Die MVC-Struktur der Anwendung
Die MVC-Struktur der Anwendung sieht wie folgt aus:
![]() |
Die drei Ansichten werden als Container 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 [form] ist das Formular zur Eingabe von Informationen, die zur Berechnung der Steuer eines Benutzers verwendet werden:

Der Benutzer füllt das Formular aus:

Er nutzt die Schaltfläche [Submit], um eine Steuerberechnung anzufordern. Er sieht die folgende Ansicht [simulations]:

Über den obigen Link kehrt er zum Formular zurück. Er findet es in dem Zustand vor, in dem er es verlassen hat. Es können Eingabefehler auftreten:

Diese werden in der Ansicht [Formular] markiert:

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

Daraufhin wird die Ansicht [Simulationen] mit einer zusätzlichen Simulation angezeigt:

Wenn die Datenquelle nicht verfügbar ist, wird der Benutzer schließlich in der Ansicht [Fehler] benachrichtigt:

8.9.2.1. Der Präsentationscode
Denken Sie daran, dass die Seite [main.aspx] alle Ansichten zusammenführt. Es handelt sich um ein einziges Formular mit drei Containern:
- [panelform] für die Ansicht [Formular]
- [panelerrors] für die Ansicht [Fehler]
- [panelsimulations] für die Ansicht [simulations]
Wir werden nun die Komponenten dieser drei Container näher erläutern. Der [panelform]-Container hat die folgende visuelle Darstellung:
![]() |
Nr. | Name | Typ | Eigenschaften | Rolle |
Panel | Formularansicht | |||
Optionsfeld | GroupName=rdmarie | Optionsfelder | ||
Benutzerdefinierter Validator | Fehlermeldung=Sie haben Ihren Familienstand nicht angegeben EnableClientScript=false | prüft, ob das Client-Programm den erwarteten Familienstand gesendet hat | ||
TextBox | Anzahl der Kinder | |||
RequiredFieldValidator | Fehlermeldung=Geben Sie die Anzahl der Kinder ein ControlToValidate=txtChildren | prüft, ob das Feld [txtChildren] nicht leer ist | ||
Bereichsprüfung | ErrorMessage=Geben Sie eine Zahl zwischen 1 und 30 ein ControlToValidate=txtChildren | prüft, ob das Feld [txtChildren] im Bereich [1,30] liegt | ||
Textfeld | EnableViewState=true | Jahresgehalt | ||
Erforderliches Feld-Validator | Zu validierendes Steuerelement=txtSalary Fehlermeldung=Geben Sie Ihren Gehaltsbetrag ein | prüft, ob das Feld [txtSalary] nicht leer ist | ||
RegularExpressionValidator | ControlToValidate=txtSalary Fehlermeldung=Ungültiges Gehalt Regulärer Ausdruck=\s*\d+\s* | prüft, ob das Feld [txtSalary] eine Folge von Ziffern ist | ||
Schaltfläche | ValidationTriggers=true | [submit]-Schaltfläche im Formular – startet die Steuerberechnung | ||
Schaltfläche | Validation=false | [Absenden]-Schaltfläche im Formular – löscht das Formular |
Vielleicht überrascht Sie die Überprüfung [cvMarié], die sicherstellt, dass der Benutzer eines der beiden Optionsfelder ausgewählt hat. Dies ist notwendig, da nicht mit Sicherheit festgestellt werden kann, ob der Benutzer das vom Server gesendete Formular verwendet. Da dies nicht garantiert werden kann, müssen wir alle übermittelten Parameter überprüfen. Beachten Sie auch das Attribut [CausesValidation=false] der Schaltfläche [btnEffacer]. Wenn der Benutzer auf diese Schaltfläche klickt, sollten die übermittelten Daten nicht überprüft werden, da sie ignoriert werden.
Alle Komponenten im Container verfügen über die Eigenschaft [EnableViewState=false], mit Ausnahme von [panelForm, txtEnfants, txtSalaire, rdOui, rdNon]. Der Container [panelerreurs] hat die folgende visuelle Darstellung:
![]() |
Nr. | Name | Typ | Eigenschaften | Rolle |
Panel | EnableViewState=false | Fehleransicht | ||
Repeater | EnableViewState=false | zeigt eine Liste von Fehlern an |
Die Komponente [rptErrors] 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 [rptErrors] verknüpfte Datenliste ist ein [ArrayList]-Objekt, das eine Liste von Fehlermeldungen enthält. Wie oben gezeigt, bezieht sich <%# Container.Dataitem%> daher auf die aktuelle Fehlermeldung. Der Container [panelsimulations] hat die folgende visuelle Darstellung:
![]() |
Nr. | Name | Typ | Eigenschaften | Rolle |
Panel | EnableViewState=false | Simulationsansicht | ||
LinkButton | EnableViewState=false | Link zum Formular | ||
DataGrid | EnableViewState=false | verantwortlich für die Anzeige der in einem [DataTable]-Objekt platzierten Simulationen |
Die Komponente [dgSimulations] wird in [Webmatrix] wie folgt konfiguriert. Im Eigenschaftenfenster von [dgSimulations] wählen wir den Link [AutoFormat] und wählen das Schema [Color 3]:
![]() | ![]() |
Anschließend wählen wir, immer noch im Eigenschaftenfenster von [dgSimulations], den Link [Property Generator] aus. Wir legen fest, dass die Spaltenüberschriften angezeigt werden sollen:

Wir wählen die Option [Columns], um die vier Spalten des [DataGrid] zu definieren:

Wir deaktivieren die Option [Spalten automatisch erstellen...]. Wir werden die vier Spalten des [DataGrid] selbst definieren. Dies wird mit einem [DataTable]-Objekt verknüpft, das vier Spalten mit den Namen „verheiratet“, „Kinder“, „Gehalt“ und „Steuer“ enthält. Um eine Spalte im [DataGrid] zu erstellen, wählen wir die Option [Related Columns] und verwenden die Schaltfläche zum Erstellen, wie oben gezeigt. Eine Spalte wird erstellt, und wir können ihre Eigenschaften definieren. Die erste Spalte der Simulationstabelle enthält die Spalte „married“ aus dem [DataTable]-Objekt, das mit dem [DataGrid] verknüpft wird. Diese erste Spalte des [DataGrid] wird im Assistenten wie folgt definiert:

Spaltentitel, hier „Verheiratet“ | |
Name der Spalte in der Datenquelle, die von dieser Spalte des [DataGrid] angezeigt wird. Hier ist es die Spalte „married“ der [DataTable]. |
Die zweite Spalte ist wie folgt definiert:
Kinder | |
children |
Die dritte Spalte ist wie folgt definiert:
Jahresgehalt | |
Gehalt | |
{0:C} – Währungsanzeige, um das Euro-Zeichen zu erhalten |
Die vierte Spalte ist wie folgt definiert:
Steuerbetrag | |
Steuer | |
{0:C} – Währungsanzeige, um das Euro-Zeichen zu erhalten |
Wir speichern den Präsentationscode und den Steuerungscode in zwei separaten Dateien. Die erste befindet sich in [main.aspx] und die zweite in [main.aspx.vb]. Der Code für [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 Anwendungssteuerungscode 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] sieht wie folgt aus:
Imports System
Imports System.Web
Imports System.Web.SessionState
Imports st.istia.univangers.fr
Imports System.Configuration
Imports System.Collections
Imports System.Data
Public Class Global
Inherits System.Web.HttpApplication
Sub Application_Start(ByVal sender As Object, ByVal e As EventArgs)
' create an impot object
Dim objImpot As impot
Try
objImpot = New impot(New impotsOLEDB(ConfigurationSettings.AppSettings("chaineConnexion")))
' put the object in the application
Application("objImpot") = objImpot
' no error
Application("erreur") = False
Catch ex As Exception
'there has been an error, we note it in the application
Application("erreur") = True
Application("message") = ex.Message
End Try
End Sub
Sub Session_Start(ByVal sender As Object, ByVal e As EventArgs)
' start of session - create a list of empty simulations
Dim simulations As New DataTable("simulations")
simulations.Columns.Add("marié", Type.GetType("System.String"))
simulations.Columns.Add("enfants", Type.GetType("System.String"))
simulations.Columns.Add("salaire", Type.GetType("System.Int32"))
simulations.Columns.Add("impôt", Type.GetType("System.Int32"))
Session.Item("simulations") = simulations
End Sub
End Class
Beim Start der Anwendung (erste Anfrage an die Anwendung) wird die Prozedur [Application_Start] ausgeführt. Sie versucht, ein Objekt vom Typ [tax] zu erstellen, indem sie dessen Daten aus einer OLEDB-Quelle abruft. 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 Anfragen wissen, dass die Initialisierung nicht korrekt durchgeführt werden konnte. Ist die Erstellung erfolgreich, wird das erstellte [impot]-Objekt ebenfalls in der Anwendung gespeichert. Es wird von allen Anfragen zur Steuerberechnung verwendet. Wenn ein Client seine erste Anfrage stellt, wird für ihn durch die Prozedur [Application_Start] eine Sitzung erstellt. Diese Sitzung dient dazu, die verschiedenen Steuerberechnungssimulationen zu speichern, die der Client durchführen wird. Diese werden in einem [DataTable]-Objekt gespeichert, das mit dem Sitzungsschlüssel „simulations“ verknüpft ist. Beim Start der Sitzung wird dieser Schlüssel einem leeren [DataTable]-Objekt zugeordnet, dessen Struktur bereits definiert wurde. Die von der Anwendung benötigten Informationen befinden sich in ihrer Konfigurationsdatei [wenConfig]:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="chaineConnexion" value="Provider=Microsoft.Jet.OLEDB.4.0; Ole DB Services=-4; Data Source=D:\data\devel\aspnet\poly\webforms2\vs\impots6\impots.mdb" />
</appSettings>
</configuration>
Der Schlüssel [connectionString] gibt die Verbindungszeichenfolge zur OLEDB-Quelle an. Der restliche Steuerungscode 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
' local variables
Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
...
End Sub
Private Sub afficheErreurs(ByRef erreurs As ArrayList)
...
End Sub
Private Sub afficheFormulaire()
...
End Sub
Private Sub afficheSimulations(ByRef simulations As DataTable, ByRef lien As String)
...
End Sub
Private Sub btnCalculer_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnCalculer.Click
....
End Sub
Private Sub lnkForm1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)
...
End Sub
Private Sub lnkForm2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles lnkForm2.Click
...
End Sub
Private Sub btnEffacer_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnEffacer.Click
...
End Sub
Private Sub razForm()
...
End Sub
Private Sub cvMarie_ServerValidate(ByVal source As System.Object, ByVal args As System.Web.UI.WebControls.ServerValidateEventArgs)
...
End Sub
End Class
Das erste vom Code bearbeitete Ereignis ist [Page_Load]:
Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
' first, we look at the state of the application
If CType(Application("erreur"), Boolean) Then
' the application failed to initialize
' the error view is displayed
Dim erreurs As New ArrayList
erreurs.Add("Application momentanément indisponible (" + CType(Application("message"), String) + ")")
afficheErreurs(erreurs)
Exit Sub
End If
' no errors - on the 1st request, the form is presented
If Not IsPostBack Then afficheFormulaire()
End Sub
Bevor wir die Anfrage bearbeiten, überprüfen wir, ob die Anwendung korrekt initialisiert wurde. Ist dies nicht der Fall, zeigen wir die Ansicht [errors] mithilfe der Prozedur [displayErrors] an. Handelt es sich um die erste Anfrage (IsPostBack=false), zeigen wir die Ansicht [form] mithilfe von [displayForm] an.
Die Prozedur, die die Ansicht [errors] anzeigt, lautet wie folgt:
Private Sub afficheErreurs(ByRef erreurs As ArrayList)
' builds a list of errors
With rptErreurs
.DataSource = erreurs
.DataBind()
End With
' container display
panelerreurs.Visible = True
panelform.Visible = False
panelsimulations.Visible = False
Exit Sub
End Sub
Die Prozedur erhält als Parameter eine Liste von Fehlermeldungen in [errors] vom Typ [ArrayList]. Wir binden diese Datenquelle einfach an die Komponente [rptErrors], die für deren Anzeige zuständig ist.
Die Prozedur zur Anzeige der Ansicht [form] lautet wie folgt:
Private Sub afficheFormulaire()
' displays the form
panelform.Visible = True
' the other containers are hidden
panelerreurs.Visible = False
panelsimulations.Visible = False
End Sub
Diese Prozedur macht lediglich den Container [panelform] sichtbar. Die Komponenten werden mit ihrem übermittelten oder vorherigen Wert (VIEWSTATE) angezeigt.
Wenn der Benutzer in der Ansicht [form] auf die Schaltfläche [Calculate] klickt, wird eine POST-Anfrage an [main.aspx] gesendet. Die Prozedur [Page_Load] wird ausgeführt, gefolgt von der Prozedur [btnCalculate_Click]:
Private Sub btnCalculer_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnCalculer.Click
' we check the validity of the data entered; if there are any errors, we report them
If Not Page.IsValid Then
afficheFormulaire()
Exit Sub
End If
' no errors - tax is calculated
Dim impot As Long = CType(Application("objImpot"), impot).calculer( _
rdOui.Checked, CType(txtEnfants.Text, Integer), CType(txtSalaire.Text, Long))
' the result is added to existing simulations
Dim simulations As DataTable = CType(Session.Item("simulations"), DataTable)
Dim simulation As DataRow = simulations.NewRow
simulation("marié") = CType(IIf(rdOui.Checked, "oui", "non"), String)
simulation("enfants") = txtEnfants.Text.Trim
simulation("salaire") = CType(txtSalaire.Text.Trim, Long)
simulation("impôt") = impot
simulations.Rows.Add(simulation)
' put the simulations in the session
Session.Item("simulations") = simulations
' the simulations page is displayed
afficheSimulations(simulations, "Retour au formulaire")
End Sub
Die Prozedur beginnt mit der Überprüfung der Gültigkeit der Seite. Denken Sie daran, dass bei Ausführung der Prozedur [btnCalculate_Click] die Validierungssteuerelemente ihre Arbeit bereits erledigt haben und das Attribut [IsValid] der Seite gesetzt wurde. Ist die Seite ungültig, wird die Ansicht [form] erneut angezeigt und die Prozedur beendet. Die Validierungskomponenten der Ansicht [form], deren Attribut [IsValid] auf [false] gesetzt ist, zeigen ihr Attribut [ErrorMessage] an. Ist die Seite gültig, wird der Steuerbetrag unter Verwendung des Objekts [tax] berechnet, das beim Start in der Anwendung gespeichert wurde. Diese neue Simulation wird der Liste der bereits durchgeführten und in der Sitzung gespeicherten Simulationen hinzugefügt.
Schließlich wird die Ansicht [simulations] durch die folgende Prozedur [displaySimulations] angezeigt:
Private Sub afficheSimulations(ByRef simulations As DataTable, ByRef lien As String)
' we link the datagrid to the simulations source
With dgSimulations
.DataSource = simulations
.DataBind()
End With
' link
lnkForm2.Text = lien
' the views
panelsimulations.Visible = True
panelerreurs.Visible = False
panelform.Visible = False
End Sub
Die Prozedur hat zwei Parameter:
- eine Liste von Simulationen in [simulations] vom Typ [DataTable]
- einen Linktext in [link]
Die Datenquelle [simulations] ist an die Komponente gebunden, die für ihre Anzeige zuständig ist. Der Linktext wird in die Eigenschaft [Text] des Objekts [LinkButton] in der Ansicht gesetzt.
Wenn der Benutzer in der Ansicht [form] auf die Schaltfläche [Delete] klickt, wird die Prozedur [btnDelete_click] ausgeführt (immer nach [Page_Load]):
Private Sub btnEffacer_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnEffacer.Click
' displays the empty form
razForm()
afficheFormulaire()
End Sub
Private Sub razForm()
' empty the form
rdOui.Checked = False
rdNon.Checked = True
txtEnfants.Text = ""
txtSalaire.Text = ""
End Sub
Der obige Code ist so einfach, dass er keiner Kommentare bedarf. Wir müssen noch die Klicks auf die Links [Fehler] und [Simulationen] in der Ansicht behandeln:
Private Sub lnkForm1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles lnkForm1.Click
' displays the form
afficheFormulaire()
End Sub
Private Sub lnkForm2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles lnkForm2.Click
' displays the form
afficheFormulaire()
End Sub
Beide Prozeduren zeigen lediglich die Ansicht [form] an. Wir wissen, dass die Felder in dieser Ansicht einen Wert erhalten, der entweder der für sie gesendete Wert oder ihr vorheriger Wert ist. Da in diesem Fall die POST-Anfrage des Clients keine Werte für die Formularfelder sendet, werden diese auf ihre vorherigen Werte zurückgesetzt. Das Formular wird daher mit den vom Benutzer eingegebenen Werten angezeigt.
8.9.4. Tests
Alle von der Anwendung benötigten Dateien befinden sich in einem Ordner namens <application-path>: ![]() | Der Ordner [bin] enthält die DLL mit den von der Anwendung benötigten Klassen [impot], [impotsData] und [impotsOLEDB]: |
Falls gewünscht, kann der Leser in Kapitel 5 nachlesen, wie die oben erwähnte Datei [impot.dll] erstellt wird. Sobald dies erledigt ist, wird der Cassini-Server mit den Parametern (<application-path>,/impots6) gestartet. Anschließend rufen wir die URL [http://impots6/main.aspx] über einen Browser auf:

Wenn Sie die ACCESS-Datei [impots.mdb] in [impots1.mdb] umbenennen, wird die folgende Seite angezeigt:

8.9.5. Fazit
Wir haben eine MVC-Anwendung, die ausschließlich serverseitige Komponenten verwendet. Durch den Einsatz dieser Komponenten konnten wir die Präsentationsschicht der Anwendung vollständig von ihrer Steuerungsschicht trennen. Dies war bisher nicht möglich, da der Präsentationscode zuvor Variablen enthielt, die vom Steuerungscode berechnet wurden und deren Werte HTML-Code enthielten. Dies ist nun nicht mehr der Fall.






















