Wikibooks
nlwikibooks
https://nl.wikibooks.org/wiki/Hoofdpagina
MediaWiki 1.47.0-wmf.3
first-letter
Media
Speciaal
Overleg
Gebruiker
Overleg gebruiker
Wikibooks
Overleg Wikibooks
Bestand
Overleg bestand
MediaWiki
Overleg MediaWiki
Sjabloon
Overleg sjabloon
Help
Overleg help
Categorie
Overleg categorie
Transwiki
Overleg transwiki
Wikijunior
Overleg Wikijunior
TimedText
TimedText talk
Module
Overleg module
Event
Event talk
Programmeren in ASP.NET/Eerste pagina
0
3425
428819
425769
2026-05-23T12:16:33Z
Erik Baas
2193
lf
428819
wikitext
text/x-wiki
{{Index Programmeren in ASP.NET}}
==Hello World in HTML==
Dit is wat we willen bereiken, maar nu nog geschreven in statische HTML:
''helloworld.html''
<syntaxhighlight lang="HTML">
<html>
<head>
<title>ASP.NET hi people</title>
</head>
<body>
<p>Hello World!</p>
</body>
</html>
</syntaxhighlight>
==Hello World in ASP.NET==
===Zuiver HTML===
Door een bestaande HTML-pagina te nemen en eenvoudigweg de extensie te veranderen in aspx, krijg je een perfect aanvaardbare ASP.NET-pagina. Het enige wat gebeurt is dat de webserver het aspx-bestand nu door de ASP.NET runtime stuurt. De ASP.NET runtime compileert het bestand en verwerkt alle code die het vindt (er is geen code in dit geval) vooraleer het resultaat naar de cliënt gaat.
''helloworld.aspx''
<syntaxhighlight lang="asp"><html>
<head>
<title>ASP.NET Hello World</title>
</head>
<body>
<p>Hello World!</p>
</body>
</html></syntaxhighlight>
Het enige dat werd veranderd is de bestandsnaam. Als de ASP.NET runtime geen enkele code vindt, laat het alles zoals het is, en geeft het door aan de browser.
Hoewel dit allemaal perfect toegelaten is, wordt er natuurlijk weinig uitgevoerd. Laat ons daarom verdergaan naar een versie die tenminste enige verwerking doet.
===De klassieke manier met ASP ===
Een van de goede eigenschappen van ASP.NET is dat de meeste klassieke ASP-code gewoon blijft werken met een minimum aan veranderingen. Als je al ASP kent is het gemakkelijk te zien wat er gebeurt in de code hieronder. Behalve het gebruik van VB in plaats van VBScript is er eigenlijk geen verschil met een klassiek ASP-script.
''helloworld2.aspx''
<syntaxhighlight lang="asp"><%@ Page Language="VB" %>
<html>
<head>
<title>ASP.NET Hello World</title>
</head>
<body>
<p><%= "Hello World!" %></p>
<p><%= Now() %></p>
</body>
</html></syntaxhighlight>
Om de inline-code (soms ook een render block genoemd) te kunnen verwerken, moet de server weten in welke taal de code geschreven is. De eerste regel in de code hierboven vertelt aan de ASP.NET-runtime-engine dat je Visual Basic (VB) gebruikt als standaardtaal voor de pagina.
Verder staat er in de pagina een standaard Response.Write()-regel die de <%= %> afkorting gebruikt zoals in ASP. Je had ook <% Response.Write("Hello World!") %> kunnen gebruiken in de plaats van <%= "Hello World!" %>.
De code hierboven lijkt bekend, maar ze toont een van de beperkingen van klassieke ASP-scripting. Als je de zin "Hello World!" wil bekomen tussen twee paragraaf-tags, dan moet je de code juist zetten op die plaats. Hierdoor wordt het moeilijk een structuur te krijgen in de code, en krijg je de zogenaamde "spaghetti-code". Het schrijven zelf is niet moeilijk, maar wel het lezen. Andere programmeurs hebben dikwijls uren nodig om de code te ontcijferen.
Nu komt ASP.NET van pas.
{{Bladeren2
|Boek=Programmeren in ASP.NET
|vorige=Server
|huidige=Eerste pagina
|volgende=HTML-controls
}}
{{Sub}}
b7wbednv4ct1uti0wezqsnew7cjw5vu
Programmeren in ASP.NET/HTML-controls
0
3426
428820
425777
2026-05-23T12:17:04Z
Erik Baas
2193
lf
428820
wikitext
text/x-wiki
{{Index Programmeren in ASP.NET}}
==Wat is een server-control?==
Vooraleer je begint met HTML-server-controls, moet je een basisconcept hebben van wat een server-control is.
Server-controls zijn speciale tags die door de webserver op ongeveer dezelfde manier verwerkt worden als HTML-tags door je browser. Je kunt server-control-tags herkennen doordat ze een runat="server" attribuut hebben. Dit helpt de server om ze te onderscheiden van standaard HTML-tags of van andere soorten tekst waar de server niets mee te maken heeft.
Eigenaardig genoeg bestaat er geen runat="client" attribuut. Als je een pagina opvraagt met het "runat"-attribuut ingesteld als client (of iets anders) krijg je een "parser error" die je zegt dat "The Runat attribute must have the value Server."
Wanneer de server een server-control tegenkomt zal hij in het geheugen een object aanmaken dat die server-control voorstelt. Dit object kan property's en methodes hebben, en het kan zelfs server-events oproepen tijdens de verwerking van de ASP.NET pagina. Als de verwerking gedaan is, zal de control zijn output in de vorm van HTML opmaken en dit wordt dan naar de browser gestuurd als onderdeel van de resulterende pagina.
Er zijn vijf soorten server-controls:
#HTML-controls
#web-controls
#user-controls
#custom controls
#web parts
Dit hoofdstuk behandelt de eerste soort server-controls meer in detail: HTML-controls.
Het volgende hoofdstuk gaat over web-controls. <!--, user-controls worden uitgelegd in hoofdstuk 20, en custom controls in hoofdstuk 21.-->
==Wat zijn HTML-controls?==
HTML-server-controls zijn eenvoudig een verzameling server-controls die erg lijken op hun overeenkomstige HTML-tags. In feite moet je om een HTML-server-control op een pagina te declareren alleen een bestaande HTML-tag nemen en het eerder genoemde runat="server"-attribuut toevoegen.
Als er een HTML-server-control is die correspondeert met de HTML-tag die je hebt "gecontroliseerd", wordt de HTML-tag het overeenkomstige type van server-control. Anders zal het eenvoudig een HTML-control worden van het standaardtype HtmlGenericControl.
===HTML-controls===
De eerste soort van server-control, de HTML-control, lijkt erg veel op een standaard HTML-tag. Het enige verschil is dat zij een speciaal runat="server" attribuut bevat. Hier is een simpel voorbeeld met alleen HTML:
''imagevoorbeeld.htm''
<syntaxhighlight lang="HTML"><html>
<head>
<title>ASP.NET image</title>
</head>
<body>
<img id="imgVoorbeeld" src="images/voorbeeld.gif" />
</body>
</html></syntaxhighlight>
In een eerste stap maken we er een aspx-pagina van:
''imagevoorbeeld1.aspx''
<syntaxhighlight lang="vb"><%@ Page Language="VB" %>
<html>
<head>
<title>ASP.NET image</title>
</head>
<body>
<img id="imgVoorbeeld" src="images/voorbeeld.gif" runat="server" />
</body>
</html></syntaxhighlight>
Een gewone image zou op deze manier geschreven worden:
<img id="imgVoorbeeld" src="images/voorbeeld.gif">
Om er een HTML-control van te maken, voeg je runat="server" toe.
<img id="imgVoorbeeld" src="images/voorbeeld.gif" runat="server" />
Als je Visual Studio gebruikt, kan je gewoon rechtsklikken op het HTML-element in Design View en "Run as Server Control" selecteren in het snelmenu.
De afbeelding heeft het runat="server"-attribuut gekregen, waardoor ze in een HTML-control veranderd is. De tag kreeg ook een id-attribuut zodat je ernaar kan refereren in je code. Zo geef je dus een naam aan een HTML-control.
De eerste regel is het zogenaamde "Page-directief", waarin de taal van de pagina ingesteld wordt. Voorlopig is er nog geen code aanwezig.
De HTML-code van het resultaat is de volgende:
<syntaxhighlight lang="HTML"><html>
<head>
<title>ASP.NET image</title>
</head>
<body>
<img src="/images/voorbeeld.gif" />
</body>
</html></syntaxhighlight>
Het runat="server"-attribuut is in het resultaat verdwenen, net zoals de eerste regel.
De coderegel om de afbeelding te veranderen is nu heel gemakkelijk:
imgVoorbeeld.src = "images/bloem.gif"
Je gebruikt dus de ID van de control om de eigenschappen ervan in te stellen.
Merk op hoe de property van de control (.src) dezelfde naam heeft als het attribuut van de overeenkomstige HTML <img>-tag (src).
''imagevoorbeeld2.aspx''
<syntaxhighlight lang="vb"><%@ Page Language="VB" %>
<script runat="server">
Sub Page_Load(ByVal Sender As Object, ByVal E As EventArgs)
imgVoorbeeld.src = "images/bloem.gif"
End Sub
</script>
<html>
<head>
<title>ASP.NET image</title>
</head>
<body>
<img id="imgVoorbeeld" src="images/voorbeeld.gif" runat="server" />
</body>
</html></syntaxhighlight>
Opmerkingen
*de code staat tussen <script>-tags, die ook weer het attribuut runat="server" hebben.
*in deze pagina staat de code binnen een subroutine Page_Load. Deze routine is in feite een event dat wordt uitgevoerd telkens vóór de pagina in HTML omgezet wordt.
*Page_Load heeft een welbepaalde signatuur: er zijn 2 vaste parameters nodig. Dit is de juiste schrijfwijze:
Sub Page_Load(ByVal Sender As Object, ByVal E As EventArgs)
In het geval van Page_Load worden deze parameters (Sender en E) zelden gebruikt.
*Je kan Page_Load ook snel toevoegen in Visual Studio door te dubbelklikken op het formulier.
*alle attributen van de HTML-control (hier de afbeelding) zijn toegankelijk in de code onder de vorm controlID.naamAttribuut. In het voorbeeld wordt het src-attribuut van de afbeelding gewijzigd door aan imgVoorbeeld.src een andere waarde te geven.
*de afbeelding wordt eerst ingesteld ("design time") op "images/voorbeeld.gif", maar daarna wordt dit in Page_Load ("run time") veranderd in "images/bloem.gif". Het is deze laatste afbeelding die de gebruiker te zien krijgt.
Nog een stapje verder: nu voeg je een knop toe, en deze knop krijgt een onServerClick-attribuut (hier met de waarde actieKlik). Vervang Page_Load door actieKlik.
''imagevoorbeeld3.aspx''
<syntaxhighlight lang="vb"><%@ Page Language="VB" %>
<script runat="server">
Sub actieKlik(Sender As Object, E As EventArgs)
imgVoorbeeld.src = "images/bloem.gif"
End Sub
</script>
<html>
<head>
<title>ASP.NET image</title>
</head>
<body>
<form runat="server">
<img id="imgVoorbeeld" src="images/voorbeeld.gif" runat="server" />
<input id="btnActie" type="button" value="Actie" runat="server"
onServerClick="actieKlik" />
</form>
</body>
</html></syntaxhighlight>
Nu kan je de afbeelding veranderen door op de knop te klikken.
Opmerkingen
*Om dit te laten werken, moet je ook een <form>-tag toevoegen. Deze moet ook het runat="server" attribuut hebben.
*De subroutine actieKlik is nu de event-handler voor wanneer er op de knop geklikt wordt.
Deze event-handler heeft dezelfde signatuur als Page_load:
Sub actieKlik(Sender As Object, E As EventArgs)
De eerste parameter Sender verwijst naar het object dat het event veroorzaakt, in dit geval btnActie. De tweede parameter E bevat bijkomende informatie over het event. Later zullen we deze parameters soms gebruiken.
Zelfs een simpele <p>-tag kan een HTML-control worden, zoals in het voorbeeld hieronder:
''helloworld3.aspx''
<syntaxhighlight lang="vb"><%@ Page Language="VB" %>
<script runat="server">
Sub Page_Load(Sender As Object, E As EventArgs)
HelloWorld.InnerText = "Hello World! " & Now()
End Sub
</script>
<html>
<head>
<title>ASP.NET Hello World</title>
</head>
<body>
<p id="HelloWorld" runat="server"></p>
</body>
</html></syntaxhighlight>
Nota: de <p>-tag heeft geen overeenkomstige HTML-control en wordt daarom verwerkt als een control van het type HtmlGenericControl. Deze heeft een eigenschap InnerText, die je kan gebruiken om de inhoud van de tag te veranderen.
==Hoe werkt het?==
Bij het opvragen van deze pagina merkt de server dat het een aspx-pagina is, en zal de ASP.NET-engine in werking treden. De eerste keer wordt de pagina gecompileerd. Dit betekent dat de code vertaald wordt in machinecode, en deze wordt opgeslagen in een uitvoerbaar bestand. ASP.NET gebruikt hiervoor de extensie .dll (van Dynamic Link Library).
Je vindt deze DLL terug in de folder "c:\Windows\Microsoft.NET\Framework\vx.x.xxxx\Temporary ASP.NET Files"
(vervang indien nodig c:\Windows door de juiste folder waar Windows geïnstalleerd werd, en vx.x.xxxx door de versie van het .NET framework).
Daarna wordt bij het opvragen van de pagina altijd deze DLL gebruikt. Alle volgende aanvragen zullen dus sneller verwerkt worden, omdat het compileren niet meer moet gebeuren. Als je het originele bestand wijzigt, dan wordt de DLL wel opnieuw gecompileerd. Dit gebeurt volledig automatisch bij de eerste aanvraag. ASP.NET vergelijkt hiervoor de datum van het aspx-bestand en van de DLL.
Deze DLL bevat nu de juiste code om een HTML-pagina aan te maken, en deze pagina wordt uiteindelijk naar de gebruiker gestuurd.
==Het nut van HTML-controls==
HTML-server-controls weerspiegelen dus hun overeenkomstige HTML-tags en voeren eenvoudig de HTML-tags uit tijdens het gebruik. Waarom heb je die controls dan nodig?
De controls vereenvoudigen sterk het werken met de property's en attributen van de HTML-tags. Ze laten je ook toe de logica die de tags beïnvloedt weg te verplaatsen van de tags zelf. Zo kan je nettere code schrijven.
''0to9.aspx''
<syntaxhighlight lang="vb"><%@ Page Language="VB" %>
<script runat="server">
Sub Page_Load(Sender as Object, E as EventArgs)
Randomize()
Dim int0to9 As Integer = Math.Floor(Rnd()*10)
imgVoorbeeld.Src = "images/digit_" & int0to9 & ".gif" ' stel afbeelding in
imgVoorbeeld.Alt = int0to9
End Sub
</script>
<html>
<head>
<title>ASP.NET Number Images</title>
</head>
<body>
<img id="imgVoorbeeld" runat="server" />
</body>
</html></syntaxhighlight>
Als je deze pagina opvraagt krijg je bijvoorbeeld dit resultaat:
<syntaxhighlight lang="HTML"><html>
<head>
<title>ASP.NET Number Images</title>
</head>
<body>
<img src="images/digit_4.gif" id="imgVoorbeeld" alt="4" />
</body>
</html></syntaxhighlight>
Merk op dat er geen enkele variabele of geen enkele code buiten het ene nette script blok staat. Server-controls maken deze flexibiliteit mogelijk. Je kan zelfs alle code in een apart bestand (bv. 0to9.aspx.vb) zetten. Dit doe je door bij de creatie van een nieuwe pagina de optie "Place code in separate file" aan te vinken. In de pagina krijg je dan bij het Page-directief de volgende attributen:
*Versie 1.1: Codebehind="0to9.aspx.vb" Inherits="0to9".
*Versie 2.0: CodeFile="0to9.aspx.vb" Inherits="0to9"
==Hoe gebruik je ze?==
Het codevoorbeeld hierboven heeft je een idee gegeven hoe HTML-controls gebruikt worden. Voor alle duidelijkheid is hier een lijst die illustreert hoe je kan spelen met sommige van de property's en methodes van een HtmlGenericControl.
Hier is een lijst met alle HTML-controls die beschikbaar zijn in ASP.NET. Al deze controls schrijven standaard HTML naar het webformulier:
{| class="wikitable"
|-
|'''Control'''||'''Beschrijving'''||'''Belangrijkste eigenschappen'''||'''Resultaat in HTML'''
|-
|HtmlGenericControl||Kan gebruikt worden voor tags waar geen andere HTML-control voor bestaat, zoals <body>, <span>, <p> of <div>||InnerText InnerHTML ||
|-
|HtmlAnchor||Link of anchor||href, Target||<pre><a href="www.com"> </a></pre>
|-
|HtmlForm||Formulier||Method, Target||<pre><form runat="server"></form></pre>
|-
|HtmlInputText||Invoerveld ||Value, Size||<pre><input type="text" runat="server" /></pre>
|-
|HtmlInputText (Password)||Invoerveld voor wachtwoorden||Value||<pre><input type="password" runat="server" /></pre>
|-
|HtmlTextArea||Invoerveld dat meerdere regels toelaat.||Value, Size, Rows||<pre><input type="textarea" runat="server"></textarea></pre>
|-
|HtmlInputHidden||Verborgen veld||Value||<pre><input type="hidden" runat="server" /></pre>
|-
|HtmlButton ||Knop||Value||<pre><input type="button" runat="server" /></pre>
|-
|HtmlInputReset ||Reset knop||Value||<pre><input type="reset" runat="server" /></pre>
|-
|HtmlInputSubmit||Submit knop||Value||<pre><input type="submit" runat="server" /></pre>
|-
|HtmlInputFile||Toont een tekstveld en een Browse knop op het formulier, zodat de gebruiker een bestand van zijn computer kan selecteren.||Value||<pre><input type="file" runat="server" /></pre>
|-
|HtmlInputCheckBox ||aankruisvakje||Checked||<pre><input type="checkbox" runat="server" /></pre>
|-
|HtmlInputRadioButton||radioknop||Checked, Value||<pre><input type="radio" runat="server" /></pre>
|-
|HtmlImage||Toont een afbeelding||Src, Alt||<pre><img src="bloem.gif" runat="server" /></pre>
|-
|HtmlInputImage||Zelfde als HtmlImage, maar werkt als een knop||Src||<pre><input type="image" src="bloem.gif" runat="server" /></pre>
|-
|HtmlTable||laat toe om informatie in tabelvorm te presenteren.||Rows||<pre>
{| runat="server"
|}</pre>
|-
|HtmlTableRow||Rij in een HtmlTable||Cells||<pre><tr> </tr></pre>
|-
|HtmlTableCell||Cel in een HtmlTableRow||InnerHTML||<pre><td> </td></pre>
|-
|HtmlSelect||Toont een lijst met items||Value, SelectedIndex, Size, Items, Multiple||<pre><select size="2" runat="server"></select></pre>
|-
|HtmlHead (2.0)||Geeft toegang tot de <head>-tag in een pagina|| ||
|-
|HtmlLink (2.0)||Geeft toegang tot de <link>-tag in een pagina|| ||
|-
|HtmlTitle (2.0)||Geeft toegang tot de <title>-tag in een pagina|| ||
|}
Aan de meeste HTML-controls kan je client-side-events koppelen, zoals onClick, onFocus en onMouseOver. Deze events worden dan gekoppeld aan standaard JavaScript-code, die op de client uitgevoerd wordt.
Daarnaast zijn er ook enkele events die op de server kunnen uitgevoerd worden:
{| class="wikitable"
|-
|''Server-Side Event''||'''Beschrijving'''||'''Beschikbaar bij'''
|-
|OnServerChange||Gebeurt op de server als de waarde van de control veranderd is ten opzichte van de vorige post||HtmlInputText, HtmlTextArea, HtmlSelect, HtmlInputCheckbox, HtmlInputRadiobutton, HtmlInputHidden
|-
|OnServerClick||Gebeurt op de server als er op de control geklikt wordt. ||HtmlButton, HtmlAnchor, HtmlInputButton, HtmlImage
|}
In dit voorbeeld worden drie knoppen getoond met zowel onClick- als onServerClick-events:
''serverclicktest.aspx''
<syntaxhighlight lang="vb"><%@ Page Language="VB" EnableViewState="False" %>
<script runat="server">
Sub Page_Load(Sender As Object, E As EventArgs)
button1.value="Button1 - gewijzigd"
button2.value="Button2 - gewijzigd"
'button3.value="Button3 - gewijzigd" ' Werkt niet: geen server control
End Sub
Sub SButton_Click(sender As Object, e As EventArgs)
label.InnerHtml = "geklikt via server"
End Sub
</script>
<html>
<head>
<script language="JavaScript">
function Button_Click(i) {
document.form2.tekstvak.value="geklikt op knop "+i;
}
</script>
</head>
<body>
<form runat="server">
<!-- server side button: onClick werkt wel,
maar het resultaat verdwijnt door postBack -->
<input id="Button1" onclick="Button_Click(1);" type="button"
value="Button1" runat="server" onServerClick="SButton_Click" />
<br>
<!-- server side button zonder onServerClick -->
<input id="Button2" onClick="Button_Click(2);" type="button"
value="Button2" runat="server" />
<br>
<!-- client side button: geen onServerClick ! -->
<input id="Button3" onClick="Button_Click(3);" type="button"
value="Button3" />
</form>
<p id="label" runat="server">
</p>
<form name="form2">
<input type="text" name="tekstvak" />
</form>
</body>
</html></syntaxhighlight>
Merk op dat je voor het onClick-event de functie opgeeft inclusief de haakjes en eventuele parameters (zoals Button_Click(1) ), terwijl je voor het onServerClick-event alleen de naam van de functie opgeeft. Parameters zijn daar niet toegelaten, ASP.NET kent zelf de standaard parameters toe.
==Oefeningen==
#Maak een pagina met twee invoervakken voor getallen, een knop en een label. Als er op de knop gedrukt wordt, komt in het label de som van de twee invoervakken.
#Maak een pagina met een keuzelijst met kleuren en een knop. Bij het selecteren van een kleur en het drukken op de knop krijgt de pagina-achtergrond de gekozen kleur. Om de achtergrondkleur in te stellen vervang je de <body>-tag door <body id="bodytag" runat="server">, en je zet de kleur met bodytag.Attributes("bgcolor")=kleur (waarin kleur bijvoorbeeld de waarde "green" kan hebben).
#Maak een pagina met 4 titels van cursussen die je elk kan aanvinken met een aankruisvak. Maak ook een knop met de titel "Alles". Als je op deze knop klikt, worden alle 4 titels automatisch aangekruist.
==Een control dynamisch aanmaken==
Soms wil je controls in runtime aanmaken. Het kan bijvoorbeeld zijn dat je op voorhand niet weet of je de control nodig hebt, of dat je een variabel aantal controls nodig hebt.
Dit is de code om een HtmlInputText-control toe te voegen aan een formulier met id "formulier1":
Dim ctl As HtmlInputText
ctl = new HtmlInputText()
ctl.ID = "Text1"
ctl.Value = "Dit is mijn tekstvak"
formulier1.Controls.Add(ctl)
Voorbeeld<br>
Maak een pagina waar je een getal kan ingeven (bijvoorbeeld: het aantal kinderen). Bij het drukken op submit moeten er evenveel tekstvakken bijkomen op dezelfde pagina.
''dynamisch.aspx''
<syntaxhighlight lang="vb"><%@ Page Language="VB" %>
<script runat="server">
Sub toonVakVoorKinderen(Sender As Object, E As EventArgs)
Dim n As Integer = txtAantal.Value
Dim i As Integer
For i=1 To n
Dim InputText As HtmlInputText
InputText = new HtmlInputText()
InputText.ID = "Text" & i
formulier1.Controls.Add(InputText)
Next i
End Sub
</script>
<html>
<head>
<title> Dynamisch </title>
</head>
<body>
<form id="formulier1" runat="server">
<input type="text" id="txtAantal" runat="server" ><br>
<input type="button" id="btnVerstuur" value="Versturen"
runat="server" onServerClick="toonVakVoorKinderen" />
</form>
</body>
</html></syntaxhighlight>
Je kan hetzelfde soort functionaliteit ook bekomen met behulp van datacontrols, zoals de Repeater<!-- (zie hoofdstuk 17)-->.
Een volledig overzicht over HTML-controls kan je hier vinden (Engelstalig):
*https://www.w3schools.com/aspnet/aspnet_refhtmlcontrols.asp
*https://www.aspalliance.com/aspxtreme/aspnet/syntax/aspsyntaxforhtmlcontrols.aspx
{{Bladeren2
|Boek=Programmeren in ASP.NET
|vorige=Eerste pagina
|huidige=HTML-controls
|volgende=Foutzoeken
}}
{{Sub}}
d3hm11u91v1wd4yocsurinornapdrmz
Programmeren in ASP.NET/Foutzoeken
0
3433
428824
425782
2026-05-23T12:17:11Z
Erik Baas
2193
lf
428824
wikitext
text/x-wiki
{{Index Programmeren in ASP.NET}}
Vooraleer we verder gaan, is het goed al iets meer te weten over de mogelijkheden in ASP.NET om fouten op te sporen (het zogenaamde "debuggen").
==ASP.NET-pagina's debuggen==
Computers zijn domme machines: ze doen alleen maar wat je vraagt. Als je verkeerde opdrachten geeft, zal de computer dikwijls toch proberen ze uit te voeren, met alle mogelijke gevolgen.
Vooraleer we verder gaan, is het interessant om eerst meer te weten over hoe je fouten kan opsporen in je pagina's.
Er zijn twee soorten fouten: compileerfouten en runtime-fouten.
#''Compileerfouten'' treden op tijdens het compileren van de code (het controleren op taalfouten en het vertalen naar uitvoerbare code). Zo krijg je bijvoorbeeld een fout als je een If-statement gebruikt zonder het bijhorende End If-statement.<br>Als je de pagina bekijkt via localhost (dus op je eigen pc), dan wordt de regel waarin de fout is aangetroffen in de pagina weergegeven met enkele omliggende regels. Verder wordt gemeld wat de fout is. Met deze informatie kan je bepalen waardoor de fout optreedt en dit aanpassen. Gewone gebruikers, die de pagina van op afstand (remote) bekijken, krijgen een algemene foutboodschap (tenzij je speciale instellingen gebruikt).
#''Runtime-fouten'' treden op terwijl de pagina uitgevoerd wordt (na het compileren). Er kan dan een situatie ontstaan waarbij het programma niet meer verder kan, bijvoorbeeld als je probeert deze code uit te voeren:
Dim i As Integer = "test"
Dan wordt om veiligheidsredenen alleen een algemene foutmelding getoond.
Tijdens de ontwikkelfase van je website is dit over het algemeen echter niet voldoende om de fout te kunnen oplossen, en wil je graag de regels code zien die de fout veroorzaken. Je kan ervoor zorgen dat de regels code wel worden weergegeven door dit in de pagina-declaratie aan te geven, als volgt:
<%@ Page Debug="true" %>
Je kan dit ook voor de hele website of voor een bepaalde subfolder inschakelen door het [[Programmeren_in_ASP.NET/Configuratiebestanden#web.config|configuratiebestand web.config]] aan te passen. Het voorbeeld hieronder zorgt ervoor dat de foutieve code voor alle pagina's getoond wordt (tenzij in de pagina zelf anders aangegeven met Debug="false").
''web.config''
<pre><configuration>
<system.web>
<compilation debug="true"/>
</system.web>
</configuration></pre>
Wil je ook de fouten kunnen zien vanaf een andere client (remote), dan voeg je ook nog de volgende regel toe:
<customErrors mode="Off" />
Wijzigingen in web.config worden opgepikt zodra de eerstvolgende pagina opgevraagd wordt.
Let op: web.config is een [[XML]]-bestand, en XML is hoofdlettergevoelig!
Zeer belangrijk: vergeet niet het debug-attribuut te verwijderen op het moment dat je applicatie volledig getest is en online gaat (de zogenaamde release-versie).
==Trace gebruiken==
Tracing is het volgen van een programma terwijl het uitgevoerd wordt.
Als een pagina niet goed werkt, of fouten vertoont, dan is het handig om te kunnen zien hoe de pagina opgebouwd wordt en wat de staat is van de pagina en de aanvraag. Door de volgende declaratie bovenin je pagina te plaatsen krijg je onderaan de pagina allerhande informatie over de verwerking van de pagina te zien.
<%@ Page Trace="true" %>
Ook dit kan je voor de hele website aan- of uitzetten. Je kan daarbij onder andere opgeven of de trace-informatie alleen lokaal zichtbaar is, of ook voor externe webbrowsers.
In het web.config-bestand hieronder is de trace-informatie alleen lokaal zichtbaar:
<pre><configuration>
<system.web>
<trace enabled="true" localOnly="true"/>
</system.web>
</configuration></pre>
Als je tracing aan hebt staan, kan je ook de trace-informatie van de laatste 10 opgevraagde pagina's in de website bekijken. Dit kan handig zijn als een fout niet iedere keer optreedt en je wilt vergelijken tussen de verschillende aanvragen.
Dit doe je door in de url de naam van de pagina eenvoudig te vervangen door "trace.axd".
Verder is er ook nog een TraceContext-object dat je kan gebruiken via de eigenschap Trace van het Page-object. Dit object heeft enkele methodes zoals Warn() en Write(), waarmee je zelf informatie in de Trace output kan zetten. Dit helpt je om de toestand van je programma te kennen zonder in de pagina zelf in te grijpen.
Bijvoorbeeld:
If (fout) Then
Trace.Warn("Er gebeurde een fout in regel ... ")
End If
of:
Trace.Write(i) ' toont de waarde van de variabele i op deze plaats in de code
Vergeet natuurlijk weer niet om tracing weer af te zetten in de release-versie. De bovenstaande coderegels met Trace.Warn en Trace.Write mag je wel laten staan: als tracing afstaat hebben ze geen enkel effect.
==Debuggen vanuit de editor==
Code kan naast compilerfouten en runtime-fouten nog een derde soort fouten bevatten: logische fouten. Deze fouten zorgen ervoor dat een programma wel normaal doorgaat, maar verkeerde resultaten geeft.
In dit geval kan het soms zeer moeilijk zijn de plaats van de fout te vinden, omdat het programma zelf de fout niet aangeeft.
Visual Web Developer Express heeft een ingebouwde debugger waarmee je een programma stap voor stap kan doorlopen, en op die manier het verloop kan controleren.
{{Bladeren2
|Boek=Programmeren in ASP.NET
|vorige=HTML-controls
|huidige=Foutzoeken
|volgende=Web-server-controls
}}
{{Sub}}
p24o4gaj1cajbzs4rrhnsf6ou01x5r9
Programmeren in ASP.NET/Web-server-controls
0
3435
428822
425773
2026-05-23T12:17:10Z
Erik Baas
2193
lf
428822
wikitext
text/x-wiki
{{Index Programmeren in ASP.NET}}
==Inleiding==
Web-controls zijn het tweede type van server-control. Zij lijken op [[Programmeren in ASP.NET/HTML-controls|HTML-controls]], maar zijn dikwijls ingewikkelder, en zijn niet noodzakelijk direct verbonden met een HTML-tag. Hierdoor kunnen ze meer flexibel en gemakkelijker te gebruiken zijn. Hun "objectmodel" is gewoonlijk ook complexer. Terwijl HTML-controls gewoonlijk eigenschappen hebben die hun overeenkomstige HTML-tag weerspiegelen, hebben web-controls dikwijls meer abstracte eigenschappen.
Je kan web-controls herkennen doordat de tag begint met <asp:...> en doordat ze een runat="server" attribuut hebben. Hier is een voorbeeld:
<asp:Label id="HelloWorld" runat="server"> voorbeeld </asp:Label>
Web-controls worden ook op de server verwerkt door de ASP.NET-runtime-engine wanneer een pagina waarin ze voorkomen opgevraagd wordt.
Ze worden geïdentificeerd door hen een id-attribuut te geven, dat je dan kan gebruiken om naar de control te verwijzen in je code. Al deze dingen hebben ze gemeen met HTML-controls.
Als uitvoer geven ze de overeenkomstige HTML-code die dan naar de client gestuurd wordt.
De uitvoer van een web-server-control is afhankelijk van het client-platform. Zo zal een web-server-control aangepaste uitvoer produceren als hij opgevraagd wordt vanaf een draagbare telefoon of een PDA.
''helloworld5.aspx''
<pre><%@ Page Language="VB" %>
<script runat="server">
Sub Page_Load(sender As Object, e As EventArgs)
lblHelloWorld.Text = "Hello World!"
End Sub
</script>
<html>
<head>
<title>ASP.NET Hello World</title>
</head>
<body>
<asp:Label id="lblHelloWorld" runat="server"> </asp:Label>
</body>
</html></pre>
Het enige verschil met de code in het vorige hoofdstuk is het gebruik van de control. Er staat een <asp:Label>-tag in de pagina. Deze nieuwe tag is nu het element in de code dat de tekst instelt op "Hello World!". Noteer dat de property veranderd is van InnerText naar eenvoudig Text. Dit komt doordat het objectmodel van de <asp:Label>-tag anders gedefinieerd is dan dat van de HtmlGenericControl die we eerder gebruikten.
Ter herinnering: het Page_Load-event is een event dat opgeroepen wordt wanneer een ASP.NET pagina aangevraagd wordt.
Nota: je moet de tag op een van de volgende twee manieren afsluiten:
1) met de overeenkomstige afsluit-tag:
<asp:Label id="lblHelloWorld" runat="server"> </asp:Label>
2) met />:
<asp:Label id="lblHelloWorld" runat="server" />
===Wat is het verschil?===
Het meest opvallende verschil tussen de twee is dat de tags voor web-controls er niet uitzien zoals HTML-tags. Dit komt doordat ze niet zo nauw verbonden zijn met de basis-HTML-tags zoals HTML-controls. Hoewel HTML-controls gewoonlijk hun overeenkomstige HTML-tag (met de attributen die je instelde) uitgeven, is dat meestal de enige HTML-tag die ze produceren. Web-controls kunnen meerdere HTML-tags produceren in alle mogelijke combinaties (of wat er ook maar nodig is) om hun taak te vervullen. Ze voeren functies van hoger niveau uit en ze weerspiegelen niet noodzakelijk een bepaalde HTML-tag.
Het nadeel van web-controls is dat je minder controle hebt over de geproduceerde HTML-code dan bij HTML-controls.
HTML-controls zijn ook erg handig om bestaande HTML-code om te zetten naar ASP.NET, gewoon door overal runat="server" bij te zetten.
Veel vensterelementen die veel gebruikt worden in Windows zijn als web-controls nu ook op webformulieren te gebruiken, zoals een kalender, een lijst met kolommen, een lijst met aankruisvakjes, enz...
===Wat is het voordeel?===
Hier is een ander voorbeeld dat goed illustreert hoe krachtig sommige van deze web-controls zijn:
''kalendervb.aspx''
<pre><%@ Page Language="VB" %>
<script runat="server">
Sub Calendar1_SelectionChanged (Sender as Object, E as EventArgs)
lblInfo.Text = "Je koos: " & Calendar1.SelectedDate
End Sub
</script>
<html>
<head>
<title>ASP.NET Calendar Web-control Voorbeeld</title>
</head>
<body>
<form runat="server">
<asp:calendar id="Calendar1" runat="server"
onSelectionChanged="Calendar1_SelectionChanged" />
<asp:label id="lblInfo" runat="server" />
</form>
</body>
</html></pre>
Het grootste deel van de listing is redelijk simpel, maar bekijk eventjes de lijn die begint met asp:calendar. Deze lijn maakt een calendar web-control aan en gelijkt op het voorbeeld van het label hierboven.
Nogal simpel, maar kijk eens naar het resultaat in de browser:
[[Afbeelding:Webcontrols_calendar.gif]]
Het is misschien niet de mooiste agenda die je kan vinden (je kan het uitzicht nog veranderen volgens je eigen smaak... dit is het uitzicht met de standaard instellingen), maar het geeft je een hoop mogelijkheden met zeer weinig code!
Dat is precies wat je met een web-control kan doen. Je krijgt een stuk functionaliteit, verpakt als een mooie control met methodes, property's, en events die ermee overeenkomen. Zo heeft de calendar-control een eigenschap SelectedDate die je in je code kan gebruiken om de gekozen datum te manipuleren. Er is ook een event SelectionChanged dat je kan gebruiken om een handeling uit te voeren telkens als de selectie verandert.
==Courante web-controls==
Er worden verschillende controls meegeleverd met het Microsoft .NET Framework. Sommige controls komen min of meer overeen met hun HTML-tegenpartij. Sommige controls leveren bijkomende informatie bij het terugposten naar de server, en sommige controls geven je de mogelijkheid om gegevens in tabelvorm of lijstvorm te tonen. Een aantal controls kan ook rechtstreeks gekoppeld worden aan een databank.
Er zijn talrijke web-controls die geleverd worden samen met ASP.NET: validators, een ad rotator, een repeater, alle soorten controls voor formulieren, een datagrid, een treeview control (boomstructuur), etc.
Als je iets zoekt dat hier nog niet genoemd werd, kan je het waarschijnlijk downloaden van het web, of je kan het zelf schrijven!
===Property's geldig voor alle controls===
Alle web-controls stammen af van een gemeenschappelijke basisklasse, namelijk de System.Web.UI.Webcontrol klasse. Alle eigenschappen van deze klasse worden automatisch ook overgeërfd door elk type web-control.
De tabel hieronder geeft alle property's gemeenschappelijk voor alle web-server-controls, behalve Literal, PlaceHolder, en Xml.
Tabel: Eigenschappen van web server controls (behalve Literal, PlaceHolder en XML):
{| class="wikitable"
|-
|'''Property'''||'''Beschrijving'''
|-
|AccessKey||Zet de toetsenbordcombinatie waarmee je toegang krijgt tot een web-control.
|-
|Attributes||Geeft de collectie attributen die werden toegepast op een web-control. Kan ook individuele attributen opvragen of wijzigen.
|-
|BackColor||Verandert of geeft de achtergrondkleur van een web-control.
|-
|BorderColor||Verandert of geeft de randkleur van een web-control.
|-
|BorderStyle||Verandert of geeft de randstijl van een web-control.
|-
|BorderWidth||Verandert of geeft de randdikte van een web-control.
|-
|CssClass||Verandert of geeft de Cascading Style Sheet (CSS)-klasse die wordt toegepast op een web-control. Komt in de pagina als een "class"-attribuut.
|-
|Enabled||Verandert of geeft een waarde die aangeeft of een web-control geactiveerd is.
|-
|EnableTheming||Indien True, dan wordt een thema toegepast op de control <!--(zie hoofdstuk 27)-->. Alleen vanaf ASP.NET 2.0.
|-
|Font||Verandert of geeft informatie over fontattributen van de web-server-control.
|-
|ForeColor||Verandert of geeft de voorgrondkleur van de control.
|-
|Height||Verandert of geeft de hoogte van de control.
|-
|ID||Geeft de naam van de control in de pagina
|-
|SkinID||Verandert of geeft de ID van de toe te passen skin <!--(zie hoofdstuk 27)-->. Alleen vanaf ASP.NET 2.0.
|-
|Style||Verandert of geeft de verzameling van tekstattributen die verschijnen onder de vorm van een CSS-style-attribuut binnen de tag van de control.
|-
|TabIndex||Verandert of geeft de positie van de control in de tabvolgorde in het huidige document.
|-
|ToolTip||Verandert of geeft de tekst die verschijnt als de gebruiker de muis boven de control laat stilstaan.
|-
|Visible||Indien False, dan wordt de control niet getoond in de pagina (onzichtbaar).
|-
|Width||Verandert of geeft de breedte van een control.
|}
==Lijst met web-controls==
De tabel hieronder toont een lijst met beschikbare web-controls, en enkele van hun meestgebruikte attributen, property's en methodes. Nog meer controls kan je op het internet vinden, gratis of tegen betaling.
Tabel: Server-side controls gebruikt in ASP.NET en webformulieren:
{| class="wikitable"
| colspan="2" |'''Label'''
|-
|Beschrijving||Toont tekst op de HTML-pagina. Komt in de pagina als een <span> tag
|-
|Attributen||Text
|-
|Property's||Text
|-
|Methodes||
|-
|Server-Side events||geen
|-
|Code||<asp:Label id=Label1 runat="server">Label</asp:Label>
|-
| colspan="2" |'''TextBox'''
|-
|Beschrijving||Geeft de gebruiker een invoerzone op een HTML-formulier. Deze kan ook meerdere lijnen bevatten (TextMode=Multiline) of dienen voor de invoer van wachtwoorden (TextMode=Password)
|-
|Attributen||Text, Rows, Columns
|-
|Property's||Text, TextMode
|-
|Methodes||Focus()
|-
|Server-Side events||TextChanged
|-
|Code||<asp:TextBox id=TextBox1 runat="server"></asp:TextBox>
|-
| colspan="2" |'''Button'''
|-
|Beschrijving||Een gewone knop gebruikt om te reageren op click events op de server. Je kan bijkomende informatie doorgeven door de CommandName en CommandArguments property's in te stellen.
|-
|Attributen||Text, CommandName, CommandArgument
|-
|Property's||Text, CommandName, CommandArgument
|-
|Methodes||
|-
|Server-Side events||Click, Command, OnClientClick
|-
|Code||<asp:Button id=Button1 runat="server" Text="Button"></asp:Button>
|-
| colspan="2" |'''LinkButton'''
|-
|Beschrijving||Zelfde functionaliteit als een Button, maar ziet eruit als een hyperlink (er is echter geen URL aan verbonden)
|-
|Attributen||Text, CommandName, CommandArgument
|-
|Property's||Text, CommandName, CommandArgument
|-
|Methodes||
|-
|Server-Side events||Click, Command, OnClientClick
|-
|Code||<asp:LinkButton id=LinkButton1 runat="server">Klik hier</asp:LinkButton>
|-
| colspan="2" |'''ImageButton '''
|-
|Beschrijving||Knop met een afbeelding, die informatie kan doorsturen over de positie van de muis op het moment dat geklikt werd (vergelijkbaar met een image map)
|-
|Attributen||ImageURL, CommandName, CommandArgument
|-
|Property's||ImageURL, CommandName, CommandArgument
|-
|Methodes||
|-
|Server-Side events||Click, Command, OnClientClick
|-
|Code||<asp:ImageButton id=ImageButton1 ImageUrl="knop.gif" runat="server"></asp:ImageButton>
|-
| colspan="2" |'''Hyperlink'''
|-
|Beschrijving||Een normale hyperlink-control die op klikken reageert
|-
|Attributen||Text, NavigateUrl, ImageURL, Target
|-
|Property's||Text, NavigateUrl, ImageURL, Target
|-
|Methodes||
|-
|Server-Side events||geen
|-
|Code||<asp:HyperLink id=HyperLink1 NavigateUrl="test.aspx" runat="server">Klik hier</asp:HyperLink>
|-
| colspan="2" |'''DropDownList'''
|-
|Beschrijving||Een normale uitklapbare lijst-control zoals de HTML-control, maar kan verbonden worden met een gegevensbron
|-
|Attributen||
|-
|Property's||SelectedIndex, SelectedValue, SelectedItem, Items, DataSource, AutoPostback
|-
|Methodes||Items.Add(), DataBind()
|-
|Server-Side events||SelectedIndexChanged
|-
|Code||<asp:DropDownList id=DropDownList1 runat="server"></asp:DropDownList>
|-
| colspan="2" |'''ListBox'''
|-
|Beschrijving||Een normale lijst-control zoals de HTML-control, maar kan verbonden worden met een gegevensbron
|-
|Attributen||Rows, SelectionMode
|-
|Property's||SelectedIndex, SelectedValue, SelectedItem, Items, DataSource, AutoPostback
|-
|Methodes||Items.Add(), DataBind()
|-
|Server-Side events||SelectedIndexChanged
|-
|Code||<asp:ListBox id=ListBox1 runat="server"></asp:ListBox>
|-
| colspan="2" |'''Repeater'''
|-
|Beschrijving||Laat toe om een bepaald sjabloon te herhalen.
|-
|Attributen||DataSource, Items
|-
|Property's||DataSource, Items
|-
|Methodes||DataBind()
|-
|Server-Side events||ItemCommand, ItemCreated, ItemDataBound
|-
|Code||<asp:Repeater id=Repeater1 runat="server"></asp:Repeater>
|-
| colspan="2" |'''DataList'''
|-
|Beschrijving||Laat toe om een bepaald sjabloon te herhalen in rijvorm. Er kan ook geselecteerd en gewijzigd worden. Meerdere kolommen per pagina zijn mogelijk.
|-
|Attributen||DataSource, Items
|-
|Property's||DataSource, Items
|-
|Methodes||DataBind()
|-
|Server-Side events||CancelCommand, EditCommand, DeleteCommand, ItemCommand, SelectedIndexChanged, UpdateCommand, ItemCreated, ItemDataBound
|-
|Code||<asp:DataList id=DataList1 runat="server"></asp:DataList>
|-
| colspan="2" |'''DataGrid'''
|-
|Beschrijving||Laat toe om een bepaald sjabloon te herhalen in tabelvorm.Je kan pagineren, sorteren en formatteren.
|-
|Attributen||DataSource, Items
|-
|Property's||DataSource, Items
|-
|Methodes||DataBind()
|-
|Server-Side events||CancelCommand, EditCommand, DeleteCommand, ItemCommand, SelectedIndexChanged, PageIndexChanged, SortCommand, UpdateCommand, ItemCreated, ItemDataBound
|-
|Code||<asp:DataGrid id=DataGrid1 runat="server"></asp:DataGrid>
|-
| colspan="2" |'''[[Programmeren in ASP.NET/GridView|GridView]] (2.0)'''
|-
|Beschrijving||Dit is een verbeterde DataGrid.
|-
|Attributen||DataSourceID, Rows
|-
|Property's||DataSourceID, Rows
|-
|Methodes||DataBind()
|-
|Server-Side events||CancelCommand, EditCommand, DeleteCommand, ItemCommand, SelectedIndexChanged, PageIndexChanged, UpdateCommand, ItemCreated, ItemDataBound
|-
|Code||<asp:GridView id=GridView1 runat="server"></asp:GridView>
|-
| colspan="2" |'''[[Programmeren in ASP.NET/FormView en DetailsView|FormView]] (2.0)'''
|-
|Beschrijving||Laat toe om een enkel record te tonen uit een gegevenslijst volgens zelf te maken sjablonen. Je kan pagineren, formatteren en wijzigen.
|-
|Attributen||DataSourceID
|-
|Property's||DataSourceID
|-
|Methodes||DataBind()
|-
|Server-Side events||CancelCommand, EditCommand, DeleteCommand, ItemCommand, PageIndexChanged, UpdateCommand, ItemCreated, ItemDataBound
|-
|Code||<asp:Formview id=Formview11 runat="server"></asp:FormView>
|-
| colspan="2" |'''[[Programmeren in ASP.NET/FormView en DetailsView|DetailsView]] (2.0)'''
|-
|Beschrijving||Laat toe om een enkel record in tabelvorm te tonen uit een gegevenslijst.Je kan pagineren, formatteren en wijzigen.
|-
|Attributen||DataSourceID
|-
|Property's||DataSourceID
|-
|Methodes||DataBind()
|-
|Server-Side events||CancelCommand, EditCommand, DeleteCommand, ItemCommand, PageIndexChanged, UpdateCommand, ItemCreated, ItemDataBound
|-
|Code||<asp:Detailsview id=Detailsview11 runat="server"></asp:DetailsView>
|-
| colspan="2" |'''CheckBox'''
|-
|Beschrijving||Gelijkt erg op de normale HTML-checkbox-control
|-
|Attributen||
|-
|Property's||Checked, Text, AutoPostback
|-
|Methodes||
|-
|Server-Side events||CheckedChanged
|-
|Code||<asp:CheckBox id=CheckBox1 runat="server" />
|-
| colspan="2" |'''CheckBoxList'''
|-
|Beschrijving||Toont een groep aankruisvakjes die dynamisch aangemaakt kunnen worden.
|-
|Attributen||
|-
|Property's||DataSource, Items, AutoPostback, RepeatDirection
|-
|Methodes||Items.Add(), DataBind()
|-
|Server-Side events||SelectedIndexChanged
|-
|Code||<asp:CheckBoxList id=CheckBoxList1 runat="server"></asp:CheckBoxList>
|-
| colspan="2" |'''RadioButton'''
|-
|Beschrijving||Gelijkt erg op de normale HTML-radioknop die een rondje toont dat je kan aanvinken
|-
|Attributen||Text, Checked, Groupname
|-
|Property's||Text, Checked, Groupname, AutoPostback
|-
|Methodes||
|-
|Server-Side events||CheckedChanged
|-
|Code||<asp:RadioButton id=RadioButton1 runat="server" />
|-
| colspan="2" |'''RadioButtonList'''
|-
|Beschrijving||Toont een groep radioknoppen die samenwerken.
|-
|Attributen||DataSource
|-
|Property's||Items, SelectedIndex, SelectedValue, SelectedItem, AutoPostback
|-
|Methodes||Items.Add(), DataBind()
|-
|Server-Side events||SelectedIndexChanged
|-
|Code||<asp:RadioButtonList id=RadioButtonList1 runat="server"></asp:RadioButtonList>
|-
| colspan="2" |'''BulletedList (2.0)'''
|-
|Beschrijving||Toont een lijst met bullets.
|-
|Attributen||DataSource, BulletStyle
|-
|Property's||Items
|-
|Methodes||Items.Add(), DataBind()
|-
|Server-Side events||
|-
|Code||<asp:BulletedList id="BulletedList1" runat="server"></asp:BulletedList>
|-
| colspan="2" |'''Image'''
|-
|Beschrijving||Gelijkt erg op de gewone afbeelding in HTML
|-
|Attributen||ImageURL, AlternateText, ImageAlign
|-
|Property's||ImageURL, AlternateText, ImageAlign
|-
|Methodes||
|-
|Server-Side events||geen
|-
|Code||<asp:Image id=Image1 runat="server"></asp:Image>
|-
| colspan="2" |'''ImageMap (2.0)'''
|-
|Beschrijving||Zoals een Image, maar met hot spots waar je kan op klikken
|-
|Attributen||ImageURL
|-
|Property's||ImageURL, HotspotMode
|-
|Methodes||
|-
|Server-Side events||Click
|-
|Code||<asp:ImageMap id=ImageMap1 runat="server" />
|-
| colspan="2" |'''FileUpload'''
|-
|Beschrijving||Gebruikt om bestanden up te loaden.
|-
|Attributen||
|-
|Property's||HasFile, FileName
|-
|Methodes||SaveAs(savePath)
|-
|Server-Side events||
|-
|Code||<asp:FileUpload id=FileUpload1 runat="server" />
|-
| colspan="2" |'''Panel'''
|-
|Beschrijving||Gebruikt om andere controls te groeperen. Komt in de pagina als als een <div> tag.
|-
|Attributen||BackImageURL, Wrap
|-
|Property's||Controls, DefaultButton, ScrollBar
|-
|Methodes||Controls.Add()
|-
|Server-Side events||geen
|-
|Code||<asp:Panel id=Panel1 runat="server">Panel</asp:Panel>
|-
| colspan="2" |'''PlaceHolder'''
|-
|Beschrijving||Dient als een soort opvulsel, waar je later andere server-side controls kan toevoegen (tijdens run-time)
|-
|Attributen||
|-
|Property's||Controls
|-
|Methodes||Controls.Add()
|-
|Server-Side events||geen
|-
|Code||<asp:PlaceHolder id="PlaceHolder1" runat="server"></asp:PlaceHolder>
|-
| colspan="2" |'''MultiView (2.0)'''
|-
|Beschrijving||Dient als container voor View-controls. Slechts een van de View-controls kan op een gegeven moment zichtbaar zijn.
|-
|Attributen||
|-
|Property's||ActiveViewIndex, Views
|-
|Methodes||SetActiveView()
|-
|Server-Side events||Activate, Deactivatie (op de View-controls)
|-
|Code||<asp:MultiView id="MultiView1" runat="server"> </asp:MultiView>
|-
| colspan="2" |'''Wizard (2.0)'''
|-
|Beschrijving||Hiermee kan je een wizard maken, met knoppen voor "Volgende", "Vorige" en "Voltooien". Zet de verschillende stappen van de wizard in aparte WizardStep-templates.
|-
|Attributen||
|-
|Property's||ActiveStepIndex
|-
|Methodes||
|-
|Server-Side events||ActiveStepChanged, NextButtonClick, FinishButtonClick, CancelButtonClick
|-
|Code||<asp:Wizard id="Wizard1" runat="server"> </asp:Wizard>
|-
| colspan="2" |'''Calendar'''
|-
|Beschrijving||Maakt een HTML versie van een kalender. Je kan de datum instellen of opvragen, navigeren, enz...
|-
|Attributen||
|-
|Property's||SelectedDate, SelectedDates, VisibleDate
|-
|Methodes||
|-
|Server-Side events||SelectionChanged, VisibleMonthChanged, DayRender
|-
|Code||<asp:Calendar id=Calendar1 runat="server"></asp:Calendar>
|-
| colspan="2" |'''AdRotator'''
|-
|Beschrijving||Hiermee kan je een lijst met advertenties (banners) opgeven. Deze lijst wordt doorlopen en elke advertentie wordt achtereenvolgens getoond. De lijst maak je in de vorm van een XML-bestand
|-
|Attributen||advertisementfile
|-
|Property's||
|-
|Methodes||
|-
|Server-Side events||AdCreated
|-
|Code||<asp:AdRotator id=AdRotator1 runat="server"></asp:AdRotator>
|-
| colspan="2" |'''Table'''
|-
|Beschrijving||Komt overeen met een HTML-tabel.
|-
|Attributen||Zoals een HTML-tabel
|-
|Property's||Rows, Row(i).Cells
|-
|Methodes||Rows.Add()
|-
|Server-Side events||geen
|-
|Code||<asp:Table id=Table1 runat="server"></asp:Table>
|-
| colspan="2" |'''XML'''
|-
|Beschrijving||Gebruikt om XML-documenten weer te geven in HTML.
|-
|Attributen||
|-
|Property's||
|-
|Methodes||
|-
|Server-Side events||geen
|-
|Code||<asp:Xml id="Xml1" runat="server"></asp:Xml>
|-
| colspan="2" |'''Literal'''
|-
|Beschrijving||Zoals een label, maar het laat je toe letterlijk HTML-code toe te voegen. In tegenstelling tot een label wordt er geen <span> tag gemaakt, en op een literal kan je geen styles toepassen.
|-
|Attributen||Text
|-
|Property's||Text
|-
|Methodes||
|-
|Server-Side events||geen
|-
|Code||<asp:Literal id="Literal1" runat="server"></asp:Literal>
|}
Al deze controls passen hun HTML-uitvoer aan aan de browser van de gebruiker. Als dit Internet Explorer is kan de control er beter uitzien dankzij DHTML-extensies. In het andere geval wordt gewone HTML 3.2 standaard-code doorgestuurd.
===Oefeningen===
#Maak een pagina met een checkbox "Gehuwd" en een invoervak "Naam huwelijkspartner". Alleen als de checkbox aangekruist is, wordt het invoervak getoond.
#Laat de gebruiker een getal invullen. Bij het drukken van een knop toon je de vierkantswortel van dit getal.
#Schrijf een pagina die het gewicht m berekent van een stalen buis, als de lengte l (in m), de dikte d (in mm), en de binnendiameter b (in m) gegeven zijn. De formule is m=3,9 π l d b.
#Maak een pagina met een tekstvak waarin je een stuk HTML-code kan ingeven. Toon het resultaat in dezelfde pagina (bvb. met een Literal-control).
#Maak een pagina waarin je kan kiezen tussen Nederlands of Frans met een radioknop. Afhankelijk van de keuze toon je de (willekeurige) inhoud in de juiste taal.
#Doe hetzelfde, maar laat de gebruiker kiezen uit een lijst met 3 talen.
#Maak een pagina waar je een wachtwoord moet ingeven. Het resultaat toont of het wachtwoord juist was.
#Maak een formulier met een checkbox "Ik wil meer informatie". Als de gebruiker het vakje aankruist, geef je een panel met meer informatie, anders geef je een lege pagina.
#Maak een pagina met twee kalendercontrols. Na het kiezen van twee datums wordt in een label het aantal dagen tussen beide datums getoond.
#Maak een pagina met een kalendercontrol. Bij het klikken op een datum wordt getoond welke dag van de week dit is (maandag, dinsdag, enz.). Gebruik de expressie WeekDayName(WeekDay(datum),0,1) om de dag van de week van een gegeven datum te berekenen.
==Werken met lijstcontrols==
Omdat lijsten (keuzelijsten, radiolijsten, checkboxlijsten en bulletedlists) zo dikwijls voorkomen, en omdat ze een aantal gezamenlijke methodes hebben, bekijken we hier de mogelijkheden.
Er zijn vijf soorten lijsten:
#ListBox
#DropDownList
#RadioButtonList
#CheckBoxList
#BulletedList (ASP.NET 2.0)
Alle vijf zijn ze afgeleid van het type "ListControl". Het grote voordeel hiervan is dat de meeste functies gemeenschappelijk zijn.
Alle lijstcontrols (zoals trouwens ook de HTML-control HtmlSelect) hebben een eigenschap Items. Deze property is van het type "ListItemCollection", en is een verzameling ListItems. Alle wijzigingen aan deze verzameling verschijnen automatisch in de lijstcontrol zelf.
Je kan vanuit Visual Studio items toevoegen via het Properties-paneel. Je kan ook items dynamisch toevoegen, bijvoorbeeld vanuit een databank (zie paragraaf -).
Elk item heeft drie belangrijke property's: Text, Value, Selected en Enabled. Voor een ListBox en een DropDownList komt elk item in de pagina in de vorm van een <option>-tag. Een item met Text "Brussel" en Value 1 krijgt dan deze vorm:
<option value="1">Brussel</option>
Hieronder vind je een aantal veelgebruikte expressies met lijstcontrols.
{| class="wikitable"
|-
|'''Ik wil:'''||'''Ik krijg het met:'''
|-
|het aantal items||mijnLijst.Items.Count
|-
|de index van het geselecteerde item (begint vanaf 0)||mijnLijst.SelectedIndex
|-
|weten of er iets geselecteerd is||If(mijnLijst.SelectedIndex>=0) Then
|-
|weten of het i-de item geselecteerd is (index van het eerste item=0)||If(mijnLijst.Items(i).Selected) Then
|-
|de tekst van het geselecteerde item||mijnLijst.SelectedItem.Text (let op: als er niets geselecteerd is, krijg je een fout)
|-
|de value van het geselecteerde item||mijnLijst.SelectedItem.Value (let op: als er niets geselecteerd is, krijg je een fout)<br>of<br>mijnLijst.SelectedValue (werkt altijd, als er niets geselecteerd is krijg je een lege streng)
|-
|zorgen dat er niets geselecteerd is||mijnLijst.SelectedIndex = -1
|-
|het item met index i selecteren (index van het eerste item=0)||mijnLijst.SelectedIndex = i<br>of<br> mijnLijst.Items(i).Selected = True<br>(deze tweede manier werkt ook indien meerdere selecties tegelijk mogelijk zijn)
|-
|het item met tekst "x" selecteren||<pre>mijnLijst.SelectedIndex=-1
Dim li = mijnLijst.Items.FindByText("x")
If(Not li Is Nothing) Then
li.Selected = True</pre>
|-
|het item met value "x" selecteren||<pre>mijnLijst.SelectedIndex=-1
Dim li = mijnLijst.Items.FindByValue("x")
If(Not li Is Nothing) Then
li.Selected = True</pre>
|-
|een item toevoegen vanuit code (onderaan de lijst)||<pre>Dim li As New ListItem("de tekst","de waarde")
mijnLijst.Items.Add(li)</pre>
|-
|een item toevoegen vanuit code (bovenaan de lijst)||<pre>Dim li As New ListItem("de tekst","de waarde")
mijnLijst.Items.Insert(0,li)</pre>
|-
|het item met index i verwijderen||mijnLijst.Items.RemoveAt(i)
|-
|de lijst leegmaken||mijnLijst.Items.Clear()
|}
Let op: een CheckBoxList kan meerdere geselecteerde items hebben. In een ListBox kan dat ook als de property SelectionMode ingesteld staat op Multiple.
In dat geval geeft SelectedIndex alleen het eerste geselecteerde item aan, en dus moet je de lijst één voor één doorlopen om te kijken welke items er nog geselecteerd zijn. Dat kan met een gewone For-lus:
<pre>Dim aantalGeselecteerd As Integer = 0
Dim i As Integer
For i=0 To mijnLijst.Items.Count-1
If(mijnLijst.Items(i).Selected) Then
aantalGeselecteerd+=1
' doe eventueel iets met dit item
End If
Next i</pre>
of met een For-Each-lus:
<pre>Dim aantalGeselecteerd As Integer = 0
Dim li As ListItem
For Each li In mijnLijst.Items
If(li.Selected) Then
aantalGeselecteerd+=1
' doe eventueel iets met dit item
End If
Next li</pre>
Nog meer voorbeelden vind je op https://www.dnzone.com/ShowDetail.asp?NewsId=671.
'''Let op:'''<br>
Zorg er goed voor dat je nooit een oneindige lus maakt in ASP.NET! De lus wordt immers op de server uitgevoerd, en je krijgt dan na enige tijd een Server Error, maar wat erger is: je vertraagt de server voor alle gebruikers.
'''Opmerking:'''<br>
Je kan ervoor zorgen dat de pagina reageert zodra de gebruiker een selectie maakt in een lijstcontrol. Dit doe je door de property AutoPostBack van de lijstcontrol op True in te stellen.
===Oefeningen===
#Maak een dropdownlijst gevuld met alle getallen van 1 tot 100.
#Maak een pagina met een CheckBoxList met 5 soorten fruit. Als de gebruiker zijn/haar keuze gemaakt heeft toon je het aantal geselecteerde items.
#Maak een pagina met een RadioButtonList met 2 keuzes: "fruit" en "groenten". Zet ook een Listbox op de pagina, met 3 voorbeelden van wat geselecteerd is in de RadioButtonList.
#Zelfde oefening, maar vervang de RadioButtonList door een CheckBoxList.
#Maak een pagina met 5 aankruisvakjes: Tafel, Stoel, Bed, Kast, en Alles. Als je op "Alles" klikt, moeten de 4 andere vakjes automatisch aangekruist worden. Tip: gebruik "AutoPostback".
#Maak een pagina met een keuzelijst, een invoervak, en een knop. Als de gebruiker iets invult in het vak en op de knop drukt, dan wordt dit toegevoegd aan de lijst.
#Zelfde oefening, maar nu ook met een knop "verwijderen", waarmee het geselecteerde item verwijderd wordt.
#Zelfde oefening, maar nu ook met een knop "omhoog" en een knop "omlaag". Het geselecteerde item wordt verplaatst in de lijst.
#Maak een pagina met twee lijsten en twee knoppen. Met de eerste knop breng je een item over van lijst1 naar lijst2, en met de tweede omgekeerd.
==Client-side-gebeurtenissen verwerken==
In tegenstelling tot HTML-controls kan je niet zomaar JavaScript toevoegen aan web-controls om gebeurtenissen zoals bijvoorbeeld OnClick te verwerken. De reden hiervoor is dat sommige web-controls al JavaScript gebruiken om automatische postback te verkrijgen, waardoor OnClick misschien al voor iets anders gebruikt wordt.
Daarom moet je een andere manier gebruiken via de eigenschap "Attributes" van de web-control.
Voorbeeld:<br>
btnSubmit.Attributes.Add("onMouseOver", "bepaaldeClientCode();")
waarin bepaaldeClientCode() een functie uit een client-side JavaScript blok is.
Een veelgebruikt voorbeeld hiervan is een "verwijder"-knop. Meestal wil je dan een waarschuwing tonen, zodat de gebruiker niet per ongeluk op de knop kan klikken.
Dit kan je doen met de volgende code:
btnVerwijder.Attributes.Add("onClick", "return confirm('Ben je wel zeker?');")
Bij knoppen in ASP.NET 2.0 kan het nog eenvoudiger, die hebben een OnClientClick-event, dat je kan instellen. De code hierboven wordt dan:
btnVerwijder.OnClientClick="return confirm('Ben je wel zeker?');"
==Commentaar tussen web-controls ==
Je zou kunnen denken dat je de gewone commentaarcodes (<!-- -->) voor HTML kan gebruiken tussen de web-control-tags. Dit werkt echter niet.
Voor web-controls gebruik je deze commentaartekens:
<%-- --%>
Bijvoorbeeld:
<%-- <asp:Label runat="server">Niet getoond</asp:Label> --%>
Binnen de <script>-tags gebruik je natuurlijk het commentaarteken voor VB (de apostrof).
{{Bladeren2
|Boek=Programmeren in ASP.NET
|vorige=Foutzoeken
|huidige=Web-server-controls
|volgende=Webformulieren
}}
{{Sub}}
1npoesga6m4hu30dexat0blcfcxm4u2
Programmeren in ASP.NET/Webformulieren
0
3437
428825
425770
2026-05-23T12:17:11Z
Erik Baas
2193
lf
428825
wikitext
text/x-wiki
{{Index Programmeren in ASP.NET}}
==Wat is een webformulier?==
Webformulieren zijn het hoofdonderdeel van ASP.NET.
Elk webformulier bevat een <form>-tag met een runat="server" attribuut:
<form id="formulier1" runat="server">
Webformulieren zijn in feite HTML-formulieren die uitgebreid zijn met alle mogelijk eigenschappen, methodes en events om een optimale controle te hebben vanuit een programma. Als je Visual Studio gebruikt, kan je formulierelementen gewoon op het formulier slepen, en vervolgens de code eenvoudig toevoegen.
Webformulieren werken zo dat bij het selecteren uit een lijst of bij het klikken op een knop automatisch server-side code uitgevoerd wordt. Dit gebeurt met zogenaamde postbacks.
Webformulieren bestaan uit twee delen: het HTML-gedeelte in een aspx-bestand (ook het markup-gedeelte genoemd), en de code achter het formulier.
==Het doel van webformulieren==
De nieuwe mogelijkheden in webformulieren zijn:
*Volledige scheiding van HTML-markup en code
*Een uitgebreide verzameling server-side controls die de browser kunnen herkennen en overeenkomstig de juiste HTML doorgeven
*Minder code nodig doordat een deel van de code al in de controls verwerkt is.
*Een programmeermodel gebaseerd op events
*Programmeurs kunnen hun eigen controls maken met aangepaste functionaliteit. Deze controls kunnen ook beschikbaar gemaakt worden voor iedereen.
==Een voorbeeld van een webformulier in Visual Web Developer==
We maken hier een webformulier waarin de gebruiker zijn voornaam en familienaam invult; Daarna kan de gebruiker op de "Login"-knop klikken. De volledige naam verschijnt dan in een label onder de knop.
Om het Login-formulier te maken
*Open Visual Studio en klik "New file..." in het "File"-menu.
*Kies "Web Form" in de lijst
*Kies de naam van de pagina bij "Name", bv. "login.aspx"
*Klik OK om het formulier aan te maken
Nu zou je een webformulier genaamd "login.aspx moeten zien in het middelste venster.
Maak het formulier zoals hierboven door de titels in het formulier te typen, door de juiste web-server-controls erop te slepen, en de eigenschappen in te stellen volgens de tabel hieronder:
Tabel: Controls gebruikt in het Login-formulier:
{| class="wikitable"
|-
|'''Control'''||'''Soort''' ||'''Property'''||'''Waarde'''
|-
|tbVoornaam||TextBox ||Name||"tbVoornaam"
|-
| || ||Text||""
|-
|tbNaam||TextBox ||Name||"tbNaam"
|-
| || || Text||""
|-
|btnSubmit||Button ||Name||"btnSubmit"
|-
| || || Text||"Login"
|-
|lblVolledigeNaam||Label ||Name||"lblVolledigeNaam"
|-
| || ||BorderStyle||"Insert"
|-
| || || Text||""
|}
Je kan de pagina nu al testen door ze op te vragen in je browser (druk F5).
Je kan nu gegevens inbrengen, maar als je op "Login" klikt, gebeurt er nog niks.
==Code aan de knop koppelen==
#Sluit het programma af door de browser te sluiten.
#Zorg dat de pagina in design mode te zien is, en dubbelklik op de "Login"-knop. Een codevenster verschijnt, met de event procedure "btnSubmit" (als je dubbelklikt wordt het default event van de knop aangemaakt).
#Vul deze methode in zodat ze er als volgt uitziet:
<pre>Sub btnSubmit_Click(ByVal sender As Object, ByVal e As EventArgs)
lblVolledigeNaam.Text = tbNaam.Text & ", " & tbVoornaam.Text
End Sub</pre>
Hier wordt de "Text"-eigenschap van zowel de tbNaam als de tbVoornaam invoervakken opgevraagd, en deze gegevens worden in de Label control geplaatst.
De ganse pagina ziet er nu zo uit:
''login.aspx''
<pre><%@ Page Language="VB" %>
<script runat="server">
Sub btnSubmit_Click(ByVal sender As Object, ByVal e As EventArgs)
lblVolledigeNaam.Text = tbNaam.Text & ", " & tbVoornaam.Text
End Sub
</script>
<html>
<head>
</head>
<body>
<form runat="server">
<p>
Voornaam:
<asp:TextBox id="tbVoornaam" runat="server">Voornaam</asp:TextBox>
</p>
<p>
Naam:
<asp:TextBox id="tbNaam" runat="server">Naam</asp:TextBox>
</p>
<p>
<asp:Button id="btnSubmit" onclick="btnSubmit_Click" runat="server"
Text="Login"></asp:Button>
</p>
<p>
<asp:Label id="lblVolledigeNaam" runat="server">Naam</asp:Label>
</p>
</form>
</body>
</html></pre>
Nu kan je de pagina testen.
Als je de pagina voor de eerste keer oproept, ziet de broncode er ongeveer zo uit:
<pre><html>
<head>
</head>
<body>
<form name="_ctl0" method="post" action="login.aspx" id="_ctl0">
<input type="hidden" name="__VIEWSTATE"
value="dDwtMTMwMjU2NjUyMzs7PhIlntyfq+qht9mIdQSMSeZjf1zG" />
<p>
Voornaam:
<input name="tbVoornaam" type="text" value="Voornaam" id="tbVoornaam" />
</p>
<p>
Naam:
<input name="tbNaam" type="text" value="Naam" id="tbNaam" />
</p>
<p>
<input type="submit" name="btnSubmit" value="Login" id="btnSubmit" />
</p>
<p>
<span id="lblVolledigeNaam">Naam</span>
</p>
</form>
</body>
</html></pre>
Je merkt een aantal zaken:
#de code is niet meer te zien
#alle web-controls zijn omgezet in gewone HTML-elementen
#het formulier heeft als action-attribuut de pagina zelf.
#er is een verborgen invoerveld "__VIEWSTATE" met een ingewikkelde waarde. Dit veld wordt gebruikt om vroeger ingevulde waarden te bewaren tussen roundtrips (zie ook hoofdstuk 22).
==Hoe werkt dit webformulier?==
Wanneer een webformulier ingeladen wordt, zijn er een aantal events die opgeroepen worden in een bepaalde volgorde. Er zijn ook events die gebeuren bij bepaalde acties van de gebruiker.
Bij een gewone ASP- of HTML-pagina wordt de pagina verwerkt op een lineaire manier, van boven naar beneden. Bij webformulieren is dat helemaal anders.
Tabel: Volgorde van events in een webformulier
{| class="wikitable"
|-
|'''Event'''||'''Uitleg'''
|-
|opvragen pagina||De gebruiker vraagt een pagina op
|-
|↓||
|-
|code inladen||Wanneer een pagina opgevraagd wordt, zal een DLL (Dynamic Link Library) geladen worden die zowel de tags in de ASPX-pagina als de code in de pagina verwerkt. Indien deze DLL nog niet bestaat of indien ze ouder is dan de ASPX-pagina, dan wordt ze gecompileerd.De pagina wordt in een beginstaat gebracht zoals beschreven in de HTML-tags in het ASPX-bestand.
|-
|↓||
|-
|Page_Preinit()||Hier kan je instellingen doen die moeten gebeuren nog voor Page_Init. Dit wordt gebruikt om bv. een thema via code in te stellen.
|-
|↓||
|-
|Page_Init()||Als je wil kan je in je code het Page_Init() event verwerken om de begintoestand van de pagina verder in te stellen. Als de gebruiker nieuwe waarden ingegeven heeft, dan zijn die nog niet aanwezig op dit moment.
|-
|↓||
|-
|toestand van de pagina herstellen ||Indien de pagina informatie naar zichzelf gepost heeft, zal de staat van de pagina ook hersteld worden dankzij een mogelijke "viewstate" die werd bewaard. Als de gebruiker wijzigingen aangebracht heeft aan de toestand van de pagina, dan worden deze wijzigingen nu ook toegevoegd.
|-
|↓||
|-
|Page_Load()||Vervolgens wordt het Page_Load()-event afgevuurd. Met dit event kan je testen of het de eerste keer is dat de pagina geladen wordt, anders werd de pagina verkregen door een postback van een gebruiker die een knop of een andere control aangeklikt heeft.Het kan zijn de je enige initialisatie wil doen als de pagina voor de eerste keer geladen wordt, bijvoorbeeld het koppelen van informatie aan sommige controls. Let op dat je hier de invoer van de gebruiker niet overschrijft.
|-
|↓||
|-
|Control events||Control-events worden alleen verwerkt in het geval van postback.
#Eerst krijg je alle "change" events. Al deze events worden in de browser verzameld, en ze worden alleen uitgevoerd op het moment dat de pagina teruggestuurd wordt naar de server. Voorbeelden zijn het veranderen van tekst in een invoervak, of het maken van een selectie uit een lijst.
#Vervolgens wordt het control-event afgevuurd dat de postback veroorzaakte. Dit kan een klik op een knop zijn, of "autopostback" change events zoals het CheckedChanged event van een check box.
|-
|↓||
|-
|Page_Prerender()||Dit event geeft je een laatste kans om nog iets aan de pagina te veranderen.
|-
|↓||
|-
|Rendering||Dan wordt de pagina in HTML opgebouwd ("rendered"). Viewstate-informatie wordt toegevoegd in een verborgen veld op de pagina zodat ASP.NET alle informatie krijgt als de pagina opnieuw opgevraagd wordt met een postback. Code tussen <%...%> tags wordt hier ook uitgevoerd.
|-
|↓||
|-
|Naar de client||De pagina wordt naar de browser van de client gestuurd.
|-
|↓||
|-
|Page_Unload()||Er is nog een laatste pagina-event dat je code kan verwerken voor de pagina verdwijnt: Page_Unload(). Omdat de pagina al aangemaakt is, wordt dit event typisch gebruikt voor het opruimen of loggen (informatie op de server bijhouden over wat er gebeurd is).
|-
|↓||
|-
|einde||Tenslotte wordt de klasse die de pagina vertegenwoordigt opgeruimd, en de pagina wordt uit het geheugen van de server gehaald.
|}
Als je de ASPX-pagina of de code verandert, en de pagina wordt daarna weer opgevraagd dan wordt de dynamisch aangemaakte DLL die overeenstemt met de pagina opnieuw aangemaakt. Deze DLL wordt telkens na aanmaak op de schijf bewaard (meestal in de folder c:\Windows\Microsoft.NET\Framework\vx.x.xxxx\Temporary ASP.NET files).
Opmerkingen
#Indien je alleen HTML-server-controls gebruikt in je formulier, dan mag je een action-attribuut toevoegen, om naar een nieuwe pagina te gaan als de gebruiker het formulier indient.
#In dit geval hoeft het formulier soms ook niet het "runat=server" attribuut te hebben.
#In het andere geval (als er dus ook web-controls zijn) zal de server geen rekening houden met het action-attribuut, het posten gebeurt altijd naar het webformulier zelf. Het "runat=server" attribuut is hier altijd vereist voor het formulier. Om de gebruiker door te sturen naar een andere pagina gebruik je dan de [[Programmeren_in_ASP.NET/Veelgebruikte_objecten#Het_HttpResponse-object|Response.Redirect()]] of [[Programmeren_in_ASP.NET/Veelgebruikte_objecten#Het_HttpServerUtility-object|Server.Transfer()]]-methode (zie verder).
#In een formulier kan je de standaard focus instellen op een bepaalde control, dit is de control die initieel de toetsenbordinvoer krijgt van de gebruiker. Stel hiervoor de property DefaultFocus in van het formulier zelf (alleen ASP.NET 2.0)
#Op een panel of formulier kan je ook de property DefaultButton instellen.
==Round trip en postback==
Een interactieve sessie met een gebruiker bestaat meestal uit de volgende stappen:
#De gebruiker vraagt een webformulier op bij de server.
#De webserver stuurt het formulier op.
#De gebruiker geeft data in en dient het formulier in bij de server.
#De server verwerkt het formulier, en stuurt het resultaat op naar de gebruiker.
In deze stappen wordt stap 3 de postback genoemd, terwijl stap 3 en 4 samen een round trip genoemd worden. Een round trip houdt dus een volledige reis over het netwerk naar de webserver en terug met het antwoord.
Om het onderscheid te kunnen maken tussen de eerste aanvraag en de postback aanvraag, kan de server gebruik maken van de IsPostBack eigenschap van het Page object. Deze eigenschap is alleen True bij postback. Bij de eerste aanvraag van een pagina is deze eigenschap False.
Je kan dit gebruiken als je bepaalde operaties alleen de eerste keer wil laten uitvoeren.
==Oefeningen==
#Maak een pagina met 3 multiple-choice vragen. Na het invullen bereken je de score.
#Maak het formulier uit de vorige oefening in het dubbel: éénmaal met HTML-controls en éénmaal met web-controls. Vergelijk.
#Maak een pagina waar je 3 artikelen kan bestellen (met elk een invoervak voor de hoeveelheid). Bereken het totaalbedrag op dezelfde pagina (na het drukken op een knop).
#Je verkoopt pizza's, die je aan huis bestelt. Maak een toepassing bestaande uit 4 pagina's:
##De gebruiker vult het aantal in voor pizza's. Geef keuze tussen 3 soorten.
##De gebruiker vult het aantal in voor drank. Geef keuze tussen 3 soorten drank.
##De gebruiker geeft zijn naam en adres in.
##Het resultaat toont een samenvatting van de bestelling en de totaalprijs.
#Maak een pagina met een formulier om een adres in te vullen. Maak twee externe stylesheet met styles voor deze pagina (bijvoorbeeld "pastel" en "roodwit"). Zorg ervoor dat alle controls gebruik maken van de stylesheet. Maak een keuzeknop waar je de stijl van de ganse pagina in één keer kan omschakelen. Tip: maak van de <link>-tag een HTML-control.
{{Bladeren2
|Boek=Programmeren in ASP.NET
|vorige=Web-server-controls
|huidige=Webformulieren
|volgende=Veelgebruikte objecten
}}
{{Sub}}
lvzhkrj9dkjz9xbyn6y799esna5e9ri
Programmeren in ASP.NET/Veelgebruikte objecten
0
3443
428828
425784
2026-05-23T12:17:16Z
Erik Baas
2193
lf
428828
wikitext
text/x-wiki
{{Index Programmeren in ASP.NET}}
==Het Page-object==
Elk aspx-bestand zorgt ervoor dat er een pagina gegenereerd wordt om naar de browser te sturen. Deze pagina wordt in het object model van ASP.NET afgeleid van het Page-object.
Als je met Visual Studio.NET programmeert, zal je merken dat elk codebehind-bestand een class bevat die afgeleid is van het Page-object.
Dit betekent dat alle functies, subroutines en eventuele property's die je toevoegt aan een pagina, in feite methodes en property's worden van de class die behoort bij de pagina. Alle controls op de pagina zullen ook tot deze class behoren. Alle property’s kan je ook opvragen in code via de Me-identifyer.
Het Page-object heeft een heleboel eigenschappen, methodes en property's. Het Page-object is op zijn beurt afgeleid van het Control-object, hetgeen nog extra eigenschappen en methodes oplevert.
We noemen hier enkel de belangrijkste:
Tabel: het Page-object
{| class="wikitable"
|-
! !!Naam!!Beschrijving
|-
|Property's||Application||verwijst naar het huidige [[#Het HttpApplicationState-object|Application-object]].
|-
| ||IsPostBack ||False indien de pagina voor de eerste keer wordt weergegeven. True indien de pagina het resultaat is van een round-trip.
|-
| ||Request ||verwijst naar het [[#Het HttpRequest-object|Request-object]]
|-
| ||Response ||verwijst naar het [[#Het HttpResponse-object|Response-object]]
|-
| ||Server ||verwijst naar het huidige [[#Het HttpServerUtility-object|Server-object]]
|-
| ||Session ||verwijst naar het huidige [[#Het HttpSessionState-object|Session-object]]
|-
| ||User ||informatie over de gebruiker die de pagina opvraagt
|-
| ||Controls ||de verzameling controls op de pagina
|-
|Methodes ||DataBind() ||voert voor alle controls op de pagina databinding uit <!--(zie ook paragraaf 14.8.2)-->
|-
| ||FindControl() ||stelt je in staat een control binnen een pagina te vinden op basis van bijvoorbeeld de ID
|-
|Events ||Init ||wordt gegenereerd wanneer de pagina wordt geïnitialiseerd.
|-
| ||Load ||wordt gegenereerd wanneer de pagina wordt geladen, nadat alle controls (inclusief hun viewstate) zijn geladen.
|-
| ||PreRender ||wordt gegenereerd net voordat de pagina wordt geschreven.
|}
==Het HttpRequest-object==
Het object HttpRequest is de opvolger van het Request-object in ASP.
HttpRequest wordt gemapt naar de eigenschap Request van het Page-object, en daardoor kan je het op dezelfde manier blijven gebruiken als in ASP.
In dynamische sites komt het veel voor dat de gebruiker via een HTML-formulier gegevens naar de server stuurt. Met ASP.NET kan je die gegevens gebruiken om bijvoorbeeld op te slaan in een database, te versturen via een e-mail of juist andere gegevens op te zoeken.
De algemene vorm van een formulier is:
<form action="..." method="..." >
...formulierobjecten...
</form>
In een formulier kunnen verschillende objecten voorkomen: tekstvakken, tekstvak met meerdere regels, keuzerondje, selectievak, keuzelijst, opdrachtenknop.
Wanneer het formulier verstuurd wordt, dan wordt er een lijst met sleutels, dit zijn namen en overeenkomstige waarden gemaakt. De naam van een sleutel is telkens het name-attribuut van het formulierelement, en de waarde is hetgeen de gebruiker invulde of selecteerde.
De waarden in een formulier zijn altijd van het subtype String. Dit betekent dat als je een getal of een datum verstuurt, dit gebeurt in de vorm van een string. Bij het verwerken van de gegevens moet je dan eerst de string opnieuw omzetten naar een getal.
===Formulieren koppelen met een ASPX-bestand ===
Met de opdrachtenknop submit en het action-attribuut van een formulier kan je vanuit een formulier een ASPX-bestand oproepen (dit mag zelfs op een andere server staan). Het formulier zelf hoeft geen ASPX-bestand te zijn, gewoon HTML mag ook.
De gegevens in een formulier kunnen op twee manieren naar de server gestuurd worden, met de POST- of met de GET-methode. Met POST worden de gegevens naar de server gestuurd als onderdeel van de HTTP-headers, met GET als onderdeel van de URL.
===Gegevens gebruiken met de GET-methode===
Hieronder zie je een voorbeeld van het HTML formulier:
''form1.htm''
<pre><HTML>
<head>
<title>GET-methode</title>
</head>
<BODY>
<form method="GET" action="formget1.aspx">
Naam <input type="text" name="naam">
<br>
Land <input type="text" name="land">
<br>
<input type="submit" value="Verstuur">
</form>
</BODY>
</HTML></pre>
Als je in dit formulier als naam "Marie" invult, en als land "Nederland", krijg je na het versturen de volgende URL:
https://servernaam/formget1.aspx?naam=Marie&land=Nederland
Merk op dat alle gegevens in de URL verwerkt werden.
De verschillende waarden worden gescheiden door &-tekens, verder worden bijvoorbeeld spaties gecodeerd zodat er geen onbruikbare URL ontstaat.
GET heeft als nadeel dat de gegevens deel uit maken van de URL, wat vooral onhandig is als het bijvoorbeeld om een wachtwoord gaat. Verder is de lengte van een URL beperkt. Sommige oudere browsers ondersteunen geen URL's langer dan 255 tekens. Opera ondersteunt ongeveer 4050 karakters, IE 4.0+ ongeveer 2083 karakters, en Netscape 6 ongeveer 2000.
Hoe kan je nu vanuit je code te weten komen wat de gebruiker ingevuld heeft?
Wanneer de GET-methode is gebruikt, kan je waardes uitlezen uit de QueryString-collectie van het Request-object met de opdracht
Waarde=Request.QueryString("NaamVanInvoer")
''formget1.aspx''
<pre><%@ Page Language="VB" %>
<script runat="server">
Sub Page_Load(Sender As Object, E As EventArgs)
Label1.Text="Hallo " & Request.QueryString("naam") & " uit " &
Request.QueryString("land")
End Sub
</script>
<HTML>
<head>
<title>GET-methode</title>
</head>
<BODY>
<asp:Label id="Label1" runat="server">
</asp:Label>
</BODY>
</HTML> </pre>
'''Opmerkingen'''
*Waarden in de querystring zijn niet hoofdlettergevoelig
*In plaats van Request.Querystring("land") kan je kortweg Request("land") gebruiken.
*Deze methode heeft als nadeel dat je in de URL de doorgegeven waarde kan zien. Als je dat niet wil (bijvoorbeeld met wachtwoorden), gebruik dan de POST-methode. Langs de andere kant kan dit een voordeel zijn bij het zoeken naar fouten: je ziet welke gegevens er uit het formulier komen door de URL te bekijken.
*De GET-methode geeft met bepaalde browsers problemen indien de door te geven waarde spaties bevat.
===Gegevens doorgeven met de POST-methode===
Wanneer de POST-methode is gebruikt, dan werkt de QueryString-methode niet (ze geeft een blanco resultaat). Je kan je waardes nu uitlezen uit een andere collectie: de Form-Collectie van het Request-object.
Dit doe je met de opdracht Request.Form("NaamVanWaarde").
Hieronder zie je een voorbeeld van het HTML-formulier en vervolgens de code om er wat mee te doen.
''form2.htm''
<pre><HTML>
<head>
<title>POST-methode</title>
</head>
<BODY>
<form method="POST" action="formpost2.aspx">
Naam <input type="text" name="naam">
<br>
Land <input type="text" name="land">
<br>
<input type="submit" value="Verstuur">
</form>
</BODY>
</HTML></pre>
''formpost2.aspx''
<pre><%@ Page Language="VB" %>
<script runat="server">
Sub Page_Load(Sender As Object, E As EventArgs)
Label1.Text="Hallo " & Request.Form("naam") & " uit " &
Request.Form("land")
End Sub
</script>
<HTML>
<head>
<title>POST-methode</title>
</head>
<BODY>
<asp:Label id="Label1" runat="server">
</asp:Label>
</BODY>
</HTML> </pre>
'''Opmerkingen'''
*In plaats van Request.Form kan je kortweg Request gebruiken, dus Request.Form("getal") kan korter als Request("getal").
*Je kan de doorgegeven waarden niet zien in de url zoals bij GET, maar als je “Trace=True” instelt in de pagina worden ze onderaan getoond.
*Als je de pagina na het versturen ververst in de browser, dan zal de browser toestemming vragen om dezelfde gegevens opnieuw te versturen.
===Keuze tussen GET en POST in een formulier===
Zoals reeds gezegd hebben elk van deze methodes hun voor- en nadelen:
{| class="wikitable"
|-
! !!GET!!POST
|-
|Versturen||<form method="GET">||<form method="POST">
|-
|Uitlezen
|
Request.QueryString("NaamWaarde")<br>
of<br>
Request("NaamWaarde")
|Request.Form("NaamWaarde")<br>
of<br>
Request("NaamWaarde")
|-
|Wanneer gebruiken:
|
*Tijdens de ontwerpfase: fouten in een formulier kunnen gemakkelijker opgespoord worden door de URL te bekijken
*Als je de gebruiker wil toelaten de opgevraagde pagina toe te voegen aan zijn of haar Favorieten.
*Als je direct toegang wil geven tot de pagina via hyperlinks, bijvoorbeeld: www.test.be/index.aspx?taal=nl
|
*Wordt door ASP.NET standaard gebruikt voor alle webformulieren.
*Als er een wachtwoord moet doorgegeven worden. Met GET zou het wachtwoord gewoon leesbaar zijn in de URL.
*Als er grote tekstvakken (textarea) doorgegeven moeten worden, bijvoorbeeld commentaar, opmerkingen of boodschappen van de gebruiker.
*Als de URL via GET te lang zou worden (meer dan 1000 tekens).
|}
'''Opmerking'''<br>
QueryString en Form kunnen soms tegelijk gebruikt worden. Je kan bijvoorbeeld instellen:
<form action="pag.aspx?taal=nl" method="post">
<input type="text" name="naam">
</form>
In dit geval zal Request.QueryString("taal") als resultaat "nl" geven, en Request.Form("naam") hetgeen door de gebruiker ingevuld werd in het vak "naam".
===Werken met verborgen velden===
Een verborgen (hidden) veld is van de vorm
<input type="hidden" name="variabele naam" value="waarde">
en wordt niet in een formulier getoond.
Wat is dan het nut van zo'n veld?
Verborgen velden kan je gebruiken om zelf bepaalde opties door te sturen, zonder dat deze door de bezoeker gekozen kunnen worden.
Ze kunnen ook dienen als een omweg om opties door te sturen die al in een vorig formulier door de gebruiker gekozen werden (bv. een stap voor stap procedure).
ASP.NET gebruikt verborgen velden voor het bewaren van [[Programmeren in ASP.NET|Viewstate|viewstate]]. Je hoeft hiervoor zelf niets te doen.
===Herhalende waarden===
In een URL is dit ook toegelaten:
https://www.naam.be/test.aspx?naam=Jan&naam=Els
Merk op dat er twee verschillende waarden opgegeven worden voor dezelfde sleutel "naam".
Hoe krijg je dan toegang tot deze afzonderlijke waarden?
In feite geven Request.QueryString() en Request.Form() een collectie van namen en waarden terug (een collectie is een object dat lijkt op een array). Je krijgt toegang tot de afzonderlijke waarden door de methode GetValues() van het NameValueCollection-object te gebruiken.
''herhalendewaarden.aspx''
<pre><%@ Page Language="VB" %>
<script runat="server">
Sub Page_Load(sender As Object, e As EventArgs)
' De regel hieronder geeft: "Jan,Els"
Label1.Text=Request.QueryString("naam")
' De regel hieronder geeft: "Jan"
Label2.Text=Request.QueryString.GetValues("naam")(0)
' De regel hieronder geeft: "Els"
Label3.Text=Request.QueryString.GetValues("naam")(1)
' De lus hieronder geeft "Jan<br>Els "
Dim Item As String
For Each Item In Request.QueryString.GetValues("naam")
Label4.Text=Label4.Text & "<br>" & Item
Next
End Sub
</script>
<html>
<head>
<title>Herhalende waarden</title>
</head>
<body>
<form runat="server">
<asp:Label id="Label1" runat="server"></asp:Label><br>
<asp:Label id="Label2" runat="server"></asp:Label><br>
<asp:Label id="Label3" runat="server"></asp:Label><br>
<asp:Label id="Label4" runat="server"></asp:Label><br>
</form>
</body>
</html></pre>
Om te testen vraag je deze pagina op met het adres:
https://servernaam/herhalendewaarden.aspx?naam=Jan&naam=Els
Als er maar één waarde is, geven beide methodes hetzelfde resultaat, dus dan heeft het geen belang welke methode je gebruikt.
===Request.ServerVariables===
De eigenschap ServerVariables van het HttpRequest-object bevat een aantal interessante gegevens over de server en over de gebruiker.
Dit script geeft je een volledige lijst:
''servervariables.aspx (fragment)''
<pre>Function GetSrvVariables() as String
Dim retString as String = ""
Dim i, j As Integer
Dim arr1(), arr2() As String
Dim coll As NameValueCollection
coll=Request.ServerVariables ' Laad de ServerVariables-collectie
arr1 = coll.AllKeys ' Plaats de namen van alle keys in een string-array.
For i = 0 To UBound(arr1)
retString = retString & arr1(i)
arr2 = coll.GetValues(i) ' Haal alle waarden onder deze key.
For j = 0 To UBound(arr2)
retString = retString & ": " & arr2(j) & "<br>"
Next j
Next i
Return retString
End function</pre>
===Oefeningen===
#Maak een HTML-pagina (geen ASPX) waar je twee getallen kan invullen. Na het versturen verschijnt een ASPX-pagina waar de som getoond wordt.
#Maak een pagina welkom.aspx met een welkom-boodschap. Als de pagina opgevraagd wordt als welkom.aspx of als welkom.aspx?taal=nl, dan is de boodschap in het Nederlands. Als ze opgevraagd wordt als welkom.aspx?taal=fr, dan is de boodschap in het Frans. Test dit uit door zelf de url in te tikken.
==Het HttpResponse-object==
Het object HttpResponse stelt je in staat gegevens terug te zenden naar de browser. Het is gemapt naar de eigenschap Response van het Page-object, zodat het direct beschikbaar is.
In ASP werd de methode Response.Write() veel gebruikt, maar in ASP.NET is dit nog maar zelden nodig, omdat de server-controls bijna alle uitvoer op zich nemen.
Het HttpResponse-object heeft ook de mogelijkheid om andere soorten bestanden aan te maken naast HTML-bestanden. Voorbeelden hiervan kan je vinden bij het [[Programmeren in ASP.NET/Server-side afbeeldingen|maken van afbeeldingen]].
Een methode van HttpResponse die dikwijls van pas komt is Redirect(url). Hiermee kan je de gebruiker doorsturen naar een andere pagina (url is het relatief of absoluut adres van die pagina).
Bijvoorbeeld:
If(ingevoerdWachtwoord<>"123") Then Response.Redirect("start.aspx")
Als het wachtwoord juist is, wordt de gebruiker doorgestuurd naar de startpagina.
===Oefeningen===
#Maak een pagina waar je met radioknoppen kan kiezen tussen 2 talen: Nederlands of Frans. Bij het klikken op "Submit" wordt de gebruiker naar een pagina in die taal gebracht.
#Maak een pagina met een quizvraag. Als de bezoeker het juiste antwoord gekozen heeft, toon je een andere pagina. Anders keer je terug naar de quizvraag.
==Het HttpSessionState-object==
===Wat is een sessie?===
We praten over een sessie als een gebruiker een pagina van een website opvraagt. Alle pagina's die de gebruiker opent behoren tot dezelfde sessie. Een sessie eindigt als de browser gesloten wordt of als de gebruiker voor een bepaalde tijd geen pagina's meer heeft opgevraagd (time-out). Dit betekent ook dat je meerdere sessies tegelijk kan openen door meerdere browservensters na mekaar te openen.
===Wat is het HttpSessionState-object?===
Binnen een sessie is het handig om gegevens te bewaren die relevant zijn voor de gebruiker, bijvoorbeeld een gebruikersnaam. Het zou vervelend zijn als de gebruiker deze gegevens telkens weer opnieuw zou moeten opgeven. Je kan deze gegevens opslaan in het HttpSessionState-object. Het wordt gemapt naar de eigenschap Session van het Page-object, zodat het direct toegankelijk is.
Het HttpSessionState-object kan je gebruiken om de waarde van variabelen van de ene naar de andere ASPX-pagina door te geven, of om binnen één pagina bij te houden wat de gebruiker eerder al gedaan heeft.
Stel: in bestand1.aspx plaats je de volgende opdracht in Page_Load:
Session("taal")="nl"
Als de gebruiker verdergaat naar bestand2.aspx (bijvoorbeeld via een hyperlink), dan kan je in bestand 2.aspx het volgende doen:
If(Session("taal")="nl") Then ...
en dan is deze voorwaarde inderdaad voldaan.
In het volgende voorbeeld wordt bijgehouden hoe dikwijls de pagina al ververst werd binnen dezelfde sessie:
''session1.aspx''
<pre><%@ Page Language="VB" %>
<script runat="server">
Sub Page_Load(Sender As Object, e As EventArgs)
Session("Teller") = Session("Teller") + 1
Label1.Text=Session("Teller")
End Sub
</script>
<html>
<head>
<title>Session</title>
</head>
<body>
<form runat="server">
<asp:Label id="Label1" runat="server"></asp:Label>
</form>
</body>
</html></pre>
Telkens je de pagina ververst, verhoogt de teller (ook als je ondertussen naar andere pagina's surft). Maar als je de browser sluit en dan een nieuwe browser opent, dan is er een nieuwe sessie en de teller begint dan weer bij 1.
Je kan alle Session-variabelen op een bepaald moment bekijken door in het Page-directief Trace="True" in te stellen.
===Hoe werkt het Session-object?===
De waardes in het HttpSessionState-object worden opgeslagen in het geheugen van de server. Om bij te houden welke sessie van een bepaalde gebruiker is, wordt er een cookie naar de browser gestuurd met een unieke waarde erin: de SessionID. Iedere keer als de browser een aanvraag doet, wordt deze cookie meegestuurd en kan de server terugvinden welke sessie erbij hoort. Deze cookie wordt ongeldig als de browser gesloten wordt, of als er 20 minuten verstreken zijn sinds de laatste aanvraag.
''session2.aspx''
<pre><%@ Page Language="VB" %>
<script runat="server">
Sub Page_Load(Sender As Object, e As EventArgs)
Label1.Text=Session.SessionID
End Sub
</script>
<html>
<head>
<title>Session</title>
</head>
<body>
<form runat="server">
<asp:Label id="Label1" runat="server"></asp:Label>
</form>
</body>
</html></pre>
Indien de browser geen cookies accepteert, dan wordt door ASP.NET een truuk gebruikt met een code in de URL (dit noemt men URL-munging), zodat het Session-object nog steeds werkt.
Het is nadelig voor de snelheid van de server als je veel waardes opslaat in het HttpSessionState-object, zeker als er veel gebruikers zijn. Gebruik het dus met mate.
Let ook op: als de gebruiker op de "Back"-knop van de browser klikt, gaat hij of zij naar de vorige pagina, maar de session-variabelen blijven zoals ze zijn. Dit kan soms tot conflicten leiden.
===Session.Abandon()===
Deze methode vernietigt de inhoud van de session-variabelen.
Per gebruiker wordt een sessie aangemaakt. Abandon() wist de sessie voor de huidige gebruiker.
===Session.Timeout===
Deze property bepaalt na hoeveel minuten de session-variabelen mogen gewist worden. Default is 20 minuten. Dit betekent dat een gebruiker die gedurende 20 minuten niets doet, zijn sessie verliest. De maximale waarde is 1 jaar.
Voorbeeld:
Session.Timeout=60
===Session.LCID===
Met de eigenschap LCID (Locale Culture ID) kan je selecteren welke regionale instellingen gebruikt moeten worden. Deze instellingen zijn heel belangrijk in internationale (niet-Engelse) toepassingen, vooral bij het weergeven en invoeren van datum en tijd, en voor het gebruik van de decimale komma. Standaard worden de instellingen van de computer van de gebruiker toegepast.
Voor België gebruik je deze instelling:
Session.LCID = 2067
Voor Nederland gebruik je deze instelling:
Session.LCID = 1043
Voor Amerikaans Engels:
Session.LCID = 1033
De LCID blijft gelden voor alle volgende statements binnen de sessie, tot ze ingesteld wordt op een andere waarde.
Je kan de LCID ook per pagina instellen, in het Page-directief van de pagina:
<%@Page language="VB" LCID="2067" %>
Een lijst met LCID's vind je hier: [https://www.webwizguide.info/asp/faq/date_time_settings.asp lijst met LCID's]
===Oefeningen===
#Maak een pagina waar de datum op 3 manieren getoond wordt: Belgisch Nederlands, Amerikaans Engels, en Pools.
#Zelfde oefening, maar nu voor de currency (munt). Een regio-afhankelijke currency krijg je door te schrijven:
<pre>Dim curr As Decimal = 12.55
Label1.Text = curr.ToString("c")</pre>
#Maak een pagina waar de gebruiker een wachtwoord moet ingeven. Na 3 verkeerde pogingen wordt de toegang geweigerd.
#Maak een quiz met 3 meerkeuzevragen, elk op een aparte pagina. Op een 4e pagina geef je de score.
==Het HttpApplicationState-object==
Het HttpApplicationState-object werkt zoals het HttpSessionState-object, maar de waarden zijn gemeenschappelijk voor alle gebruikers. Dit object roep je op met de eigenschap Application van het Page-object.
Dit object maakt het mogelijk gegevens te delen tussen alle pagina's en alle gebruikers in een applicatie.
Met het HttpApplicationState-object kan je bijvoorbeeld een teller maken die telt hoe vaak een pagina bezocht is (door alle gebruikers samen), maar ook kan je bijvoorbeeld gegevens over de database-koppeling, of andere waarden die je door de hele site nodig hebt, opslaan.
Hier is de teller opnieuw, maar nu met het HttpApplicationState-object (ververs de pagina om het resultaat te zien):
''appvar1.aspx''
<pre><%@ Page Language="VB" %>
<script runat="server">
Sub Page_Load(Sender As Object, e As EventArgs)
Application ("Teller") = Application ("Teller") + 1
Label1.Text= Application ("Teller")
End Sub
</script>
<html>
<head>
<title>Application</title>
</head>
<body>
<form runat="server">
<asp:Label id="Label1" runat="server"></asp:Label>
</form>
</body>
</html></pre>
Stel dat de bovenstaande code tegelijk door twee verschillende mensen bekeken zou worden. Doordat ASP.NET niet alle scripts meteen helemaal afmaakt, maar soms de uitvoering kan stoppen om even een ander script (deels) uit te voeren, zou het zo kunnen zijn dat de waarde die je ziet niet klopt. De waarde zou namelijk opgehoogd kunnen zijn, daarna opgehoogd kunnen zijn door de andere gebruiker en daarna pas in jouw browser geschreven worden. Nu is dit bij een teller niet zo belangrijk, maar het kan zijn dat het wel om informatie gaat die belangrijk is. In dat geval kun je de Lock()-methode gebruiken om ervoor te zorgen dat er geen andere gebruikers zijn die tegelijk toegang krijgen tot de waardes in het HttpApplicationState-object.
Omdat dit vertragend werkt moet dit alleen gedaan worden als het nodig is, waarna zo snel mogelijk de Unlock()-methode wordt gebruikt:
''appvar2.aspx (fragment)''
<pre>Sub Page_Load(Sender As Object, e As EventArgs)
Application.Lock()
Application("Teller") = Application("Teller") + 1
Label1.Text=Application("Teller")
Application.Unlock()
End Sub</pre>
De teller kan je initialiseren in het opstartbestand [[Programmeren in ASP.NET/Configuratiebestanden#global.asax|global.asax]].
Het HttpApplicationState-object heeft nog meer mogelijkheden, maar deze worden weinig gebruikt.
'''Opmerking'''<br>
Als de server crasht, of om één of andere reden herstart wordt, dan worden alle gegevens van het Application-object gewist. Bij professionele providers laat men daarom meerdere webservers samenwerken (een zogenaamde web farm).
==Het HttpServerUtility-object==
Het HttpServerUtility-object is een object met allerlei nuttige toepassingen. Het is beschikbaar via de eigenschap Server van het Page-object.
Enkele eigenschappen en methodes zijn:
{| class="wikitable"
|-
|Server.Execute(paginanaam)||voert de huidige aanvraag uit met behulp van een andere pagina
|-
|Server.GetLastError()||geeft een Exception-object dat informatie geeft over de laatst opgetreden fout
|-
|Server.HtmlEncode(tekst)||codeert een string zodat die in de browser getoond kan worden (speciale tekens worden indien nodig aangepast, bv. > wordt &gt;)
|-
|Server.HtmlDecode(tekst)||omgekeerde van HtmlEncode()
|-
|Server.MapPath(relpath)||zet een relatief pad om in een absolute bestandslocatie
|-
|Server.Transfer(url)||stuurt de verwerking door naar een andere pagina
|}
==Cookies==
Een cookie is een bestand dat met Response.Cookies op de computer van de client wordt geplaatst. Als de client een pagina opvraagt, wordt automatisch de cookie(s) meegestuurd. Dan kan de server met het CookieCollection-object Request.Cookies de cookie opvragen. Dit is een manier om informatie over het vorige bezoek van de gebruiker bij te houden op de computer van de gebruiker zelf (en niet op de server).
De cookies worden voor elke site apart opgeslagen, zodat je alleen cookies kan opvragen die door jouw site aangemaakt werden.
Algemene vorm: Response.Cookies("Cookienaam").Value=Waarde
'''Voorbeeld'''<br>
Response.Cookies("kleur").Value = kleurGebruiker
om de gekozen kleur in een cookie weg te schrijven.
Dim kleurGebruiker As String = Request.Cookies("kleur").Value
om de gekozen kleur op een andere plaats weer op te vragen.
Er zijn twee soorten cookies:
#Session cookies: deze worden alleen behouden tijdens de huidige sessie. Na het sluiten van de browser worden ze verwijderd
#Blijvende cookies (persistent cookies): deze blijven bewaard op de pc van de bezoeker, ook na het afsluiten van de browser. Er is wel altijd een vervaldatum, waarna de cookie automatisch verdwijnt.
Je maakt van een cookie een blijvende cookie door er een vervaldatum aan mee te geven:
Response.Cookies("kleur").Value="rood"
Response.Cookies("kleur").Expires = #12/17/2005#
Als je geen vaste datum wil gebruiken, maar de datum wil laten afhangen van de datum van aanmaak:
Response.Cookies("kleur").Expires = DateTime.Now.AddDays(30)
Deze cookie zal vervallen na 30 dagen.
Je kan cookies verwijderen door ze opnieuw te maken met een vervaldatum die al verstreken is (Expires=DateTime.Now.AddDays(-1))
===Cookie-voorbeeld===
In het bestand cookies.aspx wordt gekeken of de cookie al bestaat, zoniet, kan de gebruiker zijn of haar keuze intikken. Deze keuze wordt bewaard in de cookie. Dan wordt de pagina opnieuw opgeroepen. Omdat de cookie nu bestaat zal de keuze getoond worden.
''cookies.aspx''
<pre><%@ Page Language="VB" %>
<script runat="server">
Sub Page_Load(sender As Object, e As EventArgs)
' vraag de cookie op
If(Not IsNothing(Request.Cookies("kleur"))) Then
lblKleur.Text=Server.HtmlEncode(Request.Cookies("kleur").Value)
pnlInvoer.Visible=False
Else
pnlResultaat.Visible=False
End If
End Sub
Sub btnVerzend_Click(sender As Object, e As EventArgs)
' bewaar de cookie
Response.Cookies("kleur").Value=tbKleur.Text
Response.Cookies("kleur").Expires=DateTime.Now.AddDays(30)
Response.Redirect("cookies.aspx")
End Sub
</script>
<html>
<head>
<title>Cookies</title>
</head>
<body>
<form runat="server">
<asp:Panel id="pnlInvoer" runat="server">
Kies een kleur:
<asp:TextBox id="tbKleur" runat="server"></asp:TextBox>
<asp:Button id="btnVerzend" onclick="btnVerzend_Click"
runat="server" Text="Verzenden"></asp:Button>
</asp:Panel>
<asp:Panel id="pnlResultaat" runat="server">
Dit is je kleur:
<asp:Label id="lblKleur" runat="server"></asp:Label>
</asp:Panel>
</form>
</body>
</html></pre>
Merk op dat de vervaldatum wordt ingesteld op de datum van vandaag plus 30 dagen.
Cookies hebben een aantal nadelen:
*de meeste browsers beperken de hoeveelheid informatie die je kan bewaren in een cookie. Meestal is die 4096 bytes met oudere browsers, en 8192 bytes met nieuwere.
*sommige gebruikers stellen hun browser in om cookies te weigeren
*omdat cookies bij de gebruiker opgeslagen worden, kan er soms mee gesjoemeld worden. Je kan gegevens uit een cookie nooit voor 100% vertrouwen. Gebruik bijvoorbeeld nooit cookies om te weten of een gebruiker gemachtigd is of niet.
'''Opmerking'''<br>
De sleutel van de cookie is hoofdlettergevoelig. Dit betekent dat Request.Cookies("kleur") een andere waarde zal hebben dan Request.Cookies("Kleur").
Meer details over cookies vind je nog hier: https://www.codeproject.com/aspnet/AspNetCookies.asp
===Oefeningen ===
#Maak een pagina waar de gebruiker zijn of haar naam kan invullen. Op de volgende pagina wordt een boodschap "Welkom, naam." getoond.
#Maak een pagina die toont hoeveel keer de gebruiker de pagina al bezocht heeft. Dit keer wordt het aantal behouden, ook als de gebruiker de browser sluit.
#Maak een pagina waar de gebruiker een wachtwoord moet ingeven. Na 3 verkeerde pogingen wordt de toegang geweigerd. Gebruik cookies.
==Navigatie tussen pagina's==
Er zijn drie manieren die je ondertussen kent om tussen pagina's te navigeren. Hieronder wordt een vergelijking gemaakt:
{| class="wikitable"
|-
!Methode!!Wat gebeurt er?!!Wanneer gebruiken?
|-
|Response.Redirect()
|De huidige pagina wordt naar de gebruiker gestuurd met een code 302 (object moved) en de nieuwe url. De browser gebruikt deze informatie om de nieuwe pagina op te vragen.
Het doorsturen gebeurt dus op de client en vereist 2 round trips.
|
*als je wil doorverbinden naar een andere server
*als je wil doorverbinden naar een niet aspx-bestand (bv. een html-bestand)
*als je de query-string wil doorgeven als onderdeel van de url
|-
|Server.Transfer()
|De uitvoering wordt vanaf het huidige aspx-bestand doorgegeven naar het nieuwe aspx-bestand, op dezelfde server. De browser blijft de oorspronkelijke url tonen, omdat het doorsturen gebeurt op de server.
|
*als je wil doorverbinden naar een bestand op dezelfde server.
*als je de informatie uit een formulier (Form of QueryString) wil mee doorgeven (geef als tweede parameter True op)
|-
|Server.Execute()
|Het nieuwe aspx-bestand wordt uitgevoerd binnen het huidige. Na het uitvoeren van het nieuwe bestand gaat de uitvoer van het oude gewoon door. Je kan dit vergelijken met het oproepen van een functie.
|
*als de uitvoer terug moet keren naar het huidige bestand.
|}
{{Bladeren2
|Boek=Programmeren in ASP.NET
|vorige=Webformulieren
|huidige=Veelgebruikte objecten
|volgende=Validering
}}
{{Sub}}
t1h2i9bgk6xleciy3m6gvaig3akyaxp
Programmeren in ASP.NET/Validering
0
3445
428823
425783
2026-05-23T12:17:10Z
Erik Baas
2193
lf
428823
wikitext
text/x-wiki
{{Index Programmeren in ASP.NET}}
==Wat is validering?==
Validering is het onderwerpen van data aan een gegeven verzameling regels. In ASP.NET is het dikwijls de invoer van bezoekers die we willen valideren in een web formulier.
Er zijn een aantal redenen waarom we dit zouden willen doen. Enkele simpele voorbeelden:
*Er werden geen of onvolledige gegevens ingevoerd
*De waarde van de ingevoerde gegevens is niet binnen de juiste grenzen
*Het formaat van de ingevoerde gegevens is niet correct
==ASP.NET-valideringcontrols==
In ASP.NET is validering gemakkelijk toe te voegen door middel van een verzameling controls die valideringcontrols genoemd worden.
Er zijn 5 types individuele valideringcontrols. Dit zijn ze:
*RequiredFieldValidator
*CompareValidator
*RangeValidator
*RegularExpressionValidator
*CustomValidator
De '''Required Field Validator''' zorgt ervoor dat de gebruiker iets moet invullen. Het mag eender wat zijn, maar de gebruiker kan het veld niet leeg laten.
De '''Compare Validator''' en de '''Range Validator''' vergelijken beide de invoer (in de aard van x>y). Het verschil tussen beide is dat de Compare Validator maar één kant controleert, terwijl de Range Validator zowel een ondergrens als een bovengrens kan opleggen.
De '''RegularExpression Validator''' controleert de invoer met een [[Programmeren in ASP.NET/Reguliere expressies|reguliere expressie]]. Enkele veelgebruikte expressies, zoals voor een e-mail-adres, zijn direct beschikbaar.
Als geen enkele validator voor jou past, dan kan je je eigen criteria schrijven en het in een '''Custom Validator''' inkapselen.
Naast deze individuele valideringcontrols, is er nog een laatste soort: de '''Validation Summary''' Control. Deze control laat je toe om gemakkelijk te controleren of elke validator op een pagina voldaan is of niet, in de plaats van ze elk afzonderlijk te checken.
Een interessante eigenschap van valideringcontrols is dat ze automatisch client-side-validering uitvoeren via JavaScript in recente browsers. De validering gebeurt hoe dan ook nogmaals op de server, maar je krijgt automatisch het voordeel van onmiddellijke feedback als de gebruiker een recente browser gebruikt. Je hoeft zelfs geen client-side-code te schrijven.
Belangrijk: omdat er geen client-side-validering gebeurt om andere browsers dan Internet Explorer, en omdat zelfs Internet Explorer-gebruikers toch [[Programmeren in JavaScript|JavaScript]] kunnen uitschakelen, moet je op de server nog altijd controleren of de validering gelukt is, vooraleer je andere code uitvoert. Dit moet je doen met
<pre>If(Page.IsValid) Then
' code die pas uitgevoerd wordt als de validering gelukt is
End If</pre>
Nota: (ASP.NET 1.x) De client-side code voor validering staat in een bestand "WebUIValidation.js. Om validering te laten werken, moet dit bestand in een subfolder "aspnet_client\system_web\xxxxxxx" in de root van de website staan (xxxxxxxx is de versie van het .NET framework). In ASP.NET 2.0 is dit niet meer nodig, daar wordt een javascriptbestand automatisch op de server gegenereerd.
==Voorbeelden==
Hier is een simpel voorbeeld dat een RequiredFieldValidator gebruikt om ervoor te zorgen dat de gebruiker een naam invult:
''required.aspx''
<pre><%@ Page Language="VB" %>
<script runat="server">
Sub btnSubmit_Click(Sender as Object, E as EventArgs)
If(Page.IsValid) Then
' Doe iets
End If
End Sub
</script>
<html>
<head>
<title>ASP.NET Form Validering voorbeeld - Required Field Validator</title>
</head>
<body>
Merk op dat dit formulier niets doet behalve de Required Field Validator illustreren.
<hr>
<form id="frmValidator" action="required.aspx" method="post" runat="server">
Voer je naam in:
<asp:TextBox id="tbName" runat="server" />
<asp:RequiredFieldValidator id="valTxtName" ControlToValidate="tbName"
ErrorMessage="Voer je naam in!" runat="server" />
<br>
<asp:button id="btnSubmit" text="Submit"
onClick="btnSubmit_Click" runat="server" />
</form>
<hr>
Hint: Probeer het formulier in te dienen zonder iets in te tikken.
</body>
</html></pre>
Je kan ook op voorhand al een waarde invullen, en eisen dat de gebruiker deze waarde verandert. Dit doe je met de eigenschap "InitialValue" van de RequiredFieldValidator.
Hier is een ander voorbeeld, deze keer met een RangeValidator:
''range.aspx''
<pre><%@ Page Language="VB" %>
<script runat="server">
Sub btnSubmit_Click(Sender as Object, E as EventArgs)
' Doe iets
End Sub
</script>
<html>
<head>
<title>ASP.NET Form Validering voorbeeld - Range Validator</title>
</head>
<body>
<form id="frmValidator" action="range.aspx" method="post" runat="server">
Voer je leeftijd in:
<asp:TextBox id="tbAge" runat="server" />
<asp:RequiredFieldValidator id="valTxtAgeReq" ControlToValidate="tbAge"
ErrorMessage="Vul je leeftijd in!" Display="Dynamic"
runat="server" />
<asp:RangeValidator id="valTxtAgeRange" ControlToValidate="tbAge"
Type="Integer" MinimumValue="21" MaximumValue="100"
ErrorMessage="Je moet ouder zijn dan 21 en jonger dan 100!"
Display="Dynamic" runat="server" />
<br>
<asp:button id="btnSubmit" text="Submit"
onClick="btnSubmit_Click" runat="server" />
</form>
<hr>
Hint: Probeer een leeftijd onder 21 in te vullen.
</body>
</html></pre>
'''Opmerkingen'''<br>
*Vergeet bij de RangeValidator of CompareValidator niet de property "Type" in te stellen. Standaard staat dit op "String", maar voor getallen geeft dit foutieve resultaten (de string "2" is groter dan de string "10"!).
*Naast tekstvakken kan je nog de volgende controls valideren: ListBox, DropDownList, RadioButtonList, HtmlInputText, HtmlInputFile, HtmlSelect en HtmlTextArea.
*Je mag meerdere validators op één enkele control zetten. Dit is soms nodig, want de CompareValidator en de RangeValidator controleren niet of de waarde niet leeg is. Als je een bepaalde waarde wil controleren, én de waarde mag ook niet leeg zijn, dan moet je 2 validators gebruiken.
===Oefeningen===
#Schrijf een pagina waar je je adres en telefoonnummer moet ingeven. Doe de gepaste validering
#Schrijf een pagina waar je 3 multiple-choice vragen moet beantwoorden. Controleer of de 3 vragen werkelijk beantwoord werden (goed of fout heeft geen belang).
#Schrijf een validator voor een wachtwoordvak. Het wachtwoord moet altijd minstens 1 letter en 1 cijfer bevatten.
#Schrijf een formulier met twee wachtwoordvakken. De beide waarden moeten identiek zijn.
#Schrijf een formulier waar je een datum moet ingeven. Het moet een datum zijn die al voorbij is. Tip: omdat de ValueToCompare variabel is, moet je de waarde ervan instellen in Page_Load.
==CustomValidator==
Als er geen validator is die exact doet wat je wil, dan kan je je eigen valideringsfunctie schrijven. Gebruik de CustomValidator-control, en gebruik het event OnServerValidate.
De handler voor dit event ziet er zo uit:
<pre>Sub ServerValidation(source As Object, args As ServerValidateEventArgs)
' Schrijf hier je eigen code om te testen of het formulier geldig is.
If(formuliergeldig) Then
args.IsValid = True
Else
args.IsValid = false
End If
End Sub</pre>
Zoals je merkt moet je de waarde van args.IsValid instellen naargelang het formulier goed of slecht ingevuld is.
Indien je wil kan je zelfs client-side-validering toevoegen met behulp van de ClientValidationFunction-property. Voeg dan een javascriptblok toe aan de pagina met de betreffende functie erin. Deze functie moet true of false geven naargelang de validering gelukt is of niet.
Bij een CustomValidator is het niet verplicht de ControlToValidate-property in te stellen.
===Oefeningen===
#Maak een formulier waar de gebruiker een even getal moet invullen. Gebruik validering.
#Schrijf een pagina waar je moet ingeven welke talen je spreekt. Zorg ervoor dat minimaal één taal gekozen moet worden.
#Schrijf een pagina waar je een geschenk mag kiezen. Uit 4 mogelijkheden moet je er exact 2 aankruisen. Controleer of de keuze hieraan voldoet.
==Overzicht valideringcontrols==
{| class="wikitable"
!Control!!Beschrijving!!HTML voorbeeldcode
|-
|RequiredFieldValidator
|Laat je toe om te vermijden dat het veld blanco gelaten werd.
|<asp:RequiredFieldValidator id="RequiredFieldValidator1" ControlToValidate="ControlID1" ErrorMessage="Vul iets in!" runat="server"></asp:RequiredFieldValidator>
|-
|CompareValidator
|Laat je toe om de inhoud van de ene control te vergelijken met die van een andere control, of met een bepaalde waarde.
|<asp:CompareValidator id=CompareValidator1 ControlToValidate="ControlID1" ControlToCompare="ControlID2" (of ValueToCompare="50") Type="Integer" Operator="GreaterThan" ErrorMessage="De waarde moet ... zijn." runat="server"></asp:CompareValidator>
|-
|RangeValidator
|Laat je toe om te controleren of de invoer in een control binnen een bepaald bereik ligt.
|<asp:RangeValidator id=RangeValidator1ControlToValidate="ControlID1" MaximumValue="12/31/1998" MinimumValue="1/1/1998" Type="Date" ErrorMessage="De waarde moet tussen..." runat="server" ></asp:RangeValidator>
|-
|RegularExpressionValidator
|Laat je toe om te controleren of een veld voldoet aan een bepaald "invoermasker" (met een reguliere expressie).
|<asp:RegularExpressionValidatorid=RegularExpressionValidator1 ControlToValidate="ControlID1" ValidationExpression=".*@.*\..*" ErrorMessage="Verkeerde waarde" runat="server" ></asp:RegularExpressionValidator>
|-
|CustomValidator
|Laat je toe een functie toe te wijzen, zowel server-side als client-side, voor het valideren van een bepaalde control.
|<asp:CustomValidator id="CustomValidator1" ClientValidationFunction="ClientValidate" OnServerValidate="ServerValidate" ErrorMessage="Verkeerde waarde" runat="server" ></asp:CustomValidator>
|}
==Validation Summary==
Hier is een script dat het gebruik van de Validation Summary-control illustreert:
''summary.aspx''
<pre><%@ Page Language="VB" %>
<script runat="server">
Sub btnSubmit_Click(Sender as Object, E as EventArgs)
' Controleert of alle controls op de pagina geldig zijn!
If (Page.IsValid) Then
' Doe Iets
End If
End Sub
</script>
<html>
<head>
<title>ASP.NET Validering voorbeeld - Summary</title>
</head>
<body>
<p>Noteer dat dit formulier uiteindelijk niets anders doet
dan de Validators illustreren.</p>
<form runat="server">
Vul je naam in:
<asp:TextBox id="tbName" runat="server" />
<asp:RequiredFieldValidator id="valTxtName" ControlToValidate="tbName"
ErrorMessage="Vul je naam in!"
runat="server">
***
</asp:RequiredFieldValidator>
<br>
Voer je leeftijd in:
<asp:TextBox id="tbAge" runat="server" />
<asp:RequiredFieldValidator id="valTxtAgeReq"
ControlToValidate="tbAge"
ErrorMessage="Voer je leeftijd in!"
Display="None"
runat="server">
***
</asp:RequiredFieldValidator>
<asp:RangeValidator id="valTxtAgeRange" ControlToValidate="tbAge"
Type="Integer" MinimumValue="21" MaximumValue="100"
ErrorMessage="Je moet ouder zijn dan 21 en jonger dan 100!<br>"
Display="None" runat="server">
***
</asp:RangeValidator>
<br>
<asp:button id="btnSubmit" text="Submit"
onClick="btnSubmit_Click" runat="server" />
<asp:ValidationSummary ID="valSummary"
HeaderText="Er was een fout bij het invoeren van je formulier.
Controleer het volgende:"
DisplayMode="BulletList"
runat="server" />
</form>
</body>
</html></pre>
Merk op dat beide validators een Display-attribuut "None" hebben. Deze optie werkt samen met de summary-validator, zodanig dat de fout alleen in de summary getoond wordt, en niet nog eens in de aparte validators.
Display heeft drie mogelijke instellingen:
*None: de fout wordt niet getoond (als er een summary-validator is waar de fout wel getoond wordt)
*Static: de fout wordt getoond en de ruimte voor de foutboodschap wordt altijd ingenomen, ook als er geen fout optreedt
*Dynamic: de fout wordt getoond en de ruimte voor de foutboodschap wordt alleen ingenomen als er een fout is. Anders wordt deze ruimte "samengeklapt"
==Validering uitschakelen voor sommige knoppen==
Soms gebruik je een knop "Annuleren" of "Cancel" op je pagina. Als je op deze knop drukt wordt er normaal gezien ook validering toegepast. Maar dat betekent dat je het formulier eerst correct moet invullen voor je op "Annuleren" kan drukken!
Om dit probleem op te lossen heeft elke knop ook een eigenschap "CausesValidation", die standaard op "True" ingesteld staat. Als je deze op "False" zet voor de "Cancel"-knop, dan wordt er voor die knop geen validering uitgevoerd.
==Validatiegroepen (ASP.NET 2.0)==
In ASP.NET 1.x is er een probleem als je meerdere formulieren op één pagina wil gebruiken. Dit komt meer voor dan je denkt, bijvoorbeeld als je een kalender-control hebt en op dezelfde pagina een vakje om in te loggen.
In een dergelijk geval zullen validator-controls het tweede formulier blokkeren zolang het eerste niet goed ingevuld is, en omgekeerd.
In ASP.NET 2.0 is dit probleem opgelost door de invoering van validatiegroepen.
Het enige wat je moet doen is de eigenschap ValidationGroup instellen voor de verschillende validatiecontrols, en voor de overeenkomstige submit-knoppen. Controls die bij mekaar horen moet je dezelfde waarde geven. In het voorbeeld hieronder zijn er twee validatiegroepen: Groep1 en Groep2.
''validatiegroepen.aspx''
<pre><%@ Page Language="vb" %>
<script runat="server">
Sub Groep1Click(ByVal s As Object, ByVal e As EventArgs)
If Page.IsValid Then
lblResult.Text = "Groep 1 verwerkt"
End If
End Sub
Sub Groep2Click(ByVal s As Object, ByVal e As EventArgs)
If Page.IsValid Then
lblResult.Text = "Groep 2 verwerkt"
End If
End Sub
</script>
<html>
<head runat="server">
<title>Validatiegroepen</title>
</head>
<body>
<form runat="server">
<asp:Label ID="lblResult" Runat="Server" />
<fieldset style="padding:20px">
<legend>Groep 1</legend>
<asp:TextBox id="TextBox1" Runat="Server" />
<asp:Button ValidationGroup="Groep1" Text="Submit" ID="btn1"
OnClick="Groep1Click" Runat="Server" />
<asp:RequiredFieldValidator ValidationGroup="Groep1" ID="rqv1"
ControlToValidate="TextBox1" Text="(verplicht)" Runat="Server" />
</fieldset>
<fieldset style="padding:20px">
<legend>Groep 2</legend>
<asp:TextBox id="TextBox2" Runat="Server" />
<asp:Button ValidationGroup="Groep2" Text="Submit" ID="btn2"
OnClick="Groep2Click" Runat="Server" />
<asp:RequiredFieldValidator ValidationGroup="Groep2" ID="rqv2"
ControlToValidate="TextBox2" Text="(verplicht)" Runat="Server" />
</fieldset>
</form>
</body>
</html></pre>
Als je nu Groep1 niet invult, kan je toch Groep2 nog versturen, en omgekeerd.
{{Bladeren2
|Boek=Programmeren in ASP.NET
|vorige=Veelgebruikte objecten
|huidige=Validering
|volgende=Master-pagina's
}}
{{Sub}}
brmsqrn7iok4ys2mfe9kxk714qkvw6o
Programmeren in ASP.NET/Master-pagina's
0
3454
428821
425779
2026-05-23T12:17:08Z
Erik Baas
2193
lf
428821
wikitext
text/x-wiki
{{Index Programmeren in ASP.NET}}
Een van de zaken die ontbreken in ASP.NET 1.x is de mogelijkheid een sjabloon te definiëren voor meerdere pagina’s. De meeste ontwikkelaars lossen dit op door aan het begin en einde van iedere pagina een (user)control te plaatsen die de algemene opmaak van de pagina verzorgt. ASP.NET 2.0 biedt een veel elegantere oplossing in de vorm van Master-pagina's. Een master-pagina is een paginasjabloon.
In elke pagina kan je instellen welk sjabloon hij gebruikt.
Het interessante is dat je ook sjablonen kunt maken op basis van een sjabloon. Zo kun je dus voor delen van een applicatie een enigszins afwijkende opmaak gebruiken, maar toch eventuele wijzigingen aan de algehele opmaak meenemen. Je kunt als het ware een hele hiërarchie van sjablonen maken. Ook kun je tijdens het uitvoeren bepalen welke master-pagina een pagina gebruikt, zodat je bijvoorbeeld gebruikers hun eigen opmaak kunt laten kiezen.
==Een master-pagina maken==
Een master-pagina werkt met zogenaamde ContentPlaceHolder-controls waarmee één of meer regionen in het sjabloon kunnen worden aangegeven. In de pagina plaats je vervolgens Content-controls die aan de hand van de ContentPlaceHolderID aangeven voor welke placeholder ze inhoud bevatten. Hier is een simpel voorbeeld van een master-pagina:
''wiki.master''
<pre><%@ Master %>
<html >
<head>
<title>Master-pagina</title>
</head>
<body>
<form runat="server">
<h1>Master-pagina</h1>
<hr>
<asp:contentplaceholder id="Body" runat="server" ></asp:contentplaceholder>
<hr>
<asp:contentplaceholder id="Hulpvak" runat="server" ></asp:contentplaceholder>
<hr>
© 2006 WIKIPEDIA
</form>
</body>
</html></pre>
De master-pagina ziet eruit als een gewone HTML-pagina, maar wordt bewaard met de extensie .master. Verder bevat ze geen Page-directief, maar wel een Master-directief, en verschillende ContentPlaceHolder-controls.
Alles wat je in de master-pagina zet buiten de contentplaceholders zal terugkomen op elke pagina die de master gebruikt. Je mag eender welke HTML- of ASP.NET- code in de master-pagina opnemen.
==Een master-pagina gebruiken==
Hier is een pagina die de bovenstaande Page Master gebruikt:
''content.aspx''
<pre><%@ Page Language="VB" MasterPageFile="~/wiki.master" Title="Content pagina" %>
<asp:Content ContentPlaceHolderID="Body" Runat="server">
<asp:Label ID="lbl1" Runat="server" BackColor="Green">
Een label in de Body ContentPlaceHolder
</asp:Label>
</asp:Content>
<asp:Content ContentPlaceHolderID="Hulpvak" Runat="Server">
Hier kan nog andere tekst verschijnen afhankelijk van de pagina.
</asp:Content></pre>
De master-pagina staat ingesteld in het Page-directief, met behulp van de MasterPageFile-property.
Belangrijk: vergeet nooit de Title-property in te stellen, deze tekst verschijnt binnen de <title>-tag op de pagina.
Merk op dat de pagina content.aspx zelf geen <html>- of <body>-tag meer bevat.
Een <script>-sectie kan je zelf altijd toevoegen als er code moet uitgevoerd worden.
De Content-controls bevatten de eigenlijke inhoud van de pagina. Elke Content-control heeft een eigenschap ContentPlaceHolderID, die bepaalt binnen welke ContentPlaceHolder van de master-pagina de inhoud zal verschijnen.
Master-pagina's kunnen ook genest worden, dus de ene master-pagina kan al afgeleid zijn van een andere.
==Plaats van de master-pagina==
Soms staat de master-pagina niet in dezelfde folder als de pagina. Meestal is dit geen probleem.
Als de master-pagina verwijst naar andere bestanden, zoals stylesheets, afbeeldingen, of met hyperlinks bijvoorbeeld, dan moet je opletten, want als de pagina de verwijzing gewoon overneemt, dan klopt ze niet meer.
Bijvoorbeeld:
<pre><head>
<link rel="stylesheet" href="StyleSheet.css" type="text/css" />
</head>
...
<a href="inhoud.aspx">Inhoud</a>
...
<img alt="Bloem" src="Images/bloem.jpg"/></pre>
Dit voorbeeld werkt goed zolang de pagina in dezelfde folder staat als de master-pagina. In het andere geval kan je twee dingen doen:
*Gebruik absolute URL's in de master-pagina, bijvoorbeeld
<img src="/mijntoepassing/images/banner.gif" />
of
<nowiki><img src="https://www.mijndomein.com/mijntoepassing/images/banner.gif" /></nowiki>
*Gebruik applicatie-relatieve URL's in server controls, bijvoorbeeld
<asp:Image ImageUrl="~/images/banner.gif" runat="server" />
Ter herinnering: de tilde ~ verwijst naar de applicatie-root. Deze werkt alleen als je runat="server" gebruikt.
Het bovenstaande voorbeeld wordt dan:
<pre><head runat="server">
<link rel="stylesheet" href="~/StyleSheet.css" type="text/css" runat="server" />
</head>
...
<a id="A1" href="pages/inhoud.aspx" runat="server">Inhoud</a>
...
<asp:Image ID="Image1" AlternateText="Bloem" ImageUrl="~/Images/bloem.jpg"
runat="server"/></pre>
{{Bladeren2
|Boek=Programmeren in ASP.NET
|vorige=Validering
|huidige=Master-pagina's
|volgende=Navigatie
}}
{{Sub}}
8s8fm1az3ue73tqv9e514bki87jdhd6
Programmeren in ASP.NET/Gegevenstoegang
0
3560
428834
425775
2026-05-23T12:17:22Z
Erik Baas
2193
lf
428834
wikitext
text/x-wiki
{{Index Programmeren in ASP.NET}}
==Inleiding==
Dikwijls is het bij websites nodig om gegevens bij te houden voor de verschillende gebruikers. Dit kan nodig zijn om:
*gebruikers te laten kiezen welke informatie ze willen zien, bijvoorbeeld producten uit een webwinkel
*de gegevens opnieuw te gebruiken als de gebruiker opnieuw de site bezoekt, en als je geen cookies wil of kan gebruiken
*meerdere gebruikers te laten samenwerken, bijvoorbeeld op een forum, een wiki, of een intranet van een bedrijf
De meest gebruikte oplossing hiervoor is het bewaren van de gegevens in een databank. Bijna alle databankmerken kan je hiervoor gebruiken, en bij uitbreiding zelfs [[Microsoft Excel|Excel]], [[XML]], of gewoon tekstbestanden. In de praktijk wordt veel [[Microsoft Access|Access]] en [[SQL Server]] gebruikt.
Een databank of database is een bestand (of bestanden) waarin op een speciale manier gegevens opgeslagen kunnen worden. Een database bevat tabellen met rijen die we records noemen. Ieder record bevat op zijn beurt velden. Voor ieder record in een tabel is de betekenis van ieder veld hetzelfde. Een tabel met adresgegevens bevat bijvoorbeeld allemaal records met de velden adres, postcode, plaats, enz.
Tabellen in een database kunnen aan elkaar gerelateerd zijn, bijvoorbeeld persoonsgegevens en adresgegevens. Ieder record in de tabel met adresgegevens bevat dan een verwijzing naar een bepaald record in de tabel met persoonsgegevens.
De databank staat meestal op de webserver zelf, maar dit hoeft niet zo te zijn. Soms gebruikt men hiervoor een aparte databankserver.
Het werken met een databank via ASP.NET kan schematisch voorgesteld worden op deze manier:
In dit hoofdstuk en de volgende leer je hoe je een verbinding maakt met een databank, en hoe je vervolgens gegevens kan lezen en schrijven.
==ADO.NET==
ADO.NET is een gestandaardiseerde manier om toegang te krijgen tot verschillende soorten gegevens, vooral databanken.
ADO.NET is de opvolger van ADO (ActiveX Data Objects).
Het basiselement van ADO.NET is de DataSet. Dit vervangt wat vroeger in ASP een RecordSet-object heette.
Een DataSet is een kopie in het geheugen van de gegevens die uit een databank komen.
Het is een soort "afgekoppelde" weergave van de gegevens. Dit betekent dat de gegevens in het geheugen blijven ook zonder een actieve verbinding (connection) met de databank.
Het DataSet-object is veel krachtiger dan een RecordSet in ASP. Een DataSet ds heeft namelijk een collectie "DataTable"-objecten (ds.Tables), die elk kunnen gevuld worden met gegevens uit een andere tabel van de databank. Verder is er een collectie "DataRelation"-objecten die relaties kunnen leggen tussen de DataTable-objecten.
In ADO.NET zijn er 6 belangrijke objecten die helpen bij het werken met databanken:
{| class="wikitable"
|-
!Object!!Beschrijving
|-
|DataSet||object dat gegevens uit een tabel kan bewaren in het geheugen, en er bewerkingen op doen. Een DataSet kan meerdere tabellen bevatten, met onderlinge relaties.
|-
|Connection||object dat een verbinding maakt met een databank
|-
|Command||object dat SQL-opdrachten op een databank kan uitvoeren
|-
|DataAdapter||object nodig om gegevens in een DataSet te brengen vanuit een databank en omgekeerd
|-
|DataReader||object dat een reeks records van een databron kan lezen (forward-only)
|-
|CommandBuilder||Object om wijzigingen in een DataSet om te zetten in SQL commando's voor een databank zodat de wijzigingen kunnen doorgevoerd worden.
|}
Van elk van deze laatste 6 objecten zijn er twee versies: één voor OLEDB (met prefix OleDb) en één voor SQL (met prefix Sql). Zo heb je naast een OleDbConnection-object ook een SqlConnection-object.
'''Opmerking'''<br>
Vanaf versie 1.1 van dotNET heeft Microsoft ook een OdbcConnection-object (voor ODBC-databanken) en een OracleConnection-object (voor Oracle-databanken) voorzien.
Hiervoor moet je extra modules downloaden (zoek naar "ODBC .NET Data Provider" en "Oracle .NET Data Provider" op de Microsoft site).
==Een verbinding maken met een databank==
Om met een database te kunnen communiceren, moet je een database-connectie hebben. Om deze te maken bevat ADO.NET twee objecten: het OleDbConnection-object en het SqlConnection-object.
Om een dergelijk object aan te maken, moet je de databank die je wil openen opgeven in een zogenaamde [[Programmeren in ASP.NET/Werken met databanken#Een databaseconnectie maken|connectiestring]].
Voorlopig nemen we als voorbeeld de connectiestreng voor een OLEDB-verbinding met een Access-databank "adressen.mdb". Het databankbestand zet je best in de folder App_Data binnen je website. Deze folder is daar speciaal voor bedoeld, en is ook extra beveiligd. Je kan de gegevens bekijken en wijzigen binnen Visual Studio via de Database Explorer (blader naar de tabel, klik rechts en kies "Show Table Data".
De connectiestreng is dan:
"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=c:\inetpub\wwwroot\App_Data\adressen.mdb"
Het Connection-object maak je aan op deze manier:
Dim cn As New OleDbConnection(strConn)
waarin strConn de connectiestreng is.
Nadat je zo'n object hebt aangemaakt, open je de databank met de Open()-methode.
Als je klaar bent met de gegevens gebruik je de Close()-methode om de connectie weer te sluiten.
De connectie met de databank gaat dan als volgt:
<syntaxhighlight lang="sql"><%@ import Namespace="System.Data" %>
<%@ import Namespace="System.Data.OleDb" %>
< script runat="server">
Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs)
Dim strConn As String = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & _
"c:\inetpub\wwwroot\App_Data\adressen.mdb")
Dim cn As New OleDbConnection(strConn)
Try
cn.Open()
... doe hier al wat je wil met de databank ...
Catch ex As Exception
Trace.Warn(ex.Message)
Finally
cn.Close()
End Try
End Sub
</script></syntaxhighlight>
'''Opmerkingen'''
*Je gebruikt hier een OleDbConnection-object. Om dit te gebruiken moet je twee naamruimtes importeren (System.Data en System.Data.OleDb).
*Bij het aanmaken van het OleDbConnection-object geef je de connectiestreng mee als parameter.
*Je maakt een Open()- en Close()-paar, waartussen je de databank kan manipuleren. Later zullen we zien dat dit bij sommige operaties weggelaten mag worden, omdat die operaties zelf zorgen voor het openen en sluiten van de connectie.
*Je gebruikt een exception-blok om mogelijke fouten op te vangen. De Close()-methode schrijf je in het Finally-blok. Dit zorgt ervoor dat de connectie bij een fout niet per ongeluk open blijft staan. Anders kan je daarna problemen hebben om de connectie nogmaals te openen (bijvoorbeeld met Access-databanken).
*Bij de connectiestreng gebruik je een absoluut pad c:\inetpub\wwwroot\App_Data\adressen.mdb. Dit is de exacte locatie van de databank op de server.
"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=c:\inetpub\wwwroot\App_Data\adressen.mdb"
*Het kan gebeuren dat je de exacte locatie van de databank niet weet. Dit gebeurt bijvoorbeeld als je de bestanden uploadt met FTP, en als je zelf niet verantwoordelijk bent voor de serveradministratie. Het kan ook gebeuren dat je de code uitprobeert op een testserver waar de locatie misschien verschillend is. Dan zou je bij het uploaden telkens de code moeten aanpassen. Beide problemen kunnen opgelost worden door een relatieve locatie te gebruiken, dit wil zeggen de locatie van de databank relatief ten opzichte van het aspx-bestand. Er bestaat een functie Server.MapPath() waarmee je een relatieve locatie kan omzetten in een absolute:
"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & Server.MapPath("App_Data\adressen.mdb")
*Je kan de locatie van de databank ook aangeven relatief ten opzichte van de root van de applicatie. Dan gebruik je de krul ~, die in ASP.NET de root aangeeft:
"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & Server.MapPath("~\App_Data\adressen.mdb")
*Zie de [[Programmeren in ASP.NET/Appendix: foutmeldingen|Appendix]] voor de betekenis van allerlei foutmeldingen.
==Gegevens opvragen met een DataReader==
Een DataReader geeft een zogenaamde forward-only en read-only verbinding naar de resultatenset. Je kan je een DataReader-object voorstellen als een datastructuur die maar één record (één rij gegevens) tegelijk kan bevatten.
Je kan de rijen maar één keer lezen van voor naar achter. Je kan de gegevens ook niet wijzigen. Het voordeel is de hogere snelheid, de datareader is daar speciaal voor geoptimaliseerd.
DataReaders worden daarom vooral gebruikt als de gegevens maar één keer gelezen moeten worden, bijvoorbeeld bij het simpelweg tonen van een lijst op een pagina.
Als je daarentegen werkt met bijvoorbeeld pagineren of sorteren van gegevens, dan gebruik je een DataSet (zie verder).
Ook als je tijdens het doorlopen van de gegevens een nieuwe query wil doen, dan moet je voor de eerste query een DataSet gebruiken. Je kan immers maar één DataReader tegelijk uitlezen, maar wel meerdere DataSets.
Het DataReader-object bevat een methode Read(), waarmee het eerstvolgende record ingeladen wordt. Als er geen records meer zijn, zal deze methode False teruggeven, zodat je weet dat je aan het einde van de gegevens gekomen bent. Als je daarna toch nog probeert te lezen krijg je een fout (Exception).
Verder heeft het DataReader-object verschillende methodes om de gegevens uit het record te halen (GetString(i), GetInt32(i), GetBoolean(i), enz...). Hierin is i de kolom waaruit je gegevens wil halen (de eerste kolom heeft index 0).
In de volgende voorbeelden wordt gebruik gemaakt van een tabel "AdresTabel" met volgende velden:
{| class="wikitable"
|-
|veldnaam||type
|-
|ID||autonumber
|-
|Voornaam||string
|-
|Naam||string
|-
|Adres||string
|-
|Postcode||string
|-
|Gemeente||string
|}
''datareader.aspx''
<syntaxhighlight lang="vb"><%@ Page Language="VB" %>
<%@ import Namespace="System.Data" %>
<%@ import Namespace="System.Data.OleDb" %>
<script runat="server">
Sub Page_Load(Sender As Object, E As EventArgs)
Dim strConn As String = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & _
Server.MapPath("App_Data\adressen.mdb")
Dim strSQL As String = "SELECT ID, Naam, Adres FROM adrestabel"
Dim cn As New OleDbConnection(strConn)
Try
cn.Open()
Dim cm As New OleDbCommand(strSQL,cn)
Dim dr As OleDbDataReader = cm.ExecuteReader()
If dr.HasRows() Then
While dr.Read()
Label1.Text = Label1.Text & dr("ID").ToString() & " " & _
dr("Naam").ToString() & " " & _
dr("Adres").ToString() & "<br>"
End While
Else
Label1.Text = "Geen rijen gevonden."
End If
Catch ex As Exception
Trace.Warn(ex.Message)
Label1.Text = "Probleem met databank."
Finally
cn.Close()
End Try
End Sub
</script>
<html>
<head>
<title>DataReader</title>
</head>
<body>
<asp:Label id="Label1" runat="server"></asp:Label>
</body>
</html> </syntaxhighlight>
'''Opmerkingen'''
*In de plaats van dr("Naam").ToString()mag je ook schrijven:
dr("Naam") of
dr.Item("Naam") of
dr.GetString(1) of
dr.Item("Naam").ToString() of
dr.Item(1).ToString() of korter
dr(1).ToString().
*dr("Naam"), dr.Item("Naam"), en dr.GetString(1) werken alleen als het veld echt een string bevat. Als het veld bijvoorbeeld een Integer of NULL bevat, dan krijg je een foutmelding. De andere schrijfwijzen werken voor alle datatypes (en zetten die om naar strings).
*dr(1).ToString() is sneller dan dr("Naam").ToString()
*dr(1).ToString() kan problemen geven als je later het ontwerp van de databank verandert (meer of minder kolommen, of een andere volgorde).
*de HasRows()-methode wordt niet ondersteund in ASP.NET versie 1.0
===Oefeningen===
#Maak een pagina waar je adressen uit een databank toont in de vorm van een HTML-tabel.
#Maak een pagina die de eerste 5 adressen toont. Hou er rekening mee dat de databank misschien minder dan 5 adressen bevat.
#Maak een pagina die alleen het adres toont van de eerste persoon in de lijst. Bij het klikken op een link, toon je de volgende persoon in de lijsttts
==Gegevens opvragen met een dataset==
Je kan ook een DataSet gebruiken om gegevens uit een databank te halen. Een DataSet is een kopie van een tabel of query in het geheugen van de server.
Om een DataSet te vullen heb je nog een ander object nodig: de DataAdapter (die bestaat in twee versies: OleDbDataAdapter of SQLDataAdapter). Een DataSet wordt in één keer gevuld (met de Fill()-methode van de DataAdapter). Daarna kan je de gegevens gebruiken, en eventueel zelfs bijwerken in de DataSet.
De vorige pagina ziet er met een DataSet zo uit:
''dataset.aspx''
<syntaxhighlight lang="vb"><%@ Page Language="VB" %>
<%@ import Namespace="System.Data" %>
<%@ import Namespace="System.Data.OleDb" %>
<script runat="server">
Sub Page_Load(Sender As Object, E As EventArgs)
Dim strConn As String = "Provider=Microsoft.Jet.OLEDB.4.0;" & _
"Data Source=" & Server.MapPath("App_Data\adressen.mdb")
Dim strSQL As String = "SELECT * FROM adrestabel"
Dim cn As New OleDbConnection(strConn)
Try
Dim cm As New OleDbCommand(strSQL,cn)
Dim da As New OleDbDataAdapter(cm)
Dim ds As New DataSet()
da.Fill(ds)
Dim i As Integer
For i=0 To ds.Tables(0).Rows.Count - 1
Label1.Text = Label1.Text & _
ds.Tables(0).Rows(i).Item(0).ToString() & " " & _
ds.Tables(0).Rows(i).Item(1).ToString() & " " & _
ds.Tables(0).Rows(i).Item(2).ToString() & "<br>"
Next i
Catch ex As Exception
Trace.Warn(ex.Message)
Finally
cn.Close()
End Try
End Sub
</script>
<html>
<head>
<title>DataSet</title>
</head>
<body>
<form runat="server">
<asp:Label id="Label1" runat="server"></asp:Label>
</form>
</body>
</html></syntaxhighlight>
'''Opmerkingen'''
*Het is niet nodig om de connectie eerst te openen met cn.Open(), de DataAdapter doet dit automatisch.
*Eenmaal de DataSet gevuld is, dan kan je elk onderdeel van de data afzonderlijk opvragen. Om de inhoud van rij r en kolom k op te vragen gebruik je bijvoorbeeld: ds.Tables(0).Rows(r).Item(k).ToString().
*In deze pagina is het resultaat hetzelfde, maar een DataReader is sneller en legt minder beslag op het geheugen van de server. Met een DataSet kan je de resultaten in een willekeurige volgorde doorlopen, en je kan twee operaties (bijvoorbeeld twee tabellen uitlezen) doen met dezelfde connectie.
==Een scalar opvragen==
Soms moet je uit een databank maar één enkele waarde opvragen, bijvoorbeeld het aantal records met een bepaalde eigenschap. Men noemt dit een scalar-waarde.
Dit stuk code vindt bijvoorbeeld het aantal records in de ganse tabel:
''scalar.aspx''
<syntaxhighlight lang="vb"><%@ Page Language="VB" %>
<%@ import Namespace="System.Data" %>
<%@ import Namespace="System.Data.OleDb" %>
<script runat="server">
Sub Page_Load(Sender As Object, E As EventArgs)
Dim strConn As String = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & _
Server.MapPath("App_Data\adressen.mdb")
Dim strSQL as string = "SELECT COUNT(*) FROM AdresTabel;"
Dim cn As New OleDbConnection(strConn)
Try
Dim cm As New OleDbCommand(strSQL,cn)
cn.Open()
Dim aantal As Integer=cm.ExecuteScalar()
Label1.Text=aantal
Finally
cn.Close()
End Try
End Sub
</script>
<html xmlns="https://www.w3.org/1999/xhtml" >
<head runat="server">
<title>Scalar</title>
</head>
<body>
<form id="form1" runat="server">
<asp:Label ID="Label1" runat="server"></asp:Label></div>
</form>
</body>
</html></syntaxhighlight>
Omdat de query maar één waarde als resultaat geeft, mag je ExecuteScalar() gebruiken.
'''Opmerkingen'''
*ExecuteScalar() kan ook een string, een DateTime of een boolean teruggeven
*Indien de query toch meerdere rijen, meerdere kolommen of allebei teruggeeft, dan is het resultaat van ExecuteScalar() de waarde in de eerste kolom van de eerste rij.
===Oefeningen===
#Maak een pagina die het ID van het laatste record opzoekt en toont.
#Maak een pagina die het telefoonnummer van het eerste adres in AdresTabel opzoekt.
==Parameters gebruiken==
Soms hangt de query die je moet uitvoeren af van wat de gebruiker gekozen heeft.
Je kan de bovenstaande code uitbreiden door de gebruiker een criterium te laten opgeven. Zo kan de gebruiker bijvoorbeeld een gemeente opgeven, en alleen de adressen uit die gemeente worden dan getoond.
In SQL gebruik je hiervoor de WHERE-clause.
Je zal dus verschillende SQL-strengen krijgen:
SELECT COUNT(*) FROM AdresTabel WHERE Gemeente='Brussel';
SELECT COUNT(*) FROM AdresTabel WHERE Gemeente='Gent';
enz.<br>
waarbij je de echte gemeente niet op voorhand kent.
Een eerste manier om deze variabele gegevens in de SQL-streng te krijgen is met behulp van concatenatie: je plakt deze gegevens op de juiste plaats in de streng.
"SELECT * FROM AdresTabel WHERE Gemeente='" & tbGemeenteVak & "';"
Let hierbij goed op dat je niet vergeet aanhalingstekens toe te voegen als het over strings gaat. Dit moeten enkele aanhalingstekens zijn (ze behoren immers tot de SQL-syntax).
''scalar2.aspx (fragment)''
<syntaxhighlight lang="sql">Dim strSQL As String = "SELECT COUNT(*) FROM AdresTabel WHERE Gemeente='" & _
tbGemeente.Text & "';"
Dim cn As New OleDbConnection(strConn)
Try
cn.Open()
Dim cm As New OleDbCommand(strSQL,cn)
Dim aantal As Integer=cm.ExecuteScalar()
Catch ex As Exception
Trace.Warn(ex.Message)
Finally
cn.Close()
End Try</syntaxhighlight>
Dit is een methode die in sommige gevallen echter problemen kan geven.
Probeer bijvoorbeeld eens een naam in te vullen met een apostrof (bijvoorbeeld 's Gravenhage). Deze apostrof komt dan gewoon in de SQL-streng terecht, en de streng is niet meer correct. Om dit op te vangen, moet je in alle ingevoerde velden de apostroffen vervangen door dubbele apostroffen, vooraleer ze in de SQL-opdracht in te brengen.
Bovendien kunnen hackers proberen in het invoervak een systeemcommando in te geven. Het zou kunnen dat dit commando dan via de SQL-streng een gevaarlijke opdracht aan de server geeft.
Bijvoorbeeld:
"SELECT * FROM Adressen WHERE Gemeente = '" & tbGemeente.text & "';"
Stel: een hacker vult als gemeente de volgende waarde in:
'; DROP TABLE AdresTabel --
Dit kan wel catastrofaal zijn voor je gegevens!
Om dit te vermijden, bevat het OleDbCommand-object (net zoals het SqlCommand-object) een eigenschap "Parameters", waaraan je variabele gegevens kan toevoegen. Het OleDbCommand-object zorgt er dan voor dat voor alle mogelijke datatypes de juiste syntax gebruikt wordt in de SQL-streng, en dat gevaarlijke commando's onderschept worden.
''scalar3.aspx (fragment)''
<syntaxhighlight lang="sql">Dim strSQL As String = "SELECT * FROM AdresTabel WHERE Gemeente=@gemeente;"
Dim cn As New OleDbConnection(strConn)
Try
cn.Open()
Dim cm As New OleDbCommand(strSQL,cn)
cm.Parameters.AddWithValue("@Gemeente",GemeenteVak.Text)
Dim aantal As Integer=cm.ExecuteScalar()
Catch ex As Exception
Trace.Warn(ex.Message)
Finally
cn.Close()
End Try</syntaxhighlight>
'''Opmerkingen'''
*In de SQL-streng vervang je de variabelen (de parameters) door een naam die je zelf kiest, maar je moet als eerste teken een apenstaart gebruiken om aan te geven dat het een parameter is:
SELECT * FROM AdresTabel WHERE Gemeente=@Gemeente;
*Je voegt de echte waarden van de parameters toe aan het Command-object cm met de opdracht:
cm.Parameters.AddWithValue("@Gemeente",tbGemeente.Text)
*Merk op dat de aanhalingstekens niet meer nodig zijn rond de parameter.
*In Access mag je ook een vraagteken gebruiken:
SELECT * FROM AdresTabel WHERE Gemeente=?;
*Als je een vraagteken gebruikte, moet je toch een string opgeven bij cm.Parameters.AddWithValue(). De inhoud van de string heeft in feite geen belang.
*Let goed op: als er meerdere parameters zijn bij OLEDB (bijvoorbeeld Access), dan moeten ze toegevoegd worden in dezelfde volgorde waarin ze in de SQL-streng voorkomen. Men zegt dat de parameters positioneel zijn.
*Parameters maken het werken met datums ook veel gemakkelijker, omdat je je geen zorgen meer moet maken over het formaat, bv:
cm.Parameters.AddWithValue("@datum",Today())
*In ASP.NET 1.x gebruik je de methode cm.Parameters.Add in plaats van cm.Parameters.AddWithValue. De rest van de code verandert niet.
===Oefeningen===
#Maak weer een pagina waar je kan kiezen tussen 2 talen. Afhankelijk van de keuze wordt een andere pagina met informatie getoond, in de juiste taal. Dit keer wordt de inhoud van de pagina uit een databank gehaald (zet de inhoud van de pagina in een veld met data type "Memo").
#Maak een databanktabel met postcodes. Maak een pagina waar je de naam van een gemeente kan intikken. Het ASP.NET script zoekt de postcode van die gemeente en toont die op het scherm.
#Maak een databank met namen en wachtwoorden. Als de gebruiker met de juiste naam en het juiste overeenkomstige wachtwoord inlogt wordt de rest van de pagina zichtbaar.
==Lijsten vullen vanuit een databank==
===Zonder databinding===
''lijstzonderbinding.aspx''
<syntaxhighlight lang="vb"><%@ Page Language="VB" %>
<%@ import Namespace="System.Data" %>
<%@ import Namespace="System.Data.OleDb" %>
<script runat="server">
Sub Page_Load(Sender As Object, E As EventArgs)
Dim strConn As String = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & _
Server.MapPath("App_Data\adressen.mdb")
Dim strSQL As String = "SELECT * FROM adrestabel"
Dim cn As New OleDbConnection(strConn)
Try
cn.Open()
Dim cm As New OleDbCommand(strSQL,cn)
Dim dr As OleDbDataReader = cm.ExecuteReader()
While dr.Read()
lbAdressen.Items.Add(dr("Naam").ToString())
End While
Catch ex As Exception
Trace.Warn(ex.Message)
Finally
cn.Close()
End Try
End Sub
</script>
<html>
<head>
<title>Lijst zonder binding</title>
</head>
<body>
<form runat="server">
<asp:Listbox id="lbAdressen" runat="server" ></asp:Listbox>
</form>
</body>
</html> </syntaxhighlight>
Er zijn een aantal lijstcontrols die de lus hierboven (waarin de DataReader doorlopen wordt) zelf beter kunnen uitwerken. Dit noemt men databinding.
===Met databinding===
Hier zullen we een keuzelijst (ListBox) vullen met namen uit een databank met behulp van databinding.
Sleep de keuzelijst op de pagina, open het Smart Tag paneel, kies "Choose Data Source…", en vervolgens "<New data source…>". Je krijgt de Datasource Configuration Wizard.
Met deze wizard kan je verbinden met verschillende soorten databronnen.
Het ASP.NET 2.0 framework bevat verschillende DataSource-controls die ontworpen zijn om te werken met verschillende databronnen. De pagina hier bevat een AccessDataSource-control. De SqlDataSource-control kan records opvragen van een SQL-databank, zoals SQL Server of Oracle. Er zijn ook ObjectDataSource-, XmlDataSource- en SiteMapDataSource-controls.
Kies "Access Database", en vervolgens "OK". Selecteer de juiste databank (we nemen nogmaals Adressen.mdb in App_Data) en kies "Next".
In de volgende stap moet je het SELECT-statement samenstellen. Kies de juiste tabel en de juiste kolommen.
Merk op dat je optioneel een DISTINCT-clause (het aankruisvakje "Return only unique rows"), een WHERE-clause en een ORDER BY-clause kan instellen. We zullen die later gebruiken.
Via "Advanced" kan je eventueel de overeenkomstige INSERT-, UPDATE-, en DELETE- commando's genereren. We gebruiken die later bij de [[Programmeren in ASP.NET/GridView|GridView]].
Na "Next" kan je de verbinding testen en klikken op "Finish".
Je moet natuurlijk bij de ListBox instellen welk veld je wil zien. Dit gebeurt via "Data field to display", waardoor de property DataTextField ingesteld wordt. Je kan ook een DataValueField instellen via "Data field for the value", dit is het veld dat zal gebruikt worden als "value" voor elk item in de lijst. Kies respectievelijk "Naam" en "ID".
Als je klaar bent, ziet de HTML-code er ongeveer zo uit:
''lijst.aspx''
<syntaxhighlight lang="vb"><%@ Page Language="VB" %>
<html>
<head>
<title>Lijst met databinding</title>
</head>
<body>
<form id="form1" runat="server">
<asp:ListBox ID="ListBox1" runat="server" DataSourceID="AccessDataSource1"
DataTextField="Naam" DataValueField="ID" />
<asp:AccessDataSource ID="AccessDataSource1" runat="server"
DataFile="~/App_Data/Adressen.mdb"
SelectCommand="SELECT * FROM [AdresTabel]" />
</form>
</body>
</html></syntaxhighlight>
Let op de waarden voor DataTextField en DataValueField. Die waarden bepalen welke velden voor de ListBox gebruikt zullen worden.
Merk op dat er helemaal geen code meer nodig is! De AccessDataSource-control zorgt voor het ophalen van de gegevens en via de koppeling wordt de keuzelijst gevuld.
Bij het bekijken van de broncode in de browser kan je controleren dat voor elk item in de lijst (<option>-tags) het ID als value gebruikt wordt.
===Parameters gebruiken===
Je kan de bovenstaande code uitbreiden door de gebruiker een criterium te laten opgeven. Zo kan de gebruiker bijvoorbeeld een gemeente opgeven, en alleen de adressen uit die gemeente worden dan getoond.
Het DataSource-object (net zoals het AccessDataSource-object) bevat een eigenschap "SelectParameters", waaraan je variabele gegevens kan toevoegen. Het AccessDataSource -object zorgt er dan voor dat voor alle mogelijke datatypes de juiste syntax gebruikt wordt in de SQL-streng, en dat gevaarlijke commando's onderschept worden.
Gebruik opnieuw de wizard om de datasource op te geven, maar gebruik nu een WHERE-clause.
''lijstmetparameters.aspx''
<syntaxhighlight lang="vb"><%@ Page Language="VB" %>
<script runat="server">
Protected Sub btnToon_Click(ByVal sender As Object, ByVal e As System.EventArgs)
' geen code nodig
End Sub
</script>
<html>
<head>
<title>Lijst met parameters</title>
</head>
<body>
<form id="form1" runat="server">
Gemeente:<asp:TextBox id="tbGemeente" runat="server"></asp:TextBox>
<br>
<asp:Button id="btnToon" onclick="btnToon_Click" runat="server" Text="Toon"/>
<br>
<asp:ListBox ID="Listbox1" runat="server" DataSourceID="AccessDataSource1"
DataTextField="Naam" DataValueField="ID" />
<asp:AccessDataSource ID="AccessDataSource1" runat="server"
DataFile="~/App_Data/Adressen.mdb"
SelectCommand="SELECT * FROM [AdresTabel] WHERE ([Gemeente] = ?)">
<SelectParameters>
<asp:ControlParameter ControlID="tbGemeente" Name="Gemeente"
PropertyName="Text" Type="String" />
</SelectParameters>
</asp:AccessDataSource>
</form>
</body>
</html></syntaxhighlight>
===Oefeningen===
#Maak een databank met daarin een tabel met landnamen (België, Nederland, Frankrijk, ...). Maak dan een pagina met een keuzelijst waarin al deze landen voorkomen.
#Maak een pagina die een lijst met productnamen uit de tabel "Products" uit de Northwind-databank op het scherm zet.
#Maak een kleine databank met een agenda (gebeurtenissen en datums). Als de gebruiker een datum invoert, worden de gebeurtenissen van die datum getoond.
{{Bladeren2
|Boek=Programmeren in ASP.NET
|vorige=Navigatie
|huidige=Gegevenstoegang
|volgende=Werken met databanken
}}
{{Sub}}
rg8utw7mo8sptblx07ermef47xv0223
Programmeren in ASP.NET/Werken met databanken
0
3617
428829
425781
2026-05-23T12:17:17Z
Erik Baas
2193
lf
428829
wikitext
text/x-wiki
{{Index Programmeren in ASP.NET}}
==OLEDB, ODBC, en ADO.NET==
Je kunt met ASP.NET (of andere programmeeromgevingen) niet direct met een database werken. Hiervoor heb je een zogenaamde API (Application Programming Interface) nodig. Verder is er een verbinding met de database nodig. Een dergelijke verbinding wordt gemaakt met OLEDB of ODBC:
{| class="wikitable"
|-
! !!OLEDB!!ODBC
|-
|Betekenis||Object Linking and Embedding – DataBase||Open DataBase Connectivity
|-
|Voordelen
|
*Nieuwer
*Flexibeler
*Sneller
|
*Ondersteunt meer verschillende soorten databanken
|}
OLEDB of ODBC gebruik je via ADO.NET. ADO staat voor ActiveX Data Ojects. ADO is een verzameling objecten die als API dienen, en die je dus kan gebruiken in je code.
Om het bovenstaande te begrijpen kun je het geheel vergelijken met het telefoonnetwerk. ODBC is dan te vergelijken met het analoge telefoonnetwerk, OLEDB met ISDN (dezelfde functie, alleen sneller en geavanceerder). ADO.NET is het telefoontoestel en met SQL geef je aan welke gegevens je wil hebben, zoals je door een nummer te draaien aangeeft wie je wil spreken.
==Een databaseconnectie maken==
Om met een database te kunnen communiceren, moet je een databaseconnectie hebben. Om deze te maken bevat ADO.NET het Connection-object. Nadat je een Connection-object hebt aangemaakt, open je een database met de Open()-methode. Hierbij vermeld je de databank die je wil openen in een zogenaamde connectiestreng. Als je klaar bent met de gegevens gebruik je de Close()-methode om de connectie weer te sluiten.
===Een connectiestring maken===
De connectiestreng bevat alle gegevens waarmee de server de databank kan terugvinden en openen.
In de connectiestreng specificeer je het type database, de plaats en de naam van de database. Je kan indien nodig ook parameters zoals een gebruikersnaam en wachtwoord opgeven.
Een connectiestreng bestaat uit namen van sleutels en waarden, gescheiden door puntkomma's.
Een connectiestreng ziet er bijvoorbeeld als volgt uit:
"sleutel1=waarde1;sleutel2=waarde2;sleutel3=waarde3;"
De volgorde van de verschillende sleutel/waarde koppels heeft geen belang.
'''Let op''': spaties zijn soms heel belangrijk in deze strings, dus je moet ze letterlijk overnemen.
Dit zijn enkele veel voorkomende voorbeelden:
;SQL Server
"Data source=(local);initial catalog=Northwind;Integrated Security=True;"
;MS Access
"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=c:\databases\MijnDB.mdb;"
Lees [https://www.connectionstrings.com] of [https://www.carlprothman.net/default.aspx?tabid=81] voor een lijst met verschillende connectiestrengen voor verschillende databases.
Vooraleer een database te kunnen aanspreken in een ASPX-bestand, kan deze al of niet via DSN (ODBC) op de server ter beschikking gesteld worden.
===DSN===
Als je wilt kan jij (of jouw provider) op de server een vaste naam (een soort "alias") voor de databankconnectie instellen. Vanuit alle ASPX-documenten is de database dan onder die naam bereikbaar.
Dit noemt men een DSN (Data Source Name) voor de databank.
In de telefoonanalogie van hierboven is DSN te vergelijken met een knop die je kan instellen op een bepaald telefoonnummer.
===Voordelen en nadelen van DSN===
====DSN====
Het grote voordeel van de methode is dat bij het wijzigen (type of bestandsnaam) van de database niet alle ASP.NET documenten hoeven te worden aangepast. De database blijft immers gewoon onder zijn DSN-naam op de server bekend! In ASP.NET kan tegenwoordig de connectiestreng ook centraal ingesteld worden, zodat dit voordeel niet meer speelt.
====DSN-loos ====
De DSN-loze methode wordt vaak gebruikt bij experimenten en tijdelijke pagina's.
Het is erg eenvoudig om de te gebruiken database te wisselen. Het verschil is dat met DSN?less de connectiestreng in de code gewijzigd moet worden als er van een andere database gebruik gaat worden gemaakt of als de database op een andere locatie (subfolder) komt te staan.
DSN-loze verbindingen maken het ook gemakkelijk om toepassingen naar andere machines te verplaatsen, omdat je dan niet telkens een DSN moet opzetten.
Sommige providers rekenen extra kosten voor DSN-verbindingen, dus in dat geval is DSN-loos goedkoper.
Tenslotte is een DSN-loze verbinding soms minder veilig, met name als het wachtwoord in de code moet geschreven worden. Iedereen die toegang krijgt tot de code heeft dan ook toegang tot het wachtwoord op de databank.
==Een connectie met DSN==
Op de server wordt een DSN (Data Source Name) door de beheerder gedefinieerd. Dit kan gerealiseerd worden op verschillende manieren:
*via het configuratiescherm van Windows onder Administrative Tools - Data Sources (ODBC). Kies de klep System DSN. Klik Add. Kies Microsoft Access Driver (*.mdb). Kies een naam voor de connectie in "Data Source Name". Klik op "Select" en blader naar het databank bestand dat je wil koppelen.
*vanuit Visual Studio.NET
*vanuit FrontPage
*vanuit UltraDev of Dreamweaver MX
Veel databanken kan je bovendien beveiligen met een gebruikersnaam (UID) en wachtwoord (PWD).
===Een SQL Server-database openen met DSN===
Een SQL Server-database die zich op de internetserver bevindt en die via ODBC als DSN-naam "leden" heeft kan als volgt benaderd worden:
Dim strConn As String = "DSN=leden;UID=x1;PWD=x2"
Dim cn As New SqlConnection(strConn)
cn.Open()
......
cn.Close()
waarbij x1 de gebruikersnaam en x2 het wachtwoord is waarmee de database te bereiken is.
===Een Access-database openen met DSN===
Een Access-databank die zich op de internet-server bevindt en die via ODBC als DSN-naam "leden" heeft kan als volgt benaderd worden.
Dim strConn As String = "DSN=leden"
Dim cn As New ODBCConnection(strConn)
cn.Open()
......
cn.Close()
De connectiestreng is dus niets meer dan de DSN-naam!
==Een connectie zonder DSN==
De mogelijkheid bestaat een SQL Server- of een Access-databank rechtstreeks te activeren. Dit kan als volgt:
===Een SQL Server-database openen zonder DSN===
Een SQL-server database kan op deze manier opgeroepen worden:
Dim strConn As String="data source=x1;initial catalog=x2;Integrated Security=SSPI"
Dim cn As New SqlConnection(strConn)
cn.Open()
......
cn.Close()
waarbij:
*x1=naam of IP-nummer van de server
*x2=naam van de database op de SQL-server
Voor de connectiestreng zijn er nog verschillende mogelijkheden:
====Windows Integrated authenticatie====
"data source=x1;initial catalog=x2;Integrated Security=True"
of
"Server=x1;trusted_connection=true;Database=x2"
====SQL-Server authenticatie====
"Server=x1;Database=x2;User ID=x3;Password=x4"
waarbij:
*x1=naam of IP-nummer van de server
*x2=naam van de database op de SQL-server
*x3=loginnaam op de SQL-server
*x4=wachtwoord op de SQL-server
====SQL Server 2005 bestandsgebaseerd====
"Provider=SQLNCLI;Data Source=x1;AttachDbFileName=e:\data\Customers.mdf; Integrated Security=True;User Instance=True"
of
"Provider=SQLNCLI;Data Source=.\SQLEXPRESS;AttachDbFileName=|DataDirectory|data.mdf;Integrated Security=True;User Instance=True"
De punt in .\SQLEXPRESS staat hier voor de lokale server. Je mag ook (local)\SQLEXPRESS schrijven.
In de laatste string wordt de expressie |DataDirectory| automatisch vervangen door het juiste pad naar de folder App_Data binnen de website. Hierdoor is de connectiestring onafhankelijk van de server waarop de site draait, en kan je de pagina gewoon kopiëren naar de server met FTP zonder wijzigingen.
===SQL Server met ODBC===
Het kan ook met ODBC als volgt:
"Driver={SQLServer};SERVER=x1;DATABASE=x2;UID=x3;PWD=x4"
Maar dan gebruik je een ODBCConnection in plaats van een SqlConnection.
===Een Access-databank openen via ODBC===
Een Access databank kan ook zonder DSN-instellingen op de internetserver bereikt worden, en wel als volgt (DSN-loze ODBC-verbinding):
<pre>Dim strConn As String = "DRIVER={Microsoft Access Driver (*.mdb)};" & _
"DBQ=c:\inetpub\wwwroot\App_Data\adressen.mdb;
Dim cn As New ODBCConnection(strConn)
cn.Open()
......
cn.Close()</pre>
waarbij "adressen.mdb" de Access databank is.
Deze methode kan problemen geven als je de bestanden naar een andere server kopieert, waar de bestanden bijvoorbeeld op de d: schijf staan. Het kan zelfs zijn dat je de echte locatie van de bestanden niet weet.
Daarom is het altijd beter een relatief pad te gebruiken in je pagina's, relatief ten opzichte van de plaats van de huidige pagina. De server kan dit pad omzetten naar het echte absolute pad met de methode Server.MapPath().
Hoe dit gebeurt zie je in dit voorbeeld:
<pre>Dim strConn As String = "DRIVER={Microsoft Access Driver (*.mdb)};DBQ=" & _
Server.MapPath("App_Data\adressen.mdb") & ";"
Dim cn As New ODBCConnection(strConn)
cn.Open()
......
cn.Close()</pre>
waarbij "App_Data\adressen.mdb" het relatieve pad is naar de databank adressen.mdb.
'''Opmerking'''<br>
Om een Access databank te kunnen openen, moet de gebruikersaccount de nodige bestandsrechten bezitten op het databank MDB-bestand (bv. adressen.mdb). ASP.NET maakt bij de installatie een gebruiker ASPNET (Windows 2000/XP) of NETWORK SERVICE (Windows 2003) aan, die gebruikt wordt tijdens het ganse proces (tenzij je impersonation gebruikt, zie hoofdstuk 25).
Voor het opvragen van gegevens betekent dit dat de gebruiker ASPNET of NETWORK SERVICE leestoegang moet hebben tot het MDB-bestand. Voor het wijzigen van gegevens moet deze gebruiker bovendien modify-rechten hebben.
===Een Access-databank openen zonder ODBC===
Er is nog een tweede manier om een Access-databank te openen zonder ODBC te gebruiken (DSN-loze OLEDB-verbinding):
<pre>Dim strConn As String = " Microsoft.Jet.OLEDB.4.0;Data Source=" & _
Server.MapPath("App_Data\adressen.mdb"& ";"
Dim cn As New OleDbConnection(strConn)
cn.Open()
......
cn.Close()</pre>
De verbinding via OLEDB is iets sneller omdat de ODBC-driver overgeslagen wordt:
ADO → OLEDB → Databank
is sneller dan:
ADO → OLEDB → ODBC → Databank
===Oefeningen===
#Maak een pagina die een lijst toont met de uitgevers in de SQL Server-voorbeelddatabank "pubs". Gebruik een "trusted connection".
#Zelfde oefening, maar nu met een "untrusted connection".
#Maak een kleine databanktabel in Excel. Zoek op wat de connectiestreng is voor dit soort gegevensbron en toon de gegevens met een ASP.NET-pagina.
#Zelfde oefening, maar nu met een tekstbestand.
==Een connectiestring instellen in web.config==
Je kan dezelfde instelling ook maken in web.config. Dan geldt ze niet voor de ganse applicatie, maar wel voor de ganse directory (en subdirectory's). Het opvragen is ook verschillend.
In ASP.NET 2.0 is hier een speciaal element <connectionStrings> voor toegevoegd aan web.config (als onderdeel van <configuration>).
''web.config''
<pre><configuration ...>
<appSettings>
...
</appSettings>
<connectionStrings>
<add name="AdressenConnectionString"
connectionString="Provider=Microsoft.Jet.OLEDB.4.0;Data Source=c:\data\adressen.mdb"
providerName="System.Data.OleDb" />
</connectionStrings>
<system.web>
...
</system.web>
</configuration></pre>
De instelling kan je in je pagina's opvragen met deze code:
Dim strConn As String = _
ConfigurationManager.ConnectionStrings("AdressenConnectionString").ConnectionString
Als je nog werkt met ASP.NET 1.x, dan moet je het <appSettings>-element gebruiken:
''web.config''
<pre> <appSettings>
<add key="connectionstring"
value="Provider=Microsoft.Jet.OLEDB.4.0;Data Source=c:\data\adressen.mdb"/>
</appSettings></pre>
De instelling kan je in je pagina's opvragen met deze code:
Dim strConn As String = ConfigurationSettings.AppSettings("connectionstring")
{{Bladeren2
|Boek=Programmeren in ASP.NET
|vorige=Gegevenstoegang
|huidige=Werken met databanken
|volgende=Databankgegevens wijzigen
}}
{{Sub}}
gq1o50yxsrwi3hvx6d6pxoj2ke4j56k
Programmeren in ASP.NET/Databankgegevens wijzigen
0
3685
428835
425774
2026-05-23T12:17:23Z
Erik Baas
2193
lf
428835
wikitext
text/x-wiki
{{Index Programmeren in ASP.NET}}
==SQL-opdrachten uitvoeren==
[[SQL]]-opdrachten die gegevens wijzigen (zoals INSERT INTO, UPDATE of DELETE) geven geen resultaten terug zoals SELECT. De manier om deze opdrachten te gebruiken is dus verschillend.
Gebruik hiervoor het OleDbCommand-object, en roep hiervan de ExecuteNonQuery()-methode aan.
==Gegevens toevoegen==
Deze code voert een "INSERT INTO" opdracht uit:
{{Code
|
|Taal=ASP.NET
|Titel="INSERT INTO"
|Code=
<pre>Dim strConn As String = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=c:\test.mdb"
Dim cn As new OleDbConnection(strConn)
Dim strSQL As String="INSERT INTO AdresTabel (Naam,Voornaam) VALUES ('Smet','Jan');"
Dim cm As New OleDbCommand(strSQL, cn)
Try
cn.Open()
cm.ExecuteNonQuery()
'Naam werd toegevoegd
Catch ex As Exception
Trace.Warn(ex.Message)
Finally
cn.Close()
End Try</pre>
}}
'''Opmerkingen:'''
#Als je bij een Access-databank de foutmelding "Operation must use an updateable query" krijgt, dan betekent dit dat de gebruiker ASPNET (Windows 2000, XP) of NETWORK SERVICE (Windows 2003) op de server niet voldoende rechten bezit op het Access-bestand. Deze gebruiker moet het recht hebben om het Access-bestand te wijzigen.
#In SQL Server moet de gebruiker het INSERT-recht hebben voor de tabel in kwestie.
#De methode ExecuteNonQuery() geeft als return-waarde een Integer terug met het aantal records dat aangepast werd. Je kan die waarde gebruiken om te testen of het bijwerken gelukt is:
Dim aantal As Integer = cm.ExecuteNonQuery()
If(aantal>0) Then ' het is gelukt
==Parameters gebruiken bij het bijwerken==
In de bovenstaande code zal je meestal de naam en de voornaam niet op voorhand kennen. Deze gegevens komen bijvoorbeeld uit een formulier dat de gebruiker ingevuld heeft.
Je moet hier dus weer met parameters werken in het Command-object.
<pre>Dim strConn As String = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=c:\test.mdb"
Dim cn As new OleDbConnection(strConn)
Dim strSQL As String = _
"INSERT INTO AdresTabel (Naam, Voornaam) VALUES (@Naam,@Voornaam);"
Try
cn.Open()
Dim cm As New OleDbCommand(strSQL, cn)
cm.Parameters.AddWithValue("@Naam",Naamvak.Text)
cm.Parameters.AddWithValue("@Voornaam",Voornaamvak.Text)
cm.ExecuteNonQuery()
'Naam werd toegevoegd"
Catch ex As Exception
Trace.Warn(ex.Message)
Finally
cn.Close()
End Try</pre>
'''Opmerkingen:'''
*In de SQL-streng vervang je de variabelen (de parameters) door woorden die beginnen met een apenstaart:
INSERT INTO AdresTabel (Naam, Voornaam) VALUES (@Naam,@Voornaam);"
*Je voegt de echte waarden van de parameters toe met de opdrachten:
cm.Parameters.AddWithValue("@Naam",Naamvak.Text)
cm.Parameters.AddWithValue("@Voornaam",Voornaamvak.Text)
*Let goed op: in OleDb moeten de parameters toegevoegd worden in dezelfde volgorde waarin ze in de SQL-streng voorkomen, dus eerst de naam, dan de voornaam. Zelfs als je duidelijk dezelfde aanduiding @Naam gebruikt, zal dit geen enkel effect hebben. Deze aanduiding wordt gewoon genegeerd, het is alleen de volgorde die telt. De aanduiding heeft alleen nut voor jou als programmeur om het iets overzichtelijker te maken.
*Natuurlijk moeten er ook evenveel parameters toegevoegd worden als er vraagtekens zijn. Anders krijg je de foutmelding: "No value given for one or more required parameters".
*Zorg ervoor dat de waarde van een parameter nooit Nothing kan zijn. Anders krijg je de foutmelding: "Parameter @x has no default value".
===Oefeningen===
#Maak een formulier "invoer.htm" om adressen in te voeren. Stuur de gegevens naar een tweede pagina "verwerk.aspx". Voeg het ingevoerde adres toe aan de databank. Merk op dat het formulier zelf geen ASP-code bevat (alleen HTML).
#Zelfde oefening, maar zet nu het formulier en de verwerking in één enkele (aspx-)pagina.
#Maak een formulier om verjaardagen toe te voegen aan een databank met een "verjaarkalender".
#Schrijf een script dat alle records van een tabel in Access kopieert naar een gelijkaardige tabel in SQL Server.
==Gegevens bijwerken==
De code hieronder voert een "UPDATE"-opdracht uit. Merk op dat je ook hier voor de WHERE-clause een parameter gebruikt.
<pre>Dim strConn As String = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=c:\test.mdb"
Dim cn As new OleDbConnection(strConn)
Dim strSQL As String="UPDATE AdresTabel Set Naam=@Naam WHERE ID=@ID;"
Dim cm As New OleDbCommand(strSQL, cn)
cm.Parameters.AddWithValue("@Naam",strNieuweNaam)
cm.Parameters.AddWithValue("@ID",id)
Try
cn.Open()
cm.ExecuteNonQuery()
'Naam werd bijgewerkt
Catch ex As Exception
Trace.Warn(ex.Message)
Finally
cn.Close()
End Try</pre>
Bij een UPDATE-commando kan het gebeuren dat je geen foutmelding krijgt, maar dat er toch niets bijgewerkt wordt. Meestal komt dit doordat de WHERE-conditie verkeerd geschreven is, zodat er geen enkel record aan voldoet.
==Gegevens verwijderen ==
De code voert een "DELETE" opdracht uit. Je gebruikt een parameter om op te geven welk record je wil verwijderen.
<pre>Dim strConn As String = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=c:\test.mdb"
Dim cn As new OleDbConnection(strConn)
Dim strSQL As String="DELETE FROM AdresTabel WHERE ID=@ID;"
Dim cm As New OleDbCommand(strSQL, cn)
cm.Parameters.AddWithValue("@ID",id) ' id is de ID van het record dat weg moet
Try
cn.Open()
cm.ExecuteNonQuery()
'record werd verwijderd
Catch ex As Exception
Trace.Warn(ex.Message)
Finally
cn.Close()
End Try</pre>
===Oefening===
#Breid de toepassing met de wachtwoorden-databank uit, zodat een gebruiker ook zijn of haar wachtwoord kan wijzigen
==Opgeslagen procedures uitvoeren==
Opgeslagen procedures of stored procedures (bijvoorbeeld in SQL Server) kan je uitvoeren net alsof je een query uitvoert. Je moet alleen de CommandType-property van het SqlCommand-object instellen op StoredProcecure:
<pre>Dim strConn As String = "Server=(local);trusted_connection=true;Database=Adressen"
Dim cn As New SqlConnection(strConn)
Try
cn.Open()
Dim strSQL As String = "sp_MijnStoredProcedure"
Dim cm As New SqlCommand(strSQL, cn)
cm.CommandType = CommandType.StoredProcedure
cm.ExecuteNonQuery()
'procedure werd uitgevoerd
Catch ex As Exception
Trace.Warn(ex.Message)
Finally
cn.Close()
End Try</pre>
Je kan ook parameters toevoegen, net zoals bij een gewone query.
{{Bladeren2
|Boek=Programmeren in ASP.NET
|vorige=Werken met databanken
|huidige=Databankgegevens wijzigen
|volgende=Werken met datacontrols
}}
{{Sub}}
t38stcepq5oy7r1gez6l9nf0t1mw754
Programmeren in ASP.NET/Werken met datacontrols
0
3686
428833
425778
2026-05-23T12:17:20Z
Erik Baas
2193
lf
428833
wikitext
text/x-wiki
{{Index Programmeren in ASP.NET}}
==Datacontrols==
In ASP.NET zijn er zes controls die speciaal gemaakt zijn voor het tonen van gegevens uit databanken:
{| class="wikitable"
|-
!Control!!Beschrijving
|-
|Repeater||Beperkte control, vooral voor het simpel weergeven van gegevens
|-
|DataList||Toont gegevens als een lijst, met uitgebreide mogelijkheden voor opmaak en verwerking
|-
|DataGrid||Toont gegevens als een tabel (overeenkomend met de database-tabel of -query), met uitgebreide mogelijkheden voor opmaak, verwerking, sorteren, en paginering. Een datagrid kan zonder enige code een HTML-tabel produceren vanuit een database-tabel, maar als je wil kan je ook alles zelf controleren.
|-
|[[Programmeren in ASP.NET/GridView|GridView]]||Dit is de opvolger van de DataGrid in ASP.NET 2.0. De GridView heeft nog meer mogelijkheden dan de DataGrid: gegevens wijzigen zonder code, sorteren en pagineren zonder postback van de ganse pagina
|-
|FormView||Nieuwe control in ASP.NET 2.0, bedoeld om een invulformulier te koppelen aan één record uit een tabel.
|-
|DetailsView||Nieuwe control in ASP.NET 2.0, speciaal bedoeld om de details te tonen van één enkel record uit een tabel.
|}
Deze controls hebben al een hoop functionaliteit ingebouwd, waardoor veel taken erg simpel worden.
==Repeater==
===Databinding met een Repeater-control===
De Repeater is de eenvoudigste datacontrol. Een Repeater is ideaal als de gegevens alleen moeten weergegeven worden.
Hier is een voorbeeld:
''repeater.aspx''
<pre><%@ Page Language="VB" %>
<html>
<head>
<title>Repeater</title>
</head>
<body>
<form id="form1" runat="server">
<asp:Repeater ID="Repeater1" runat="server"
DataSourceID="AccessDataSource1">
<ItemTemplate>
<%# Eval("Naam") %> <%# Eval("Voornaam") %><br>
</ItemTemplate>
</asp:Repeater>
<asp:AccessDataSource ID="AccessDataSource1" runat="server"
DataFile="~/App_Data/Adressen.mdb"
SelectCommand="SELECT * FROM [AdresTabel]"></asp:AccessDataSource>
</form>
</body>
</html></pre>
Wat gebeurt er in deze pagina?
*tijdens het Page_PreRender-event worden de gegevens uit de databank gehaald door de DataSource-control, en deze wordt met databinding gekoppeld aan de repeater.
*De gegevens worden in de Repeater getoond met behulp van de speciale databindingsyntax <%# Eval("Naam") %>. Op de plaats van deze tag komt de waarde uit de databank te staan.
*Deze gegevens staan binnen een <ItemTemplate>-tag.
Merk op dat alle code en HTML weer gescheiden zijn. Alleen de databinding-resultaten staan nog in de HTML-sectie met de syntax (met het hekje).
'''Opmerking'''<br>
Je kan gegevens zoals getallen en datums formatteren met deze syntax:
<%# Eval("GeboorteDatum","{0:d}") %>
(in dit voorbeeld krijg je een korte datum zonder het uur).
Zie [https://msdn.microsoft.com/library/en-us/cpguide/html/cpconformattingtypes.asp] voor de verschillende formatteringscodes.
==Syntax voor data-binding==
Met ASP.NET is er een nieuw soort syntax voor het inbrengen van gegevens in de HTML-sectie van een document via data-binding. Deze syntax gebruikt het hekje: <%#...%>
Hier zijn enkele voorbeelden:
{| class="wikitable"
|-
|Gewone property||Klant: <%# klantID %>
|-
|Collection||Bestellingen: <asp:ListBox id="L1" datasource='<%# myArray %>' runat="server">
|-
|Expressie||Contact: <%# ( klant.Voornaam & " " & klant.Naam ) %>
|-
|Resultaat van een methode||Saldo: <%# GetSaldo(klantID) %>
|-
|Veld van een datacontrol||<%# Eval("Naam") %>
|}
Deze syntax lijkt erg op de korte ASP-syntax voor renderblokken (<%= %>), maar het gedrag is toch heel anders. Terwijl de renderblokken worden geëvalueerd op het moment dat de pagina verwerkt wordt, zal de ASP.NET-databindingsyntax alleen geëvalueerd worden wanneer de DataBind()-methode aangeroepen wordt.
DataBind() is een methode van Page en van alle server-controls. In ASP.NET 2.0 hoef je deze methode niet zelf aan te roepen als de datacontrol gekoppeld is aan een DataSource-control (AccessDataSource of SQLDataSource). De methode wordt vanzelf uitgevoerd tijdens Page_Load of Page_PreRender.
Als je DataBind() oproept voor een bepaalde control, dan wordt dit ook doorgegeven aan alle kinderen van die control. Zo zal DataList1.DataBind() de DataBind()-methode oproepen voor elke control in de DataList-templates (meer over de DataList-control in de paragrafen hieronder). Het oproepen van DataBind() op de pagina – Page.DataBind() of gewoon DataBind() – zorgt ervoor dat alle databinding-expressies op de pagina geëvalueerd worden.
DataBind() wordt gewoonlijk opgeroepen in twee gevallen:
#vanuit het Page_Load-event of Page_Prerender-event
#nadat de gegevens gewijzigd werden (bijvoorbeeld omdat je updates gedaan hebt)
'''Opmerkingen:'''
*De databinding-expressie zoals in de voorbeelden hierboven moet als resultaat een waarde van het type String geven. Indien nodig moet je zelf de omzetting doen. Bijvoorbeeld, als datum een datum is:
Aantal records: <%# datum.ToShortDateString() %>
*Je mag code die moet uitgevoerd worden niet in dit blok plaatsen (zoals assignments, voorwaarden of lussen). Alleen specifieke databindingexpressies die een resultaat teruggeven mogen binnen dit blok gebruikt worden. Functies die een waarde teruggeven mogen dus wel.
*In de praktijk haal je de gegevens voor een datacontrol meestal uit een databank, maar in feite kunnen deze controls ook hun gegevens krijgen van een gewone array. Het principe wordt getoond in de volgende code:
Repeater1.DataSource = New Integer() {1, 2, 3, 4, 5}
Repeater1.DataBind()
*Als je als datasource een <code>XmlDataSource</code> gebruikt, dan vervang je Eval door XPath:
<%# XPath("adres") %>
===Zoeken met een Repeater===
Soms wil je alleen maar de adressen uit een bepaalde gemeente laten zien. De gebruiker kan deze gemeente invullen in een tekstvak tbGemeente.
Om dit te bekomen moet je een WHERE-conditie opnemen in de datasource. Dit kan je doen via de wizard. We deden dit vroeger ook al bij [[Programmeren_in_ASP.NET/Gegevenstoegang#Parameters_gebruiken_2|lijsten met parameters]]. Stel de WHERE-conditie zo in dat het veld Gemeente moet overeenkomen met de waarde in de control tbGemeente (het tekstvak). Automatisch wordt deze tekst dan als parameter gebruikt bij het opvragen van de gegevens.
Je kan zelfs meer dan één WHERE-conditie gebruiken als je wil.
===Oefeningen===
#Breid de pagina repeater.aspx uit met een zoekfunctie: laat de gebruiker een gemeente ingeven, en toon alleen de adressen uit die gemeente.
#Maak een pagina waar je de gemeentes kan opzoeken met een bepaalde postcode.
#Zorg ervoor dat de tabel ook een veld met het e-mailadres bevat. Toon het e-mailadres met de repeater, maar zodanig dat je er kan op klikken (met mailto:).
#Maak een tabel met gebeurtenissen en datums. Maak een pagina met 2 Calendar-controls, waar alle gebeurtenissen tussen die 2 datums getoond worden.
==Templates gebruiken==
De repeater heeft in totaal 5 templates om gegevens te tonen. (De DataList en de DataGrid hebben nog 2 extra templates, zie verder)
*Het '''ItemTemplate''' wordt getoond voor elke rij in de data-source van de repeater.
*Het '''AlternatingItemTemplate''' wordt getoond voor alle even rijen. Hiermee kan je bijvoorbeeld kleuren laten wisselen voor elke rij. Indien dit template ontbreekt, dan wordt voor alle items het ItemTemplate gebruikt.
*Het '''HeaderTemplate''' wordt eenmaal getoond bovenaan de control. Je kan deze template gebruiken om titels te tonen.
*Het '''SeparatorTemplate''' wordt getoond tussen de rijen. Als er maar 1 record is, wordt het niet getoond.
*Het '''FooterTemplate''' wordt eenmaal getoond onderaan de control. Soms kan je hier bijvoorbeeld totalen tonen.
Alleen het ItemTemplate is altijd verplicht. De andere zijn optioneel.
Je kan alleen databinding uitvoeren in het ItemTemplate en het AlternatingItemTemplate.
Binnen elk van deze templates kan je verder eender welke HTML-tags gebruiken, en ook HTML-controls en servercontrols zijn toegelaten.
'''Enkele voorbeelden:'''
Met een Label-control:
<pre><ItemTemplate>
<asp:Label Text='<%# Eval("Naam") %>' runat="server"> </asp:Label><br>
</ItemTemplate></pre>
In de vorm van een tabel:
<pre><ItemTemplate>
<table width="100%">
<tr>
<td width="50%"> <%# Eval("Naam") %> </td>
<td width="50%"> <%# Eval("Voornaam") %> </td>
</tr>
</table>
</ItemTemplate></pre>
Met een alternerende kleur:
<pre><ItemTemplate>
<%# Eval("Naam") %> <%# Eval("Voornaam") %><br>
</ItemTemplate>
<AlternatingItemTemplate>
<span style="color: red;">
<%# Eval("Naam") %> <%# Eval("Voornaam") %><br>
</span>
</AlternatingItemTemplate></pre>
Met een hyperlink:
<asp:Hyperlink Text='<%# Eval("url") %>' NavigateUrl='<%# Eval("url") %>' runat="server" />
==DataList==
===Gegevens ophalen met een DataList-control===
Een tweede veelgebruikte control is de datalist-control. Deze control kan alles wat de Repeater kan, maar bovendien kan je met een DataList gegevens selecteren, wijzigen, verdelen in meerdere kolommen, enz.
In het eerste voorbeeld hieronder wordt een datalist-control gebruikt voor het tonen van gegevens alleen. Bij het aanmaken van de databankconnectie met de wizard wordt voor elk veld automatisch een label toegevoegd aan het ItemTemplate.
Bij een datalist kan je templates toevoegen door in de smart tag "Edit templates" te kiezen. Sleep een Label-control op het ItemTemplate en kies in de smart tag van het Label dan weer "Edit Databindings". Klik op "Refresh Schema" als de lijst met velden grijs is. Je kan ook een "custom binding" instellen voor de Text-property met deze waarde: Eval("Naam"). Merk op dat je ook andere eigenschappen van het label kan instellen met databinding.
''datalist.aspx''
<pre><%@ Page Language="VB" %>
<html>
<head>
<title>Datalist</title>
</head>
<body>
<form id="form1" runat="server">
<asp:DataList ID="DataList1" runat="server" DataSourceID="AccessDataSource1">
<ItemTemplate>
<asp:Label ID="Label1" runat="server" Text='<%# Eval("Naam") %>' / >
</ItemTemplate>
</asp:DataList>
<asp:AccessDataSource ID="AccessDataSource1" runat="server"
DataFile="~/App_Data/Adressen.mdb"
SelectCommand="SELECT * FROM [AdresTabel]"></asp:AccessDataSource>
</form>
</body>
</html></pre>
'''Opmerkingen:'''
*Een datalist heeft veel meer mogelijkheden dan een repeater. Enkele worden in de volgende paragrafen besproken.
*In tegenstelling tot de repeater laat de datalist-control toe dat je de verschillende templates rechtstreeks kan aanpassen in Visual Studio. Je doet dit door rechts te klikken op de datalist en te kiezen voor "Edit templates...".
*Ook het "Property Builder"-venster bevat uitgebreide opties om op een eenvoudige manier de datalist in te stellen.
*Als je de opmaak wilt aanpassen, selecteer dan de DataList component in Visual Studio, en klik op de "Auto Format..."-link in de Smart Tag opties.
===DataList met een alternerende kleur===
Net zoals bij een repeater kan je een alternerende opmaak kiezen voor elk tweede item in de lijst. Bij een DataList echter is het dikwijls voldoende een AlternatingItemStyle toe te voegen, zoals in het voorbeeld hieronder, waar de achtergrondkleur gewijzigd werd:
'''datalistalt.aspx (fragment)'''
<pre><asp:DataList id="DataList1" runat="server">
<ItemTemplate>
<asp:Label id="Label1" Text='<%# Eval("Naam") %>' runat="server">
</asp:Label>
</ItemTemplate>
<AlternatingItemStyle backcolor="#FFE0C0" />
</asp:DataList></pre>
In Visual Studio selecteer je hiervoor de DataList, en je wijzigt de property AlternatingItemStyle in het property-paneel.
Je hoeft hier dus geen AlternatingItemTemplate te maken, waar je (zoals bij de repeater hierboven) dezelfde code van het ItemTemplate grotendeels moet herhalen. Alleen de opmaak ("Style") wordt hier aangepast.
Het ene sluit echter het andere niet uit: je kan ze ook samen gebruiken.
'''Tip:''' het is nog beter als je de kleur kan instellen met behulp van een stylesheet.
Maak bijvoorbeeld een stijlklasse "altstyle" met de juiste instellingen, en gebruik de CssClass-property:
<AlternatingItemStyle CssClass="altstyle"></AlternatingItemStyle>
===Meerdere kolommen gebruiken in een DataList-control===
Door de property RepeatColumns van de DataList in te stellen op 2 i.p.v. 0 wordt de lijst gespreid over twee kolommen op je pagina.
Alleen de DataList-control heeft deze mogelijkheid.
Andere property's RepeatDirection en RepeatLayout geven je nog extra opties.
===Gegevens selecteren met een DataList-control===
De DataList-control biedt de mogelijkheid om één item te selecteren uit de lijst. Dit item krijgt dan een eigen opmaak via de SelectedItemStyle. Bovendien kan je het SelectedItemTemplate gebruiken om van dit item bijvoorbeeld meer informatie te tonen dan van de andere.
''datalistselect.aspx''
<pre><%@ Page Language="VB" %>
<script runat="server">
Protected Sub DataList1_SelectedIndexChanged(ByVal sender As Object, _
ByVal e As System.EventArgs)
DataList1.DataBind()
End Sub
</script>
<html>
<head>
<title>Datalist</title>
</head>
<body>
<form id="form1" runat="server">
<asp:DataList ID="DataList1" runat="server" DataSourceID="AccessDataSource1"
OnSelectedIndexChanged="DataList1_SelectedIndexChanged">
<ItemTemplate>
<asp:Label ID="Label1" runat="server" Text='<%# Eval("Naam") %>' />
<asp:LinkButton ID="btnSelecteer" CommandName="Select"
runat="server" Text="Selecteer" />
</ItemTemplate>
<SelectedItemStyle BackColor="#C04000" />
<SelectedItemTemplate>
<%# Eval("Naam") %> <%# Eval("Voornaam") %>
</SelectedItemTemplate>
</asp:DataList>
<asp:AccessDataSource ID="AccessDataSource1" runat="server"
DataFile="~/App_Data/Adressen.mdb"
SelectCommand="SELECT * FROM [AdresTabel]"></asp:AccessDataSource>
</form>
</body>
</html></pre>
'''Opmerkingen:'''
*Het ItemTemplate hierboven bevat alleen een label met de naam, het SelectedItemTemplate bevat ook de voornaam.
*Om een item te kunnen selecteren, werd een LinkButton toegevoegd aan het ItemTemplate.
Belangrijk is dat de property CommandName van deze LinkButton ingesteld werd op "Select". Hierdoor zal het klikken op deze LinkButton er automatisch voor zorgen dat de SelectedItemIndex van de DataList ingesteld wordt op het betreffende item.
*Alleen het instellen van de SelectedItemIndex is niet voldoende. De ganse DataList moet immers hertekend worden, en daarvoor moet de DataBind()-methode aangeroepen worden. Dit doe je in het SelectedIndexChanged event van de DataList, dat je moet toevoegen.
====Oefeningen====
#Verander deze pagina zo dat je de naam en de voornaam altijd ziet, maar bij het klikken op "Selecteer" krijg je het ganse adres en het telefoonnummer erbij. Zorg er ook voor dat alle "Selecteer" links netjes onder mekaar staan.
#Zelfde oefening, maar voeg ook een alternerende kleur toe.
#Zelfde oefening, maar voeg nu twee knoppen toe ("vorige" en "volgende"), waarmee je het geselecteerde item instelt.
===Gegevens wijzigen met een DataList-control===
Ook voor het wijzigen van gegevens heeft de DataList mogelijkheden ingebouwd.
Hiervoor is er ook weer een aangepast template: het EditItemTemplate. Typisch zal je in dit template invoervakken (of aankruisvakjes of andere controls) voorzien, zodat de gebruiker de gegevens kan wijzigen.
''datalistedit.aspx''
<pre><%@ Page Language="VB" %>
<%@ import Namespace="System.Data" %>
<%@ import Namespace="System.Data.OleDb" %>
<script runat="server">
Sub DataList1_EditCommand(ByVal sender As Object, ByVal e As _
DataListCommandEventArgs)
DataList1.EditItemIndex = e.Item.ItemIndex
DataList1.DataBind()
End Sub
Sub DataList1_UpdateCommand(ByVal sender As Object, ByVal e As _
DataListCommandEventArgs)
Dim strConn As String = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & _
Server.MapPath("App_Data\adressen.mdb")
Dim naam As String = CType(e.Item.FindControl("tbNaam"), TextBox).Text
Dim id As Integer = DataList1.DataKeys(e.Item.ItemIndex)
Dim cn As New OleDbConnection(strConn)
Dim strSQL As String = "UPDATE Adrestabel SET naam = @naam WHERE id = @id"
Dim cm As New OleDbCommand(strSQL, cn)
cm.Parameters.AddWithValue("@naam", naam)
cm.Parameters.AddWithValue("@id", id)
Try
cn.Open()
cm.ExecuteNonQuery()
Catch ex As Exception
Trace.Warn(ex.Message)
Finally
cn.Close()
End Try
DataList1.EditItemIndex = -1
DataList1.DataBind()
End Sub
Sub DataList1_CancelCommand(sender As Object, e As DataListCommandEventArgs)
DataList1.EditItemIndex = -1
DataList1.DataBind()
End Sub
</script>
<html>
<head>
<title>DataList met wijzigen</title>
</head>
<body>
<form id="Form1" runat="server">
<asp:DataList id="DataList1" runat="server"
DataSourceID="AccessDataSource1"
OnEditCommand="DataList1_EditCommand"
OnUpdateCommand="DataList1_UpdateCommand"
DataKeyField="ID" OnCancelCommand="DataList1_CancelCommand">
<ItemTemplate>
<%# Eval("Naam") %>
<asp:LinkButton id="btnWijzigen" runat="server" Text="wijzigen"
CommandName="Edit"></asp:Button>
</ItemTemplate>
<EditItemTemplate>
Naam:
<asp:TextBox id="tbNaam" text='<%# Eval("Naam") %>'
runat="server"></asp:TextBox>
<asp:LinkButton id="btnBijwerken" runat="server" Text="bijwerken"
CommandName="Update"></asp:Button>
<asp:LinkButton id="btnAnnuleren" runat="server" Text="annuleren"
CommandName="Cancel"></asp:Button>
</EditItemTemplate>
</asp:DataList>
<asp:AccessDataSource ID="AccessDataSource1" runat="server"
DataFile="~/App_Data/Adressen.mdb"
SelectCommand="SELECT * FROM [AdresTabel]"></asp:AccessDataSource>
</form>
</body>
</html></pre>
'''Opmerkingen:'''
*In de plaats van de selecteerlink is er nu in het ItemTemplate een knop (het mocht evengoed weer een linkbutton zijn) voor het aanpassen van de gegevens. Deze knop krijgt de eigenschap CommandName="Edit".
*Bij het klikken op deze knop wordt het EditCommand-event van de DataList afgevuurd. Zorg voor een afhandeling van dit event (hierboven de DataList1_EditCommand handler). Je moet hierin 2 dingen doen:
*#stel de EditItemIndex in van de DataList. Om te weten welke de index is gebruik je de eigenschappen van de DataListCommandEventArgs parameter e die met dit event meegegeven wordt: DataList1.EditItemIndex=e.Item.ItemIndex
*#voer databinding uit om de DataList opnieuw op te bouwen.
*Bekijk het EditItemTemplate hierboven. Het label voor de naam uit het ItemTemplate is hier vervangen door een invoervak.
*Er is ook een knop voorzien om de wijzigingen door te voeren. Deze knop krijgt de eigenschap CommandName="Update".
*Bij het klikken op deze knop wordt het UpdateCommand event van de DataList afgevuurd. Zorg voor een afhandeling van dit event (hierboven de DataList1_UpdateCommand handler). Hierin moet je de nieuwe gegevens naar de databank sturen, en de DataList hertekenen.
*De nieuw ingevoerde naam krijg je via CType(e.Item.FindControl("tbNaam"), TextBox).Text. Aangezien elk item in de DataList een vak TextBox1 bevat, kan je niet gewoon tbNaam.Text gebruiken. Met de FindControl()-methode kan je binnen een bepaalde control (in dit geval het DataListItem) zoeken naar een andere control met een bepaald ID. CType zet e.Item.FindControl("tbNaam") (een Control-object) om in een TextBox-object. Dit noemt men een cast. Zonder CType zou je de property Text niet kunnen opvragen, want het Control-object zelf heeft geen Text-property.
*Het ID van het gewijzigde item krijg je via DataList1.DataKeys(e.Item.ItemIndex)
*Opdat dit laatste zou werken, moet je de eigenschap DataKeyField van de DataList instellen op "ID".
*Tenslotte is er in het EditItemTemplate ook nog een knop "Annuleren". Deze knop heeft de eigenschap CommandName="Cancel", en bij het klikken erop wordt het CancelCommand afgevuurd. Hierin moet je DataList1.EditItemIndex instellen op –1, en vervolgens de DataList weer binden.
====Oefening====
*Maak een databank met een tabel met gegevens over computers (Naam, Merk, Processor, Geheugen, Hardeschijf). Maak een pagina om die tabel te wijzigen.
===Gegevens verwijderen met een DataList-control===
Naast een "update"-knop kan je ook een "delete"-knop voorzien. Deze knop moet de instelling CommandName="Delete" hebben. Probeer dit zelf uit, en voorzie het gepaste event om het record te verwijderen.
'''Tip:''' het is meestal een goed idee om hiervoor bevestiging van de gebruiker te vragen. Anders worden soms gegevens per ongeluk gewist.
====Oefeningen====
#Maak een datalist waar je adressen kan wijzigen.
#Zelfde oefening, maar je kan ook adressen toevoegen.
#Zelfde oefening, maar je kan ook adressen verwijderen.
===OnItemDataBound===
Stel dat je de aandacht van de gebruiker op bepaalde rijen in de lijst wil vestigen, bijvoorbeeld als een bedrag negatief is.
De datacontrols (dus ook de repeater) hebben een event dat uitgevoerd wordt voor elk item in de lijst: het ItemDataBound-event.
Dit event treedt op net voor het item toegevoegd wordt aan de control. Je kan op dat moment nog wijzigingen aanbrengen als je dat wilt.
Het ItemDataBound-event krijgt als tweede parameter (e) een object van het type DataListItemEventArgs. Dit kan je gebruiken in je code om toegang te krijgen tot het item:
*'''<code>e.Item</code>''' is het DataListItem. Dit is de rij van de DataList waarop alles wat in het template staat geplaatst wordt. Dit is een control die alle eigenschappen van een cel in een html-tabel heeft, zoals achtergrondkleur, rand, enz...
*'''<code>e.Item.ItemType</code>''' is het type van het item. Hiermee kan je controleren of het een gewoon item is, een alternating item, een geselecteerd item, een edit item, een headeritem of een footeritem.
*'''<code>e.Item.ItemIndex</code>''' is de index van het item, te beginnen vanaf 0. Dit geldt alleen voor gewone items en alternating items.
*'''<code>e.Item.DataItem</code>''' is een object dat overeenkomt met de rij uit de databank waarmee het item overeenstemt.
*'''<code>DataBinder.Eval(e.Item.DataItem,"naamveld")</code>''' geeft de waarde van het opgegeven veld in de databank voor het item.
*Om toegang te krijgen tot een bepaalde control binnen een template, kan je '''<code>e.Item.FindControl("IDControl")</code>''' gebruiken. IDControl is daarin de ID van de control binnen het template.
In de pagina hieronder worden adressen in Brussel getoond met een rode achtergrond.
''datalistdatabound.aspx (fragment)''
<pre>Sub DataList1_ItemDataBound(sender As Object, e As DataListItemEventArgs)
If e.Item.ItemType = ListItemType.Item Or _
e.Item.ItemType = ListItemType.AlternatingItem Then
Dim gemeente As String = DataBinder.Eval(e.Item.DataItem, "Gemeente")
If(gemeente="Brussel") Then
e.Item.BackColor = System.Drawing.Color.Red
End If
End If
End Sub</pre>
Merk op dat er een test nodig is om te controleren over welk template het gaat. Alleen voor het ItemTemplate en AlternatingItemTemplate wordt de code uitgevoerd. Voor andere templates zou de code fouten geven (het HeaderTemplate heeft bijvoorbeeld geen DataItem), dus dat moet vermeden worden.
====Oefeningen====
#Je kan het ItemDataBound-event ook gebruiken om allerlei code uit te voeren voor alle items in de lijst. Maak een DataList "Computers". Sommige velden geven als resultaat True/False. Vervang dit door Ja/Neen.
#Hierboven werd opgemerkt dat je voor het verwijderen van gegevens best bevestiging vraagt. Dit kan het best door een stukje JavaScript-code toe te voegen aan het client-side onclick-event van de Delete-knop. Dit doe je met <code> btnDelete.Attributes.Add("onclick","return confirm('Ben je zeker?');").</code> Omdat elk item zijn eigen btnDelete heeft, moet je deze code in OnItemDataBound zetten. Breid oefening 3 van de vorige reeks uit met deze beveiliging.
#Maak een DataList "cd's" met in het SelectedItemTemplate een Repeater-control. Deze repeater toont alle nummers van de betreffende cd. Gebruik het ItemDataBound event van de DataList om de repeater te vullen met gegevens. Zorg ervoor dat dit alleen gebeurt in het SelectedItemTemplate.
#Zelfde oefening, maar gebruik nu een DataList in plaats van een Repeater. Je krijgt dus een DataList binnen een DataList (geneste DataList).
===Eigen commando's maken===
Je kan de CommandName-property van een knop binnen een DataList instellen op de reeds genoemde commando's: "Select", "Edit", "Update", "Delete" en "Cancel". Deze commando's hebben een voorgeprogrammeerde betekenis in ASP.NET.
Je kan ook zelf je eigen commando's toevoegen.
Je kan bijvoorbeeld een knop toevoegen met commando's zoals CommandName="Controleren" of CommandName="Volgende".
De voorgeprogrammeerde commando's hebben elk hun eigen event-handler.
Om je eigen commando's te verwerken gebruik je de algemene handler OnItemCommand. Je moet dan testen welk commando precies de handler veroorzaakt. Dit kan je achterhalen met behulp van e.CommandName (e is de tweede parameter van OnItemCommand).
Gebruik de volgende code:
<pre>Sub DataList1_ItemCommand(sender As Object, e As DataListCommandEventArgs)
If(e.CommandName="Controleren") Then
... de code indien "Controleren" gekozen werd ...
End If
End Sub</pre>
====Oefening====
#Maak een DataList met adressen. Zorg ervoor dat het ItemTemplate leeg is, terwijl het SelectedItemTemplate wel gegevens toont. Begin met het eerste item geselecteerd, zodat je alleen het eerste adres op het scherm krijgt. Voeg nu een knop "Volgende" toe aan het SelectedItemTemplate. Als je op de knop klikt, krijg je het volgende adres uit de databank.
===Memo-velden en regeleindes===
In sommige databankvelden kan tekst ingevoerd worden die regeleindes bevat (carriage returns). In Access bijvoorbeeld gebruik je daarvoor een Memo-veld.
Er ontstaat nu een probleem bij de weergave van deze velden in een html-pagina. Dit komt omdat de browser regeleindes beschouwt als open ruimte, en die worden gewoon weergegeven als een spatie.
In feite komt het erop neer dat je als ontwikkelaar bij de weergave van een memo-veld alle regeleindes moet omzetten in<br>-tags.
Hiervoor gebruik je de volgende functie (een zogenaamde helper-functie):
<pre>Function VoegBreaksToe(str As String) As String
return str.Replace(vbCrLf,"<br>")
End Function</pre>
In je datalist bijvoorbeeld roep je deze functie op de volgende manier aan:
<pre><asp:Label runat="server">
<%# VoegBreaksToe(Eval("mijnmemoveld")%>
</asp:Label></pre>
==DataGrid==
De derde veelgebruikte control is de DataGrid-control. Hiermee kan je gegevens vanaf een databank (maar ook vanaf andere bronnen) tonen in de vorm van een tabel. Een voordeel van de DataGrid-control is dat hij al gegevens kan tonen zonder één enkel template.
Deze control kan in ASP.NET 2.0 beter vervangen worden door een [[Programmeren in ASP.NET/GridView|GridView]]-control, die veel krachtiger is. In Visual Studio 2005 vind je de DataGrid zelfs niet meer op de toolbox.
We bespreken de DataGrid hier kort voor pagina's die nog in ASP.NET 1.x gemaakt zijn. Dit is de code voor alleen het weergeven van de data in ASP.NET 1.x:
===Gegevens ophalen met een DataGrid-control===
''datagrid.aspx''
<pre><%@ Page Language="VB" %>
<%@ import Namespace="System.Data" %>
<%@ import Namespace="System.Data.OleDB" %>
<script runat="server">
Dim strConn As String = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & _
Server.MapPath("App_Data\adressen.mdb")
Dim strSQL As String = "SELECT * FROM AdresTabel"
Sub Page_Load(Sender As Object, E As EventArgs)
If Not Page.IsPostBack Then
BindGrid()
End If
End Sub
Sub BindGrid()
Dim cn As New OleDBConnection(strConn)
Try
cn.Open()
Dim cm As New OleDBCommand(strSQL, cn)
DataGrid1.DataSource = cm.ExecuteReader()
DataGrid1.DataBind()
Finally
cn.Close()
End Try
End Sub
</script>
<html>
<head>
<title>Data Grid</title>
</head>
<body>
<form runat="server">
<asp:datagrid id="DataGrid1" runat="server">
</asp:datagrid>
</form>
</body>
</html></pre>
Merk op dat je nergens namen van velden moet ingeven: de DataGrid maakt volledig automatisch een tabel aan!
===Gegevens wijzigen met een DataGrid-control===
Om gegevens te kunnen wijzigen moet je de datasource control aanpassen, zodat die ook INSERT, UPDATE en DELETE-commando’s bevat. Dit doe je door in de wizard de knop “Advanced” te gebruiken.
Het wijzigen van gegevens is volledig vergelijkbaar met het wijzigen van gegevens in een DataList, behalve dat de DataGrid ook het EditItemTemplate zelf automatisch kan aanmaken.
In de UpdateCommand event handler moet je te weten komen welke de nieuwe gegevens zijn die de gebruiker ingevuld heeft.
Bij een DataList gebruikte je hiervoor '''<code>e.Item.FindControl("idVanHetTekstvak")</code>'''.
Bij een DataGrid ken je de id's meestal niet (omdat alles automatisch aangemaakt wordt).
Daarom gebruik je een andere methode:
e.Item.Cells(k).Controls(0)
waarbij k het nummer van de kolom is (te beginnen vanaf 0). Controls(0) is de eerste control binnen een cel, en dat is inderdaad het tekstvak in die kolom.
{{Bladeren2
|Boek=Programmeren in ASP.NET
|vorige=Databankgegevens wijzigen
|huidige=Werken met datacontrols
|volgende=GridView
}}
{{Sub}}
chbjnht1rjtcae8nc0jcscep4oew01s
Programmeren in ASP.NET/GridView
0
3791
428826
425780
2026-05-23T12:17:14Z
Erik Baas
2193
lf
428826
wikitext
text/x-wiki
{{Index Programmeren in ASP.NET}}
De '''GridView''' is de opvolger van de [[Programmeren_in_ASP.NET/Werken_met_datacontrols#DataGrid|DataGrid]]-control in ASP.NET 2.0. Hoewel de DataGrid-control nog altijd bestaat in ASP.NET 2.0 is het beter om de GridView-control te gebruiken.
Het voordeel van de GridView-control is dat je in veel gevallen een taak kan verrichten zonder code te schrijven. De GridView-control kan records tonen, sorteren, pagineren en wijzigen zonder de code die je daarvoor nodig had bij de DataGrid.
Daarenboven laat de GridView toe om records te sorteren en pagineren zonder een postback van de hele pagina naar de server.
==De GridView-control gebruiken==
Om te beginnen maak je een nieuwe pagina gridview.aspx.
Vervolgens sleep je een GridView-control (vanuit de "Data"-sectie van de toolbox) op je pagina.
Open nu het Smart Tag-paneel, kies "Choose Data Source…", en vervolgens "<New data source…>". Je krijgt de Datasource Configuration Wizard, net zoals bij het databinden van lijsten.
Kies SQL Data Source, en vervolgens "New connection...". Selecteer de juiste SQL Server databank (bijvoorbeeld "Pubs" op (local) met Windows Integrated Security.
Vervolgens krijg je de optie de connectiestreng te bewaren in het web.config-bestand. Dit gebeurt altijd bij SQL Server-databronnen (niet bij Access).
We zullen dit later gebruiken, voorlopig vinken we dit af.
In de volgende stap moet je het SELECT-statement samenstellen. Kies “SELECT * FROM Publishers”.
Merk op dat je optioneel een DISTINCT-clause (het aankruisvakje "Return only unique rows"), een WHERE-clause en een ORDER BY-clause kan instellen. We zullen die later gebruiken.
Via "Advanced" kan je eventueel de overeenkomstige INSERT-, UPDATE-, en DELETE- commando's genereren. Je hebt deze nodig als je ook [[#Wijzigen met een GridView-control|gegevens wilt wijzigen]].
Als je klaar bent, ziet de HTML-code er ongeveer zo uit:
''gridview.aspx''
<pre><%@ Page Language="VB" %>
<html xmlns="https://www.w3.org/1999/xhtml">
<head runat="server">
<title>GridView</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False"
DataKeyNames="pub_id" DataSourceID="SqlDataSource1">
<Columns>
<asp:BoundField DataField="pub_id" HeaderText="pub_id"
ReadOnly="True" SortExpression="pub_id" />
<asp:BoundField DataField="pub_name" HeaderText="pub_name"
SortExpression="pub_name" />
<asp:BoundField DataField="city" HeaderText="city"
SortExpression="city" />
<asp:BoundField DataField="state" HeaderText="state"
SortExpression="state" />
<asp:BoundField DataField="country" HeaderText="country"
SortExpression="country" />
</Columns>
</asp:GridView>
<asp:SqlDataSource ID="SqlDataSource1" runat="server"
ConnectionString="Data Source=(local);Initial Catalog=pubs;Integrated Security=True"
ProviderName="System.Data.SqlClient"
SelectCommand="SELECT * FROM [publishers]">
</asp:SqlDataSource>
</div>
</form>
</body>
</html></pre>
Merk op dat er weer geen enkele regel code in de pagina staat. De GridView gebruikt de SqlDataSource-control om de records terug te vinden. De GridView-control is verbonden met de SqlDataSource-control via de DataSourceID-property.
===Oefening===
#Maak in Access een tabel met adresgegevens. Maak een pagina die de adressen uit de tabel toont.
==De connectiestring in web.config bewaren==
Als je dezelfde connectie in meerdere pagina's gebruikt, kan je beter kiezen voor de optie om ze in web.config te bewaren. Het voordeel is dan dat je ze later maar op één plaats moet veranderen indien nodig.
In web.config zal deze instelling toegevoegd worden:
<pre><connectionStrings>
<add name="AdressenConnectionString" connectionString="Data Source="(local)";Initial Catalog=Adressen;Integrated Security=True"
providerName="System.Data.SqlClient" />
</connectionStrings></pre>
Merk op dat er hiervoor sinds ASP.NET 2.0 een speciaal element <connectionStrings> bestaat.
In de pagina gebruik je een speciale syntax met een dollarteken om aan te geven dat de variabele uit web.config komt:
<%$ element:variabele %>
In dit geval wordt dit (in de pagina):
<pre><asp:SqlDataSource
ConnectionString="<%$ ConnectionStrings:AdressenConnectionString %>"
ID="SqlDataSource1" runat="server"
SelectCommand="SELECT [ID], [Voornaam], [Naam] FROM [AdresTabel]">
</asp:SqlDataSource></pre>
==Alleen bepaalde velden tonen==
Na het doorlopen van de wizard toont de GridView alle velden die in de datasource voorkomen. Achteraf kan je dit nog veranderen.
In Visual Web Developer kan je de kolommen het gemakkelijkst aanpassen door in het smart tag-menu te klikken op "Edit columns...".
De GridView ondersteunt de volgende veldtypes:
*BoundField – toont gewoon het veld als een string.
*ButtonField – toont een knop.
*CheckboxField – toont een aankruisvak als het veld een boolean is.
*CommandField – genereert een knop voor een commando zoals Edit, Update, of Cancel.
*HyperLinkField – toont een hyperlink.
*ImageField – toont een afbeelding als het veld de url van een afbeelding bevat.
*TemplateField – geeft je volledige controle om zelf de inhoud van de kolom te bepalen.
De GridView hieronder gebruikt twee BoundFields om de namen uit de Employees-tabel te tonen (Northwind-databank).
''gridviewvelden.aspx''
<pre><html>
<head id="Head1" runat="server">
<title>Alleen bepaalde velden tonen</title>
</head>
<body>
<form id="Form1" runat="server">
<asp:GridView ID="GridView1" DataSourceID="ProductsSource"
AutoGenerateColumns="False" Runat="Server" DataKeyNames="EmployeeID">
<Columns>
<asp:BoundField DataField="LastName" HeaderText="LastName"
SortExpression="LastName" />
<asp:BoundField DataField="FirstName" HeaderText="FirstName"
SortExpression="FirstName" />
</Columns>
</asp:GridView>
<asp:SqlDataSource ID="ProductsSource"
ConnectionString="Server=localhost;Database=Northwind;Trusted_Connection=true"
SelectCommand="SELECT [EmployeeID], [LastName], [FirstName] FROM
[Employees]" Runat="Server" ProviderName="System.Data.SqlClient" />
</form>
</body>
</html> </pre>
Merk op dat het BoundField een NullDisplayText-property heeft. Deze bepaalt de tekst die getoond wordt als een kolom een null-waarde bevat.
'''Opmerkingen'''
*Als je een datum toevoegt bij de BoundFields, dan wordt deze getoond als "1/2/2005 0:00:00". Meestal wil je dit laatste deel (de tijd) er niet bij. Daarom kan je bij een BoundField de DataFormatString-property instellen, die gebruikt wordt om de databankgegevens in een stringpatroon te gieten. Zet ook HtmlEncoding=false. Om een datumveld te tonen als een korte datum (dd/mm/yy), gebruik je bijvoorbeeld het patroon {0:d}.
*Je kan ook het <colomns>-element met alle BoundFields compleet verwijderen en AutoGenerateColumns op True zetten. Dan maakt de grid zijn kolommen automatisch aan bij de databinding (maar dan heb je verder geen controle erover).
===Oefeningen===
#Maak opnieuw een pagina die de adressen uit de tabel AdresTabel (databank Adressen) toont. Toon alleen de naam en de voornaam
#Maak een kleine tabel Leveranciers met 2 kolommen: Naam, URL. Maak een GridView die de tabel toont. De URL wordt getoond als hyperlink (de site wordt getoond als een popup).
#Zelfde oefening als oefening 1, maar nu toon je de naam en de voornaam samen als hyperlink. Als je erop klikt krijg je een tweede (popup-) venster, met het ganse adres.
==Gegevens zoeken met de GridView-control==
Net zoals bij een [[Programmeren in ASP.NET/Werken met datacontrols#Repeater|Repeater]] kan je de GridView gebruiken om alleen bepaalde gegevens uit de tabel te tonen, bijvoorbeeld alleen de adressen van een bepaalde gemeente.
===Oefeningen===
#Maak een pagina met een tekstvak, een knop en een gridview. De gebruiker vult een gemeente in en bij het klikken op de knop toont de GridView alle adressen uit die gemeente. Gebruik de tabel met adressen.
#Zelfde opdracht, maar nu met een dropdownlist en een GridView. De dropdownlist toont alle gemeentes uit de tabel met adressen). Bij het selecteren van een gemeente toont de GridView alle adressen uit die gemeente.
==Lege tabel==
De GridView heeft ook een <EmptyDataTemplate> dat je kan gebruiken om een boodschap te tonen als er geen gegevens gevonden worden.
==Sorteren en pagineren met de GridView-control==
Sorteren en pagineren met de GridView-control is nog gemakkelijker dan met de DataGrid. Je gebruikt hiervoor de AllowSorting- en de AllowPaging-property's, en ook wederom is het niet nodig om aparte code te schrijven:
''gridviewsort.aspx''
<pre><html>
<head runat="server">
<title>Sorteren en pagineren in een GridView</title>
</head>
<body>
<form id="form1" runat="server">
<asp:GridView DataSourceID="TitlesSource" AllowSorting="true"
AllowPaging="true" Runat="Server" />
<asp:SqlDataSource ID="TitlesSource"
ConnectionString= "Server=localhost;Database=pubs;Trusted_Connection=true"
SelectCommand="SELECT * FROM Titles" Runat="Server" />
</form>
</body>
</html> </pre>
De GridView-control ondersteunt ook automatisch oplopend en aflopend sorteren. Als je op een kolomhoofd klikt, verandert dus de volgorde.
Als Paging aan staat, heb je ook meerdere mogelijkheden voor de navigatie dan bij de DataGrid. Je kan deze instellen via de PagerSettings- and PagerStyles- property's.
Naast NextPrevious en Numeric heb je ook NextPreviousFirstLast en NumericFirstLast navigatie.
Bovendien kan je in plaats van gewone links ook afbeeldingen gebruiken:
<pre><asp:GridView DataSourceID="src1" AllowPaging="true" PageSize="4" Runat="Server">
<PagerSettings Mode="NextPreviousFirstLast"
FirstPageImageUrl="First.gif" PreviousPageImageUrl="Prev.gif"
NextPageImageUrl="Next.gif" LastPageImageUrl="Last.gif" />
</asp:GridView> </pre>
===Oefening===
#Breid de pagina van de vorige oefening uit met zowel sorteren als pagineren.
==Client-side sorteren en pagineren==
Met de GridView-control kan je ook sorteren en pagineren zonder dat er een postback nodig is van de ganse pagina naar de server.
Je doet dit door de EnableSortingAndPagingCallbacks-property op True in te stellen.
''gridviewcallback.aspx''
<pre><html>
<head runat="server">
<title>Callback GridView</title>
</head>
<body>
<form runat="server">
<%=DateTime.Now %>
<asp:GridView DataSourceID="TitlesSource" EnableSortingAndPagingCallbacks="true"
AllowPaging="true" AllowSorting="true" Runat="Server" />
<asp:SqlDataSource ID="TitlesSource"
ConnectionString= "Server=localhost;Database=pubs;Trusted_Connection=true"
SelectCommand="SELECT * FROM Titles" Runat="Server" />
</form>
</body>
</html> </pre>
Deze pagina toont de datum en de tijd, en de inhoud van de Titles-tabel. Als je sorteert of pagineert in de GridView, merk je dat de tijd niet verandert op de pagina.
Achter de schermen gebruikt de GridView het XMLHTTPRequest-object van Microsoft Internet Explorer om te communiceren met de web-server. Dit object wordt ondersteund vanaf Internet Explorer 5.0. In andere browsers werkt het sorteren en pagineren ook wel, maar met een gewone postback.
==Selecteren met de GridView-control==
Met de GridView kan je ook gegevens selecteren. Je doet dit door in de smart tag "Enable Selection" aan te vinken. Als je formattering toegevoegd hebt, worden geselecteerde items in een andere kleur getoond. Je kan ook het OnSelectedIndexChanged-event opvangen om bij elke selectie een actie te ondernemen, bijvoorbeeld in een apart panel meer informatie tonen.
Je kan ook de AutoGenerateSelectButton-property op true zetten.
De GridView heeft geen SelectedItemTemplate zoals de DataList. Er is wel een SelectedRowStyle.
==Wijzigen met de GridView-control==
Met de GridView kan je ook de gegevens wijzigen. Je doet dit door in de smart tag "Enable Editing" aan te vinken. Je kan ook de AutoGenerateEditButton-property op true zetten.
De DataSource-control waaraan de GridView gekoppeld is, moet wel een geldige UpdateCommand-property hebben (dit moet een SQL UPDATE-commando zijn). Je kan dit commando zelf toevoegen, of je kan de wizard gebruiken:
#Selecteer de DataSource-control, klik op de smart tag en kies "Configure Data Source..."
#Klik twee keer op Next
#Na het instellen van het SELECT-statement, klik je op "Advanced...". Je kan nu INSERT-, UPDATE-, en DELETE- commando's automatisch laten aanmaken (als deze optie grijs is komt dit doordat het SELECT-statement geen primary key bevat).
#Werk de wizard verder af.
''gridviewedit.aspx''
<pre><html>
<head id="Head1" runat="server">
<title>Edit GridView</title>
</head>
<body>
<form id="Form1" runat="server">
<asp:GridView ID="GridView1" DataSourceID="ProductsSource"
DataKeyNames="ProductID" Runat="Server" AutoGenerateColumns="False" >
<Columns>
<asp:CommandField ShowEditButton="True" />
<asp:BoundField DataField="ProductID" HeaderText="ProductID"
InsertVisible="False"
ReadOnly="True" SortExpression="ProductID" />
<asp:BoundField DataField="ProductName" HeaderText="ProductName"
SortExpression="ProductName" />
<asp:CheckBoxField DataField="Discontinued" HeaderText="Discontinued"
SortExpression="Discontinued" />
</Columns>
</asp:GridView>
<asp:SqlDataSource ID="ProductsSource"
ConnectionString= "<%$ ConnectionStrings:NorthwindConnectionString %>"
SelectCommand= "SELECT [ProductID], [ProductName], [Discontinued] FROM
[Products]"
UpdateCommand="UPDATE [Products] SET [ProductName] = @ProductName, [Discontinued]
= @Discontinued WHERE [ProductID] = @original_ProductID" Runat="Server"
DeleteCommand="DELETE FROM [Products] WHERE [ProductID] = @original_ProductID"
InsertCommand="INSERT INTO [Products] ([ProductName], [Discontinued]) VALUES
(@ProductName, @Discontinued)" >
<DeleteParameters>
<asp:Parameter Name="original_ProductID" Type="Int32" />
</DeleteParameters>
<UpdateParameters>
<asp:Parameter Name="ProductName" Type="String" />
<asp:Parameter Name="Discontinued" Type="Boolean" />
<asp:Parameter Name="original_ProductID" Type="Int32" />
</UpdateParameters>
<InsertParameters>
<asp:Parameter Name="ProductName" Type="String" />
<asp:Parameter Name="Discontinued" Type="Boolean" />
</InsertParameters>
</asp:SqlDataSource>
</form>
</body>
</html> </pre>
[[Afbeelding:Wijzigen in de GridView.gif|thumb|right|Wijzigen in de GridView]]
Merk op dat er een UpdateCommand, een DeleteCommand en een InsertCommand toegevoegd zijn, met opgave van de overeenkomstige parameters.
De databank wordt automatisch bijgewerkt, en in tegenstelling tot de DataGrid moet je geen code schrijven.
Als je de links Nederlandstalig wil hebben kan je het CommandField als volgt aanpassen:
<pre><asp:CommandField SelectText="selecteren" EditText="wijzigen"
UpdateText="bijwerken" DeleteText="verwijderen" CancelText="annuleren"
ShowSelectButton="True" ShowEditButton="True" ShowDeleteButton="True" /></pre>
In de meeste gevallen kan de GridView automatisch de juiste datatypes van de kolommen die je wil bijwerken bepalen. In het voorbeeld hierboven wordt de waarde van het ProductID tekstvak automatisch omgezet in een integer, en de waarde van het Discontinued-aankruisvak wordt automatisch omgezet naar een BIT vóór het UPDATE-commando uitgevoerd wordt.
'''Opmerkingen'''
<ul>
<li>Merk op dat de BoundColumn voor ProductID ingesteld staat met ReadOnly="True". Automatisch wordt dan bij het wijzigen van gegevens in die kolom geen tekstvak getoond, maar een gewoon label. Dit is nuttig voor bijvoorbeeld een "Autonumber"-veld, dat toch niet kan gewijzigd worden.
<li>Bij een AccessDataSource wordt soms het verkeerde INSERT-commando aangemaakt als er AutoNumber-velden zijn. Je moet dit dan manueel wijzigen. Als er bijvoorbeeld staat<br>
<span style="font-family: Courier;">InsertCommand="INSERT INTO tbl ([ID], [Naam], [Adres]) VALUES (?,?,?)"</span><br>
waarin ID een AutoNumber-veld is, dan moet je dit zelf veranderen in<br>
<span style="font-family: Courier;">InsertCommand="INSERT INTO tbl ([Naam], [Adres]) VALUES (?,?)"</span><br>
Verwijder dan ook ID bij de InsertParameters. Bij UPDATE en DELETE heb je dit probleem niet.
<li>Als het tekstvak te klein is, kan je via de ControlStyle (een eigenschap van de BoundColumn) deze breedte groter instellen.</li>
<li>Visual Web Developer 2008 Express. Error bij opslaan datumveld: "Serverfout in toepassing /Test_DB1. De gebruikte versie van SQL Server biedt geen ondersteuning voor gegevenstype date". Oplossing: in properties datakeynames zetten, en wijzig sqlDataSource1.UpdateQuery property datatype van object naar datetime.</li>
</ul>
==Verwijderen met een GridView==
Kies Edit Columns in het menu van de GridView, selecteer CommandField, en het subtype Delete. Voeg die kolom toe. Deze kolom zal automatisch een Delete-knop produceren in elke rij, en bij het klikken op die knop wordt die rij verwijderd.
Het verwijderen gebeurt echter onmiddellijk, zonder bevestiging. Dit betekent dat als je per ongeluk op de delete-knop klikt je het record verwijdert. En dit kan je meestal niet ongedaan maken.
Daarom is het goed bij verwijderen altijd bevestiging te vragen. Een goede manier om dit te doen is een client-side JavaScript toe te voegen aan de delete-knop.
Dit kan gemakkelijk door het CommandField om te zetten in een TemplateField (zie verder), en dan op de delete-knop de property OnClientClick in te stellen op
OnClientClick=”return confirm(‘Ben je zeker?’);”
===Oefening===
#Maak een GridView voor de AdresTabel zodat je de adressen ook kan wijzigen en verwijderen
#Breid de oefening met de tabel Leveranciers (met 2 kolommen: Naam en URL) uit zodat je de naam en de url ook kan wijzigen.
==Een TemplateField toevoegen==
Je kan ook zoals bij de DataList met een EditItemTemplate werken, maar dan moet je een TemplateField gebruiken.
Soms wil je nog meer controle over hoe de kolommen getoond worden. Je wil bijvoorbeeld naast het tekstvak een klein pictogram, of je wil op sommige vakken of knoppen een ToolTip met uitleg toevoegen. Dergelijke problemen kan je oplossen met een TemplateField.
Selecteer de grid weer, kies "Edit fields..." in de smart tag, en selecteer de kolom "ProductName" in de lijst onderaan. Klik nu op "Convert this field into a TemplateField". Dit is het resultaat:
<pre><asp:TemplateField HeaderText="ProductName" SortExpression="ProductName">
<ItemTemplate>
<asp:Label ID="Label1" runat="server" Text='<%# Eval("ProductName") %>' />
</ItemTemplate>
<EditItemTemplate>
<asp:TextBox ID="TextBox1" runat="server" Text='<%# Bind("ProductName") %>' />
</EditItemTemplate>
</asp:TemplateField></pre>
Deze code doet net hetzelfde als de vorige, maar binnen het TemplateField zijn er nu verschillende templates, die je elk apart manueel (en via het designvenster – kies Edit Templates...) kan aanpassen.
Merk ook op hoe de gegevens gekoppeld worden aan de juiste control binnen het template: met Bind() en Eval(). Bind() wordt gebruikt voor binding in twee richtingen (lezen en schrijven), Eval() voor binding in één richting: alleen lezen.
===Oefeningen===
#Breid de oefening met de Leveranciers-tabel uit zodat in de plaats van de url een afbeelding (pictogram) getoond wordt. De afbeelding werkt wel nog als hyperlink om de website te openen. Je kan hier geen HyperlinkField gebruiken (geen afbeelding) en ook geen ImageField (geen hyperlink), maar het kan wel met een TemplateField. Tip: maak eerst een HyperlinkField, en zet die om naar een TemplateField, dan heb je minder werk.
#Breid de tabel Leveranciers uit met een 3e kolom: email. Maak een GridView die ook het e-mailadres toont als een hyperlink. Tip: voor het e-mailadres moet je een templatefield gebruiken, omdat e-mailadressen in een hyperlinkfield voor de veiligheid geblokkeerd worden.
#Wijzig de pagina waar je adresgegevens kan wijzigen zodanig dat de link “Wijzigen” een ToolTip toont met meer uitleg.
#Toon uit AdresTabel de naam en het telefoonnummer en toon vóór elk nummer het telefoonsymbool (als gif). Als de persoon geen telefoon heeft, toon je niets.
==Foutverwerking==
De voorbeelden hierboven bevatten geen code voor foutverwerking. Bij databanken kunnen er allerlei fouten optreden, en zoals het nu is loopt de pagina in de soep.
Om dit te vermijden, kan je foutverwerking toevoegen door een event handler aan te maken voor het RowDeleted-event en het RowUpdated-event van de GridView, en kan je daar de fout gracieus opvangen. Om ook foutverwerking te doen bij het tonen van de gegevens (SELECT-commando), moet je op de DataSourceControl het OnSelected-event afvangen.
De pagina hieronder illustreert dit:
''gridviewerror.aspx''
<pre><%@ Page Language="vb" %>
<script runat="server">
Protected Sub ProductsSource_Selected(ByVal sender As Object,
ByVal e As System.Web.UI.WebControls.SqlDataSourceStatusEventArgs)
If Not e.Exception Is Nothing Then
lblError.Text = "Kon gegevens niet opvragen"
e.ExceptionHandled = True
End If
End Sub
Sub GridViewDeleted(ByVal s As Object, ByVal e As GridViewDeletedEventArgs)
If Not e.Exception Is Nothing Then
lblError.Text = "Kon rij niet verwijderen"
e.ExceptionHandled = True
Else
lblError.Text = "De rij werd met succes verwijderd"
End If
End Sub
Sub GridViewUpdated(ByVal s As Object, ByVal e As GridViewUpdatedEventArgs)
If Not e.Exception Is Nothing Then
lblError.Text = "Kon rij niet bijwerken"
e.ExceptionHandled = True
Else
lblError.Text = "De rij werd met succes bijgewerkt"
End If
End Sub
</script>
<html>
<head runat="server">
<title>Foutverwerking in een GridView</title>
</head>
<body>
<form runat="server">
<asp:Label ID="lblError" ForeColor="Red" EnableViewState="false"
Runat="Server" />
<asp:GridView DataSourceID="ProductsSource" OnRowUpdated="GridViewUpdated"
OnRowDeleted="GridViewDeleted"
AutoGenerateEditButton="true" DataKeyNames="ProductID" Runat="Server" />
<asp:SqlDataSource ID="ProductsSource"
ConnectionString="Server=localhost;Database=Northwind;Trusted_Connection=true"
SelectCommand= "SELECT ProductID,ProductName,Discontinued FROM Products"
UpdateCommand="Update Products SET ProductName=@ProductName,
Discontinued=@Discontinued WHERE ProductID=@ProductID"
DeleteCommand="Delete FROM Products WHERE ProductID=@ProductID"
Runat="Server" OnSelected="ProductsSource_Selected" />
</form>
</body>
</html> </pre>
De GridViewDeleted-methode wordt uitgevoerd telkens een GridView-rij verwijderd wordt en de GridViewUpdated-methode telkens een rij bijgewerkt wordt. De tweede parameter van deze methodes (GridViewUpdatedEventArgs en GridViewUpdatedEventArgs) heeft telkens property's die je kan gebruiken voor foutverwerking:
* de Exception-property geeft je de exception die optrad tijdens het UPDATE-commando
* de ExceptionHandled-property kan je gebruiken om aan te geven of je zelf de fout wilt verwerken. Als je deze property op true zet, dan zal de server geen fout meer tonen. Als ExceptionHandled false is, dan zal de exception daarna toch doorgaan, en krijgt de gebruiker de gewone gebruikersonvriendelijke foutmelding van de server.
==Master/Detail met twee GridView-controls==
Tenslotte maken we een Master/Detail formulier door twee GridView-controls te combineren. Met de eerste GridView-control toon je een lijst met leveranciers (tabel Suppliers uit Northwind). Als je een leverancier selecteert, dan zal de tweede GridView-control alle producten tonen van die leverancier.
Maak de eerste GridView aan met alleen de kolommen SupplierID, CompanyName en CompanyContact. Selecteer ook de optie "Enable Selection".
De tweede GridView-control toont de producten van de leverancier die geselecteerd is in de eerste GridView. Deze koppeling gebeurt door bij de DataSource-control van de tweede GridView een WHERE-conditie op te geven.
Merk op dat de pagina twee SqlDataSource-controls bevat; één voor elke GridView-control.
'''Opmerking'''
*Je kan de tweede GridView zelfs binnen de eerste tonen, dit noemt men een geneste GridView. Je kan ook een GridView binnen een Repeater of een DataList tonen, daar is het gemakkelijker om de bladschikking dan compact in te stellen.
==OnRowDataBound==
Net zoals het ItemDataBound-event bij de [[Programmeren in ASP.NET/Werken met datacontrols#DataList|DataList]] kan je het RowDataBound-event gebruiken om nog aanpassingen te doen op het moment dat de gegevens in de rijen terechtkomen.
Het RowDataBound-event krijgt als tweede parameter (e) een object van het type GridViewRowEventArgs. Dit kan je gebruiken in je code om toegang te krijgen tot het item:
*e.Row is de GridViewRow. Dit is de rij van de GridView-tabel die overeenkomt met één rij in de databanktabel.
*e.Row.RowType is het type van de rij. Hiermee kan je controleren of het een gewone rij is (DataRow), een header-rij of een footer-rij.
*e.Row.RowState is de status van de rij. Hiermee kan je controleren of het een normale rij is (Normal), een alternerende rij, een edit-rij of een geselecteerde rij.
*e.Row.RowIndex is de index van het item, te beginnen vanaf 0. Dit geldt alleen voor gewone items en alternating items.
*e.Row.DataItem is een object dat overeenkomt met de rij uit de databank waarmee het item overeenstemt. Dit geldt alleen voor gewone items en alternating items.
*DataBinder.Eval(e.Row.DataItem,"naamveld") geeft de waarde van het opgegeven veld in de databank voor het item.
*Om toegang te krijgen tot een bepaalde control binnen een BoundField, kan je e.Row.Cells(i).Controls(0) gebruiken. De index i is daarin het volgnummer van de kolom (te beginnen vanaf 0).
*Om toegang te krijgen tot een bepaalde control binnen een TemplateField, kan je e.Row.Cells(i).FindControl("IDControl") gebruiken. De index i is daarin het volgnummer van de kolom en IDControl is de ID van de control binnen het template.
===Oefeningen===
#Zoek op het Internet hoe je onderaan een GridView totalen kunt tonen. Pas dit toe in een pagina.
#Zoek op het Internet hoe je in een GridView de records kan groeperen. Maak een pagina met een GridView waarbij de adressen per gemeente worden gegroepeerd.
#Zoek op het Internet hoe je een GridView kan maken waar je alle rijen tegelijk kan wijzigen. Pas dit toe in een pagina.
{{Bladeren2
|Boek=Programmeren in ASP.NET
|vorige=Werken met datacontrols
|huidige=GridView
|volgende=FormView en DetailsView
}}
{{Sub}}
bdg7iehwtz08x2uizdblivadmw0l3fy
Programmeren in ASP.NET/FormView en DetailsView
0
3848
428827
425785
2026-05-23T12:17:15Z
Erik Baas
2193
lf
428827
wikitext
text/x-wiki
{{Index Programmeren in ASP.NET}}
De FormView-control en de DetailsView zijn twee volledig nieuwe controls in ASP.NET 2.0, speciaal om individuele databankrecords te tonen en te wijzigen, toe te voegen of te verwijderen.
Je kan de controls apart gebruiken om één enkel databaserecord te tonen, of je kan ze samen met de GridView-control gebruiken om master/detail-formulieren te maken.
==Gegevens tonen met de FormView-control==
De FormView-control is bedoeld om één enkel databankrecord te tonen. Voor elke kolom uit de databanktabel toont de FormView-control automatisch labels en waarden voor elke geselecteerde kolom. De volgende pagina toont hoe je de FormView-control kan gebruiken om één enkel record van de Authors-tabel te tonen.
Om deze pagina te maken voeg je de FormView-control toe aan de pagina, en vervolgens doorloop je de wizard om één record uit de databank te halen.
''formview.aspx''
<pre><html>
<head runat="server">
<title>FormView</title>
</head>
<body>
<form runat="server">
<asp:FormView ID="FormView1" runat="server" DataKeyNames="au_id" DataSourceID="AuthorsSource">
<EditItemTemplate>
au_id: <asp:Label ID="au_idLabel1" runat="server" Text='<%# Eval("au_id") %>'/><br>
au_lname: <asp:TextBox ID="au_lnameTextBox" runat="server" Text='<%# Bind("au_lname") %>'/><br>
au_fname: <asp:TextBox ID="au_fnameTextBox" runat="server" Text='<%# Bind("au_fname") %>'/><br>
phone: <asp:TextBox ID="phoneTextBox" runat="server" Text='<%# Bind("phone") %>'/><br>
address: <asp:TextBox ID="addressTextBox" runat="server" Text='<%# Bind("address") %>'/><br>
city: <asp:TextBox ID="cityTextBox" runat="server" Text='<%# Bind("city") %>'/><br>
state: <asp:TextBox ID="stateTextBox" runat="server" Text='<%# Bind("state") %>'/><br>
zip: <asp:TextBox ID="zipTextBox" runat="server" Text='<%# Bind("zip") %>'/><br>
contract: <asp:CheckBox ID="contractCheckBox" runat="server" Checked='<%# Bind("contract") %>' /><br>
<asp:LinkButton ID="UpdateButton" runat="server" CausesValidation="True" CommandName="Update"
Text="Update">
</asp:LinkButton>
<asp:LinkButton ID="UpdateCancelButton" runat="server" CausesValidation="False"
CommandName="Cancel" Text="Cancel">
</asp:LinkButton>
</EditItemTemplate>
<InsertItemTemplate>
au_id: <asp:TextBox ID="au_idTextBox" runat="server" Text='<%# Bind("au_id") %>'/><br>
au_lname: <asp:TextBox ID="au_lnameTextBox" runat="server" Text='<%# Bind("au_lname") %>'/><br>
au_fname: <asp:TextBox ID="au_fnameTextBox" runat="server" Text='<%# Bind("au_fname") %>'/><br>
phone: <asp:TextBox ID="phoneTextBox" runat="server" Text='<%# Bind("phone") %>'/><br>
address: <asp:TextBox ID="addressTextBox" runat="server" Text='<%# Bind("address") %>'/><br>
city: <asp:TextBox ID="cityTextBox" runat="server" Text='<%# Bind("city") %>'/><br>
state: <asp:TextBox ID="stateTextBox" runat="server" Text='<%# Bind("state") %>'/><br>
zip: <asp:TextBox ID="zipTextBox" runat="server" Text='<%# Bind("zip") %>'/><br>
contract: <asp:CheckBox ID="contractCheckBox" runat="server" Checked='<%# Bind("contract") %>' /><br>
<asp:LinkButton ID="InsertButton" runat="server" CausesValidation="True" CommandName="Insert"
Text="Insert">
</asp:LinkButton>
<asp:LinkButton ID="InsertCancelButton" runat="server" CausesValidation="False"
CommandName="Cancel" Text="Cancel">
</asp:LinkButton>
</InsertItemTemplate>
<ItemTemplate>
au_id: <asp:Label ID="au_idLabel" runat="server" Text='<%# Eval("au_id") %>'/><br>
au_lname: <asp:Label ID="au_lnameLabel" runat="server" Text='<%# Bind("au_lname") %>'/><br>
au_fname: <asp:Label ID="au_fnameLabel" runat="server" Text='<%# Bind("au_fname") %>'/><br>
phone: <asp:Label ID="phoneLabel" runat="server" Text='<%# Bind("phone") %>'/><br>
address: <asp:Label ID="addressLabel" runat="server" Text='<%# Bind("address") %>'/><br>
city: <asp:Label ID="cityLabel" runat="server" Text='<%# Bind("city") %>'/><br>
state: <asp:Label ID="stateLabel" runat="server" Text='<%# Bind("state") %>'/><br>
zip: <asp:Label ID="zipLabel" runat="server" Text='<%# Bind("zip") %>'/><br>
contract: <asp:CheckBox ID="contractLabel" runat="server" Checked='<%# Bind("contract") %>'
Enabled="false" /><br>
</ItemTemplate>
</asp:FormView>
<asp:SqlDataSource ID="AuthorsSource"
ConnectionString="Server=localhost;Database=Pubs;Trusted_Connection=true"
SelectCommand= "SELECT * FROM Authors WHERE au_id='172-32-1176'"
Runat="Server" />
</form>
</body>
</html></pre>
De FormView-control wordt hier verbonden met een SqlDataSource-control die de auteur opvraagt met ID 172-32-1176. Dit is het resultaat:
[[Afbeelding:FormView-control.gif|center|De FormView-control]]
Merk op dat de labels automatisch de veldnamen uit de databank tonen, en dat er drie templates aangemaakt zijn:
#ItemTemplate
#EditItemTemplate
#InsertItemTemplate
Je kan deze templates naar believen zelf aanpassen om de lay-out te krijgen die je wil.
Merk ook op hoe de gegevens gekoppeld worden aan de juiste control binnen het template: met Bind() en Eval(). Bind() wordt gebruikt voor binding in twee richtingen (lezen en schrijven), Eval() voor binding in één richting: alleen lezen.
Om te kunnen wijzigen en toevoegen moet je de datasource aanpassen via de Advanced-knop, en "Generate INSERT, UPDATE and DELETE statements" aanvinken. Als je daarna de FormView opnieuw aanmaakt, verschijnen automatisch de nodige knoppen:
[[Afbeelding:FormView edit.gif|center|FormView-control met wijzigmogelijkheid]]
Om de weergegeven tekst op de knoppen ("Edit", "Delete", "New", "Update" en "Cancel") te vertalen moet je manueel de templates aanpassen. In elk template vind je LinkButtons terug voor de verschillende acties.
==Navigatie met de FormView-control==
Hierboven heb je gezien hoe je met de FormView-control één enkel record kan tonen. Je kan de FormView ook gebruiken om van record naar record te navigeren.
Hiervoor moet je de AllowPaging-property op true instellen. De FormView-control maakt automatisch de nodige navigatieknoppen aan. De datasource moet natuurlijk meerdere records geven, dus laat de WHERE-conditie van de vorige pagina weg.
Je krijgt een Pager zoals bij de DataGrid en de GridView. De instellingen gebeuren ook op dezelfde manier via de PagerSettings- en PagerStyle-property's.
==Een Master/Detail-pagina maken met de FormView-control==
Hier maken we een Master/Detail-formulier door de FormView- en GridView-controls te combineren. De procedure is bijna dezelfde als bij een Master/Detail met twee GridViews.
Met de GridView-control toon je een lijst met werknemers (tabel Employees uit Northwind). Als je een werknemer selecteert, dan zal de FormView-control meer gegevens tonen over die werknemer.
Maak de GridView aan met alleen de kolommen EmployeeID, Firstname en Lastname. Selecteer ook de optie "Enable Selection". Hierdoor krijg je een extra kolom met een knop "Select". Als je op deze knop klikt, wordt de rij geselecteerd.
De FormView-control toont de werknemer die geselecteerd is in de GridView. Deze koppeling gebeurt door bij de DataSource-control van de FormView een WHERE-conditie op te geven:
[[Afbeelding:Gridform.gif|center|Master/Detail formulier met een GridView- en een FormView-control]]
Merk op dat de pagina twee SqlDataSource-controls bevat; één SqlDataSource is verbonden met de GridView-control, en de andere SqlDataSource is verbonden met de FormView-control.
'''Opmerkingen'''
*Als je items bijwerkt, verwijdert of toevoegt, dan worden die wijzigingen niet automatisch getoond in de GridView. Om dit te bekomen voeg je respectievelijk de ItemUpdated-, ItemDeleted, en ItemInserted-events toe, met de volgende code:
GridView1.DataBind()
:Hierdoor zal de GridView opnieuw gegevens ophalen en dus ververst worden.
*Denk er ook weer aan om foutverwerking toe te voegen, net zoals bij de GridView. Dit doe je in dezelfde ItemUpdated-, ItemDeleted en ItemInserted-events.
===Oefeningen===
#Maak een pagina met twee GridViews: één voor albums en één voor nummers. De grids zijn gekoppeld via een master/detail-relatie. Voeg nu aan elke GridView een FormView toe om de records te kunnen bekijken in detail en om ze te kunnen wijzigen.
==ChangeMode==
Soms wil je een FormView-control gebruiken om onmiddellijk gegevens toe te voegen. Dat kan door de control direct in "Insert"-mode te schakelen. Dit doe je met de volgende regel (Bijvoorbeeld in Page_Load):
FormView1.ChangeMode(FormViewMode.Insert)
Als je de FormView-control alleen maar gebruikt om gegevens toe te voegen, bijvoorbeeld in een aparte pagina die niets anders doet, dan kan je hem default instellen op toevoegen. Zet daarvoor de DefaultMode-property op de waarde "Insert".
Je mag dan zelfs het ItemTemplate en het EditItemTemplate volledig verwijderen, alleen het InsertItemTemplate is dan nodig.
==DetailsView==
De DetailsView-control is ook een volledig nieuwe control in ASP.NET 2.0, die vergelijkbaar is met de FormView-control. Bij de DetailsView-control heb je geen templates, deze worden automatisch aangemaakt, en je kan de schikking niet wijzigen.
Daar staat tegenover dat de DetailsView-control alle velden onder elkaar toont in een nette tabel, en dat er verder niet veel code nodig is. Bij een aanpassing van het ontwerp van een tabel, bijvoorbeeld als een extra veld toegevoegd wordt, kan deze control de nieuwe situatie tonen zonder dat de pagina moet aangepast worden.
Je kan de DetailsView-control gebruiken zoals de FormView: apart, of in een master/detail-scenario.
==Gegevens tonen met de DetailsView-control==
De DetailsView-control is net zoals de FormView bedoeld om één enkel databankrecord te tonen. Voor elke kolom uit de databanktabel toont de DetailsView-control automatisch labels en waarden voor elke geselecteerde kolom. De volgende pagina toont hoe je de DetailsView-control kan gebruiken om één enkel record van de Authors-tabel te tonen.
''detailsview.aspx''
<pre><html>
<head runat="server">
<title>Details View</title>
</head>
<body>
<form runat="server">
<asp:DetailsView DataSourceID="AuthorsSource" Runat="Server" />
<asp:SqlDataSource ID="AuthorsSource"
ConnectionString="Server=localhost;Database=Pubs;Trusted_Connection=true"
SelectCommand= "SELECT * FROM Authors WHERE au_id='172-32-1176'"
Runat="Server" />
</form>
</body>
</html></pre>
De DetailsView-control wordt hier verbonden met een SqlDataSource-control die de auteur opvraagt met ID 172-32-1176.
Merk op dat de labels automatisch de veldnamen uit de databank tonen.
Net als bij de GridView-control kan je bij de DetailsView-control zelf controleren welke velden je toont. De manier is ook dezelfde: zet de AutoGenerateRows-property op false en voeg de juiste velden toe. Je gebruikt hier een <fields>-tag, terwijl het bij de GridView een <columns>-tag was.
De DetailsView-control ondersteunt dezelfde veldtypes als de GridView-control.
''detailsviewvelden.aspx''
<pre><html>
<head runat="server">
<title>Details View</title>
</head>
<body>
<form id="Form1" runat="server">
<asp:DetailsView ID="DetailsView1" DataSourceID="AuthorsSource"
AutoGenerateRows="false" Runat="Server">
<Fields>
<asp:BoundField DataField="au_id" HeaderText="ID" ReadOnly="true" />
<asp:BoundField DataField="au_lname" HeaderText="Naam" />
<asp:BoundField DataField="au_fname" HeaderText="Voornaam" />
</Fields>
</asp:DetailsView>
<asp:SqlDataSource ID="AuthorsSource"
ConnectionString= "Server=localhost;Database=Pubs;Trusted_Connection=true"
SelectCommand="SELECT * FROM Authors WHERE au_id='172-32-1176'"
Runat="Server" />
</form>
</body>
</html> </pre>
==Navigatie met de DetailsView-control==
Hierboven heb je gezien hoe je met de DetailsView-control één enkel record kan tonen. Je kan de DetailsView ook gebruiken om van record naar record te navigeren.
Hiervoor moet je de AllowPaging-property op true instellen. De DetailsView-control maakt automatisch de nodige navigatieknoppen aan.
Je krijgt een Pager zoals bij de FormView. De instellingen gebeuren ook op dezelfde manier via de PagerSettings- en PagerStyle-property's.
==Databaserecords wijzigen met de DetailsView-control==
Met de DetailsView-control kan je ook databaserecords wijzigen, verwijderen en toevoegen. Dit is zelfs mogelijk zonder één regel code te schrijven.
Om te wijzigen gebruik je de AutoGenerateEditButton-, AutoGenerateDeleteButton-, en AutoGenerateInsertButton-property's. Net zoals bij de GridView moet je bij de DataSource-control waarden (SQL-opdrachten) opgeven voor UpdateCommand, InsertCommand, en DeleteCommand.
Met de volgende pagina krijg je een DetailsView-control waarmee je de "Authors"-tabel kan wijzigen:
''detailsviewedit.aspx''
<pre><html>
<head runat="server">
<title>Details View</title>
</head>
<body>
<form runat="server">
<asp:DetailsView DataSourceID="AuthorsSource" AllowPaging="true"
AutoGenerateEditButton="true" AutoGenerateDeleteButton="true"
AutoGenerateInsertButton="true" DataKeyNames="au_id" Runat="Server" />
<asp:SqlDataSource ID="AuthorsSource"
ConnectionString= "Server=localhost;Database=Pubs;Trusted_Connection=true"
SelectCommand= "SELECT au_id,au_lname,au_fname,contract FROM Authors"
UpdateCommand= "UPDATE Authors SET au_lname=@au_lname, au_fname=@au_fname,
contract=@contract WHERE au_id=@au_id"
DeleteCommand="DELETE FROM Authors WHERE au_id=@au_id"
InsertCommand= "INSERT INTO Authors (au_id,au_lname,au_fname,contract)
VALUES (@au_id,@au_lname,@au_fname,@contract)" Runat="Server" />
</form>
</body>
</html> </pre>
==Een Master/Detail pagina maken met de DetailsView-control==
De procedure is precies dezelfde als voor de FormView-control. Zie [[#Een Master/Detail-pagina maken met de FormView-control|boven]].
===Oefening===
#Maak een pagina om publishers toe te voegen aan de databank "pubs". Gebruik een GridView en een DetailsView.
==Vergelijking tussen de datacontrols==
{| class="wikitable" style="font-size:xx-small"
|-
|Control||Wanneer gebruiken?||Selected ItemTemplate||Edit ItemTemplate||opmaken in Visual Studio.NET||meerdere kolommen per pagina||gegevens automatisch tonen||ingebouwd sorteren||ingebouwd pagineren||client-side sorteren en pagineren
|-
|Repeater
|
*voor read-only weergave van gegevens
*voor het tonen van gegevens naast elkaar
|nee||nee||nee||nee||nee||nee||nee||nee
|-
|DataList
|
*voor het weergeven en wijzigen van gegevens in een ander formaat dan een tabel
*voor het weergeven van items in meerdere kolommen naast elkaar (column layout)
*indien er veel velden zijn (waardoor een DataGrid veel te breed wordt)
|ja||ja||ja||ja||nee||nee||nee||nee
|-
|DataGrid
|
*voor het snel zonder veel ontwerp weergeven en wijzigen van gegevens in tabelvorm
|ja||ja||ja||nee||ja||ja||ja||nee
|-
|GridView
|
*voor het snel zonder veel ontwerp weergeven en wijzigen van gegevens in tabelvorm
*indien sorteren nodig is
*indien pagineren nodig is
*indien client-side sorteren en pagineren nodig is
|ja||ja||ja||nee||ja||ja||ja||ja
|-
|FormView
|
*om één enkel record te tonen
|nvt||ja||ja||nee||nee||nvt||ja||nee
|-
|DetailsView
|
*om één enkel record te tonen
|nvt||ja||ja||nee||ja||nvt||ja||nee
|}
nvt=niet van toepassing
{{Bladeren2
|Boek=Programmeren in ASP.NET
|vorige=GridView
|huidige=FormView en DetailsView
|volgende=User-controls
}}
{{Sub}}
8yhz21c3i6pmcf7qbq7n01y806n9ziu
Programmeren in ASP.NET/User-controls
0
4740
428830
425786
2026-05-23T12:17:17Z
Erik Baas
2193
lf
428830
wikitext
text/x-wiki
{{Index Programmeren in ASP.NET}}
==Inleiding==
Server-controls zijn zaken die het programmeren met ASP.NET zo simpel en krachtig maken. Je hebt al gezien hoe je [[Programmeren_in_ASP.NET/HTML-controls|HTML]]- en [[Programmeren_in_ASP.NET/Web-server-controls|web-server-controls]] kan gebruiken in je ASP.NET pagina's.
Wat als er nu geen control is die precies doet wat je wil?
Je kan in ASP.NET je eigen controls maken en ze gebruiken op je pagina's net zoals je de meegeleverde controls van .NET zou gebruiken.
Ook als je merkt dat je op meerdere pagina's telkens dezelfde code of HTML (of allebei) opnieuw gebruikt, kan je eraan denken om van dat onderdeel een control te maken, zodat je het steeds kan hergebruiken zonder alles opnieuw te schrijven.
Als je bijvoorbeeld een website maakt voor een boekhandel, zou je een control kunnen maken om een boek te tonen (met coverfoto, titel, auteur, enz.). Deze control kan je dan bijvoorbeeld gebruiken op een pagina over dat boek, maar ook in een lijst per auteur en in een lijst per uitgever.
===Voordelen===
Door je code in een control samen te brengen krijg je een aantal voordelen:
*je code kan gemakkelijk gebruikt worden in allerlei projecten
*je code kan eens en voor altijd getest en gedebugd worden, en ze kan daarna altijd opnieuw gebruikt worden
*je kan de control verbeteren of bijwerken, en automatisch worden alle pagina's met die control bijgewerkt
*sommige controls helpen je om een eenduidige visuele interface te voorzien voor meerdere toepassingen. Bijvoorbeeld door altijd hetzelfde soort knop te gebruiken.
*controls laten je toe het werk te verdelen over meerdere programmeurs.
*de control hoeft niet in dezelfde taal geschreven zijn als de pagina. Je kan bijvoorbeeld een control maken in C#, en hem gebruiken in een pagina met VB.
*je kan je control door anderen laten gebruiken, en zelf kan je controls van anderen gebruiken.
===Soorten===
Er zijn 3 soorten controls die je zelf kan maken:
#user-controls
#custom controls
#WebParts
De simpelste soort zijn user-controls. Deze worden gemaakt in een apart bestand, ongeveer op dezelfde manier als webformulieren. Ze kunnen ook gewone HTML-tags bevatten.
Custom controls zijn meer gevorderd (ze kunnen bijvoorbeeld toegevoegd worden aan de toolbox in Visual Studio). [[Programmeren_in_ASP.NET/Custom controls|Custom controls]] worden in het volgende hoofdstuk besproken.
[[Programmeren in ASP.NET/WebParts|WebParts]] zijn controls die door de gebruiker zelf kunnen toegevoegd worden aan een pagina, en die ook door de gebruiker gewijzigd kunnen worden.
==Je eerste user-control==
In feite is er niets moeilijks aan het schrijven van een simpele user-control (soms ook een pagelet genoemd). Bijna elk onderdeel van een ASP.NET pagina kan gebruikt worden als een user-control.
Kies in Visual Web Developer in het menu File - New File - Web User Control, en geef als naam basic.ascx (vermijd spaties of punten in de bestandsnaam). Voeg de volgende code toe:
''basic.ascx''
<pre><%@ Control Language="VB" ClassName="basic" %>
<p>
Dit is een user-control... ja hoor!
</p></pre>
Dat is alles. Wat hierboven staat kan gemakkelijk gebruikt worden als een user-control.
Toegegeven, er gebeurt niet veel, maar het illustreert wel dat deze controls zeer simpel kunnen zijn. Let op de .ascx-extensie. ASCX is de gebruikelijke extensie die aan pagina's gegeven wordt als ze moeten werken als een control. Het zorgt voor duidelijkheid en .ascx bestanden worden beschermd tegen directe uitvoering door de webserver, zodat de gebruiker nooit de code kan downloaden.
Nu je een user-control gemaakt hebt, is hier een voorbeeld hoe je die kan gebruiken in een ASP.NET web pagina.
''basic.aspx''
<pre><%@ Page Language="VB" %>
<%@ Register TagPrefix="wikibooks" TagName="basic" Src="basic.ascx" %>
<html>
<head>
<title>ASP.NET User-control voorbeeld - Basic</title>
</head>
<body>
<wikibooks:basic runat="server" />
</body>
</html></pre>
De pagina hierboven geeft een standaard HTML-pagina met de tekst binnen onze user-control in plaats van in de tag van de user-control.
'''Opmerkingen'''
#In Visual Studio kan je de user-control ook in de pagina zetten door het ascx-bestand vanuit de Solution Explorer (rechterpaneel) op de pagina te slepen.
#Een user-control wordt gecompileerd net zoals een aspx-bestand, dit is tijdens de eerste uitvoering.
Hoe werkt het toevoegen van een user-control?
Het bijzondere zit hier in het "Register"-directief. Om dit te gebruiken moet je drie attributen opgeven:
{| {{Wikitable}}
|-
|TagPrefix||definieert de prefix die gebruikt moet worden in de tags waar de controls komen. Je mag de standaard <uc0:xxxx> gebruiken, of je eigen tags kiezen.
|-
|TagName||bepaalt de naam waarmee de control zal aangeduid worden. Deze naam mag nog niet bestaan binnen de namespace, maar je mag hem zelf kiezen. Het is het beste om een naam te kiezen die aangeeft wat de control ongeveer doet.
|-
|Src||verwijst naar de code waar de control gedefinieerd wordt. Hierbij wordt een virtueel pad gebruikt, dus de waarde moet zoiets zijn als "control.ascx" of "/path/control.ascx" of “~/controls/control.ascx” en niet een absoluut pad zoals "C:\path\control.ascx."
|}
Eenmaal je het "Register"-directief hebt toegevoegd, is de control geregistreerd en kan hij gebruikt worden net zoals elke andere server-control. Je geeft de TagPrefix en TagName op in de tag van de control, net zoals je dat zou doen met een ingebouwde control. Controleer alleen nog of je het runat="server"-attribuut hebt, en je bent klaar. Hier is de simpelste vorm voor een user-control-tag:
<TagPrefix:TagName runat="server" />
Je kan meerdere user-controls op één pagina zetten. Het "Register"-directief moet je maar éénmaal toevoegen, maar elke user-control krijgt dan een andere user-control-tag. Je geeft ze dan ook best een ID, en die moet natuurlijk voor elke control verschillend zijn.
===Oefeningen===
#Maak een user-control die de datum op het scherm zet.
#Maak een user-control die een willekeurig getal op het scherm zet. Gebruik Rnd(10).
#Maak een "klok" user-control, die de tijd toont (en die verder tikt). Zet hiervoor in het HTML-gedeelte van de user-control een JavaScript.
#Maak een user-control "teller" die toont hoe dikwijls de pagina al bezocht werd. Gebruik het [[Programmeren_in_ASP.NET/Veelgebruikte_objecten#Het_HttpApplicationState-object|HttpApplicationState-object]].
==Eigenschappen geven aan je control==
Tot nu doet je control nog niet veel meer dan code uit een apart bestand halen. Gelukkig houdt het hier niet op.
Eigenschappen (property's) kan je vergelijken met variabelen die behoren tot de control. In .NET gebruik je voor property's speciale zogenaamde accessormethodes (ook getters en setters genoemd).
Nu maak je een nieuwe control met een label, en voeg je twee property's toe, één voor de kleur en één voor de tekst.
''properties.ascx''
<pre><%@ Control Language="VB" ClassName="properties" %>
<script runat="server">
Private _kleur As String = "black"
Public Property Kleur as String
Get
Return _kleur
End Get
Set (Value As String)
_kleur = Value
Label1.ForeColor = System.Drawing.Color.FromName(_kleur)
End Set
End Property
Private _tekst as String = "Dit is een user-control!"
Public Property Tekst as String
Get
Return _tekst
End Get
Set (Value As String)
_tekst = Value
Label1.Text = _tekst
End Set
End Property
</script>
<p>
<asp:Label id="Label1" runat="server"></asp:Label>
</p></pre>
Standaard ziet de control er nog hetzelfde uit, maar je kan nu wel de kleur en de tekst van de control wijzigen. Dat kan op 2 manieren, rechtstreeks in de tag, of via code (op voorwaarde dat de control een id-attribuut heeft waardoor je er kan naar verwijzen). Merk ook op dat de control meerdere malen gebruikt wordt, en dat elke instantie afzonderlijk kan ingesteld worden.
''properties.aspx''
<pre><%@ Page Language="VB" %>
<%@ Register TagPrefix="wikibooks" TagName="properties" Src="properties.ascx" %>
<script language="VB" runat="server">
Sub Page_Load(Sender as Object, E as EventArgs)
UserCtrl1.Kleur = "green"
UserCtrl1.Tekst = "De property's van deze control werden via code ingesteld!"
End Sub
</script>
<html>
<head>
<title>ASP.NET User-control voorbeeld - Property's</title>
</head>
<body>
<wikibooks:properties runat="server" />
<wikibooks:properties Kleur="red" runat="server" />
<wikibooks:properties Tekst="Dit is wel tof!" runat="server" />
<wikibooks:properties Kleur="blue" Tekst="Niet?" runat="server" />
<wikibooks:properties id="UserCtrl1" runat="server" />
</body>
</html></pre>
'''Opmerkingen'''
#Je kan ook methodes toevoegen aan een user-control. Als je deze methodes publiek maakt, dan kan je ze gewoon vanuit de pagina oproepen.
#Publieke properties van je user control verschijnen automatisch in het Property Panel van Visual Studio, en ook intellisense gebruikt ze.
#Je kan op deze manier zelfs een control maken zonder visuele onderdelen (zonder html), met enkel een of meerdere methodes. Het voordeel is dat je die methodes dan in meerdere pagina's kan toevoegen en gebruiken.
===Oefeningen===
#Maak een user-control met een dropdownlist, waarin alle landen staan. Maak ook een property die het geselecteerde land geeft.
#Maak een user-control die een afbeelding toont met een rollover-effect. Maak hiervoor eigenschappen "ImageURL1" en "ImageURL2".
#Maak een user-control die een afbeelding toont, maar als de afbeelding niet gevonden wordt, moet er een boodschap verschijnen "foto niet beschikbaar" (in de plaats van een leeg kader). Gebruik de methode System.IO.File.Exists("naambestand") om te testen of het bestand bestaat. "naambestand" moet een absoluut pad bevatten, gebruik Server.MapPath() om dat pad te vinden.
#Maak een user-control "adres", dat een adres toont uit de Adressendatabank. Geef de control een property "AdresID", die verwijst naar de ID van het adres in de tabel. De control moet zelfstandig de gegevens uit de databank halen (hierdoor staat de control meer op zichzelf, een goed voorbeeld van object-georiënteerd programmeren).
#Maak een user-control waarmee de gebruiker een datum kan kiezen. Gebruik 3 dropdownlists (dag, maand, jaar). Maak een property "SelectedDate".
#Maak een user-control die een balkgrafiek maakt door een bepaalde afbeelding n maal te herhalen. n is een property van de user-control.
#Maak een "getalvak", dit is een tekstvak dat alleen getallen accepteert. Gebruik een validator, en zorg er ook voor dat de invoer rechts uitgelijnd is. Maak een property "Waarde".
==Een control events laten verwerken==
Je kan een control bijna alles laten doen wat je maar wil. In de volgende code zal de control het OnClick-event van een knop verwerken. Met dit soort gebeurtenisverwerking (event handling) kan je controls schrijven die bijna geen code in de pagina meer nodig hebben. De controls kunnen hun gebeurtenissen zelfstandig verwerken.
Deze control bevat een tekstvak-web-control en een knop. De control is zo gemaakt dat het getal in het tekstvak verhoogt als je op de knop drukt.
''events.ascx''
<pre><%@ Control Language="VB" %>
<script runat="server">
Public Property Waarde as Integer
Get
Return CInt(tbGetal.Text)
End Get
Set
tbGetal.Text = CStr(Value)
End Set
End Property
Sub btnUp_Click (Src as Object, E as EventArgs)
Waarde = Waarde + 1
End Sub
</script>
Getal: <asp:textbox id="tbGetal" runat="server" />
<asp:Button ID="btnUp" runat="server" OnClick="btnUp_Click" Text="Up"></asp:Button></pre>
''events.aspx''
<pre><%@ Page Language="VB" %>
<%@ Register TagPrefix="wikibooks" TagName="events" Src="events.ascx" %>
<html>
<head>
<title>ASP.NET User-control voorbeeld - Validering & Events</title>
</head>
<body>
<form runat="server">
<wikibooks:events id="events1" runat="server" Waarde="0" />
</form>
</body>
</html></pre>
===Oefeningen===
#Maak een user-control die werkt zoals een checkbox, maar die dubbel zo groot is. Doe dit door je eigen afbeeldingen te gebruiken voor "aangekruist" en "niet aangekruist".
#Maak een control die samengesteld is uit een keuzelijst en twee knoppen "omhoog" en "omlaag". Als de gebruiker een keuze maakt en op "omhoog" klikt, dan moet het item omhoog schuiven in de lijst. Maak ook een property "Items", zodat vanuit de pagina de lijst van items kan opgevraagd worden in de volgorde die de gebruiker dan ingesteld heeft.
#Maak een user-control waarmee de gebruiker een datum kan kiezen. Gebruik 3 dropdownlists (dag, maand, jaar) en een Calendar-control. Zorg dat beide altijd dezelfde datum aangeven. De gebruiker kan dan zowel de dropdownlists als de Calendar gebruiken.
==Eigen events opwekken vanuit een user-control ==
In het vorige voorbeeld verwerkte de user-control zelf de events van de knop. Meestal wil je toch ook de pagina hiervan op de hoogte brengen. Om dat te doen moet de user-control zelf een nieuw event "opwekken" waarop de pagina kan reageren.
Het volgende voorbeeld toont een user-control, events2, die een custom event opwekt, Change, telkens als het cijfer verhoogt.
Dit wordt als volgt gedaan:
*Het eigen Change-event wordt gedeclareerd met het standaard eventpatroon. (Dit patroon bevat de definitie van een protected OnChange-methode die het Change-event opwekt.)
<pre>Public Event Change(Sender as Object, E as EventArgs)
Protected Sub OnChange(e As EventArgs)
RaiseEvent Change(Me, e)
End Sub</pre>
*Het OnClick-event van btnUp bestond al. Hierin wekken we nu ook het Change-event op door de OnChange-methode aan te roepen.
<pre>Private Sub btnUp_Click(sender As Object, e As EventArgs)
Waarde = Waarde + 1
OnChange(EventArgs.Empty)
End Sub</pre>
Het Change-event kan verwerkt worden door een pagina die de control bevat, zoals in het volgende voorbeeld getoond wordt. Je moet wel zelf de event-handler aanmaken en koppelen aan de control. In het voorbeeld voorziet de pagina een event-handling-methode voor het Change-event, waarin een boodschap getoond wordt in een label.
''events2.ascx''
<pre><%@ Control Language="VB" %>
<script runat="server">
Public Property Waarde as Integer
Get
Return CInt(tbGetal.Text)
End Get
Set
tbGetal.Text = CStr(Value)
End Set
End Property
Sub btnUp_Click (Sender as Object, E as EventArgs)
Waarde = Waarde + 1
OnChange(EventArgs.Empty)
End Sub
Public Event Change(Sender as Object, E as EventArgs)
Protected Sub OnChange(e As EventArgs)
RaiseEvent Change(Me, e)
End Sub
</script>
Getal: <asp:textbox id="tbGetal" runat="server" />
<asp:Button ID="btnUp" runat="server" OnClick="btnUp_Click" Text="Up"></asp:Button></pre>
In de pagina hieronder wordt de control gebruikt, en het Change-event wordt verwerkt:
''events2.aspx''
<pre><%@ Page Language="VB" %>
<%@ Register TagPrefix="wikibooks" TagName="events" Src="events2.ascx" %>
<script runat="server">
Sub events1_Change(Sender as Object, E as EventArgs)
Label1.Text = "het getal werd verhoogd"
' doe verdere verwerking hier, bijvoorbeeld databank bijwerken
End Sub
</script>
<html>
<head>
<title>ASP.NET User-control voorbeeld - Validering & Events</title>
</head>
<body>
<form runat="server">
<wikibooks:events id="events1" runat="server" Waarde="0"
OnChange="events1_Change" /><br>
<asp:Label id="Label1" runat="server" Text=""></asp:Label>
</form>
</body>
</html></pre>
===Oefeningen===
#Voor elk van de drie vorige oefeningen, zorg ervoor dat de pagina een event krijgt bij een wijziging in de user-control.
{{Bladeren2
|Boek=Programmeren in ASP.NET
|vorige=FormView en DetailsView
|huidige=User-controls
|volgende=Custom controls
}}
{{Sub}}
nwp1n9sioseo7rzh317nvyr999mu9bz
Programmeren in ASP.NET/Custom controls
0
4783
428836
425793
2026-05-23T12:17:23Z
Erik Baas
2193
lf
428836
wikitext
text/x-wiki
{{Index Programmeren in ASP.NET}}
==Inleiding==
'''Custom controls''' zijn gecompileerde controls die door de programmeur zelf ontworpen worden en die werken zoals web-controls.
Ze hebben meer mogelijkheden dan de simpele user-controls uit het vorige hoofdstuk:
*Ze kunnen toegevoegd worden aan de Toolbox in Visual Web Developer
*Je kan hun eigenschappen rechtstreeks instellen in de editor (met het property-paneel)
*Ze kunnen gebruikt worden zonder de broncode
*Ze kunnen gedeeld worden tussen verschillende applicaties op dezelfde server.
Custom controls kunnen op drie manieren gemaakt worden:
#door een bestaande control als basis te nemen en daarvan een nieuwe custom control af te leiden (bv. door een gespecialiseerd tekstvak af te leiden van asp:textbox). Dit noemt men een derived custom control.
#door een nieuwe custom control samen te stellen uit twee of meer bestaande controls. Dit noemt men composite custom control.
#door een nieuwe custom control te maken vanaf nul (afgeleid van de basis control klasse Webcontrol of Control) Dit noemt men een full custom control.
'''Opmerking:'''
*Wanneer je custom controls gebruikt in Visual Web Developer, dan is een aantal extra "designer"-methodes nodig om de control ook te laten werken in de editor zelf. Dit zorgt ervoor dat de control er al min of meer als zichzelf uitziet in de editor (anders krijg je alleen een weinig zeggend label). In deze cursus worden deze methodes niet besproken. Zonder deze methodes werkt de control normaal als je hem test vanaf een website, hij werkt alleen niet binnen de editor.
==Een simpele custom control maken==
In het vorige hoofdstuk zag je dat je voor een user-control een .ascx-bestand gebruikt. Voor een custom control maak je een .vb-bestand (of .cs als je met C# werkt).
Alles wat je moet doen om een simpele custom control te maken is een klasse aanmaken die afgeleid is van Control (of WebControl) en de Render()-methode daarvan te overschrijven.
De Render()-methode heeft één argument van type System.Web.UI.HtmlTextWriter. De HTML die je control naar de client wil sturen moet doorgegeven worden als een string naar de Write()-methode van HtmlTextWriter.
Kies File-New File in Visual Web Developer, en kies vervolgens Class en geef het bestand de naam simpel.vb. Merk op dat er voor dit bestand een folder App_Code aangemaakt wordt. Alle custom controls (en klasses) komen automatisch in deze folder terecht.
Het volgende voorbeeld toont een simpele control die een boodschapstreng rendert.
''simpel.vb''
<syntaxhighlight lang="vbnet">
Imports System
Imports System.Web
Imports System.Web.UI
Namespace Wikibooks
Public Class Simpel : Inherits Control
Protected Overrides Sub Render(writer As HtmlTextWriter)
writer.Write("<H2>Welkom bij Wikibooks!</H2>")
End Sub
End Class
End Namespace</syntaxhighlight>
In de pagina moet je nu de control registreren ongeveer zoals bij een user control. Je moet een TagPrefix opgeven en een Namespace. De control wordt automatisch opgezocht in de folder App_Code via de namespace.
''simpel.aspx''
<syntaxhighlight lang=html4strict><%@ Page Language="VB" %>
<%@ Register TagPrefix="cc1" Namespace="Wikibooks" %>
<html>
<head>
<title>Simpele custom control</title>
</head>
<body>
<form runat="server">
<cc1:Simpel id="MijnControl" runat=server/>
</form>
</body>
</html></syntaxhighlight >
==Een assembly maken==
Om een control aan de toolbox toe te voegen moet hij eerst gecompileerd worden. Bij het compileren wordt de code omgezet in een zogenaamd assembly-bestand met extensie .dll (dynamic link library) in de bin-folder.
Maak een tekstbestand en noem het maaksimpel.bat.
''maaksimpel.bat''
<pre>SET source=App_Code\simpel.vb
SET target=bin\EenvoudigeControls.dll
SET assemblies=system.dll,system.web.dll
SET compiler=%WINDIR%\Microsoft.NET\Framework\v2.0.50727
MKDIR bin
%COMPILER%\vbc /t:library /out:%target% /r:%assemblies% %source%
PAUSE</pre>
(controleer wel of de versie van het framework 2.0.50727 overeenstemt met die op jouw server)
Hierin is:
{| {{Wikitable}}
|-
|source||de naam van het bronbestand met de code
|-
|target||de naam (en het pad) van de assembly die moet gemaakt worden
|-
|assemblies||de modules die je nodig hebt om de code te compileren (als je bijvoorbeeld ook databanken gebruikt, moet je hier nog system.data.dll aan toevoegen). In de Helpmodule van je editor kan je opzoeken tot welke assembly een bepaald object behoort.
|-
|compiler||de locatie van de Visual Basic compiler (vbc.exe) op jouw computer
|-
|pause||niet verplicht, maar zorgt ervoor dat het venster niet onmiddellijk sluit, zodat je eventuele fouten nog kan lezen.
|}
Dubbelklik in Windows Explorer op dit bestand om het uit te voeren. Het programma vbc (Visual Basic Compiler) zal nu het bestand simpel.vb compileren en de uitvoer EenvoudigeControls.dll wordt in een subfolder "bin" geplaatst. Eventuele fouten worden gemeld.
Onthoud dat telkens je wijzigingen aanbrengt in simpel.vb, je het bestand opnieuw moet compileren.
Voor andere compilaties moet je maaksimpel.bat kopiëren en aanpassen. Stel iedere keer "source" en "target" in op de juiste waarde.
Pas nu simpel.aspx aan, zodat die met de assembly werkt, en niet met de code in App_Code. De referentie Assembly="EenvoudigeControls" in simpel.aspx moet verwijzen naar deze assembly (zonder de DLL-extensie, en zonder bin). Verwijder het bestand simpel.vb uit de App_Code-folder, anders krijg je nu een conflict.
''simpel.aspx''
<syntaxhighlight lang=html4strict ><%@ Page Language="VB" %>
<%@ Register TagPrefix="cc1" Namespace="Wikibooks"
Assembly="EenvoudigeControls" %>
<html>
<body>
<form method="POST" action="Simpel.aspx" runat=server>
<cc1:Simpel id="MijnControl" runat=server/>
</form>
</body>
</html></syntaxhighlight>
ASP.NET zoekt automatisch naar alle dll's in de bin-folder (en alleen daar).
Eenmaal de control gecompileerd is kan je hem toevoegen aan de toolbox in Visual Studio. Klik rechts op de toolbox, en kies "Choose items...". Blader naar je dll en voeg hem toe.
Als je deze control nu in een ander project op een pagina sleept, zal Visual Studio automatisch op dat moment de dll ook kopiëren naar de bin-folder van die applicatie.
Let op: als je achteraf de dll wijzigt, moet je de bijgewerkte dll zelf kopiëren naar de applicaties die ze gebruiken.
==Eenvoudige property's geven aan de control==
We werken hier weer met getters en setters omdat ze toelaten data te verbergen en ze worden ondersteund door visuele designers zoals Visual Studio.
Het volgende voorbeeld toont hoe je simpele property's toevoegt. Het voorbeeld maakt een property Grootte met het type Integer.
''simpelproperty.vb''
<syntaxhighlight lang=vbnet>Imports System
Imports System.Web
Imports System.Web.UI
Namespace Wikibooks
Public Class SimpelProperty : Inherits Control
Private _grootte As Integer
Public Property Grootte As Integer
Get
Return _grootte
End Get
Set
_grootte = Value
End Set
End Property
Protected Overrides Sub Render(writer As HtmlTextWriter)
writer.Write("<H" & _grootte & ">Wikibooks</H" & _grootte & ">")
End Sub
End Class
End Namespace</syntaxhighlight>
''simpelproperty.aspx''
<syntaxhighlight lang=html4strict><%@ Page Language="VB" %>
<%@ Register TagPrefix="cc1" Namespace="Wikibooks" %>
<html>
<head>
<title>Simpele custom control</title>
</head>
<body>
<form runat="server">
<cc1:SimpelProperty Grootte="3" runat="server" />
</form>
</body>
</html></syntaxhighlight>
Als je deze control toevoegt aan je pagina, dan kan je de property Grootte terugvinden in het Property Panel.
===Oefeningen===
#Maak een control die een horizontale balkgrafiek produceert door een afbeelding te herhalen of uit te rekken. De lengte van de grafiek is een property.
==Een samengestelde control maken==
Je kan nieuwe controls ontwerpen door bestaande controls samen te voegen.
Een typisch voorbeeld is een zogenaamde "spin"- of "up-down"-control.
Dit is een control waar je een getal kan invoeren door het in te tikken, of door het in te stellen met twee knoppen: "omhoog" en "omlaag". Deze control bestaat uit 3 bestaande controls: één invoervak en twee knoppen.
Samengestelde controls komen overeen met user-controls die ontworpen worden met ASP.NET-pagina-syntax. Het grootste verschil tussen user-controls en samengestelde controls is dat user-controls bewaard worden als .ascx tekstbestanden, terwijl samengestelde controls gecompileerd worden en daarna bewaard worden in assembly's.
De stappen in het ontwerp van een samengestelde control zijn:
*Overschrijf de <code>CreateChildControls</code>-methode (overgeërfd van Control) om instanties aan te maken van de benodigde child-controls en voeg deze instanties toe aan de Controls-collectie.
*Als je samengestelde control meerdere keren kan voorkomen op dezelfde pagina, en je control bevat bijvoorbeeld een tekstvak, dan bestaat er het gevaar dat je op die pagina meerdere tekstvakken krijgt met dezelfde ID. Om dit te vermijden moet je de System.Web.UI.INamingContainer-interface implementeren (zie het voorbeeld hieronder). Wanneer die interface wordt gebruikt door een control, zal het ASP.NET-pagina-framework automatisch nieuwe namen geven aan de child-controls.
Je moet de Render()-methode hier niet overschrijven, omdat de child-controls de rendering voor hun rekening nemen. Je kan property's maken die op hun beurt property's van de child controls bepalen.
Het volgende voorbeeld maakt een samengestelde control, Samengesteld1, die een LiteralControl combineert met een TextBox.
Samengesteld1 stelt een eigen property, Waarde, van type Integer, ter beschikking die een string doorsluist van en naar de Text-property van TextBox.
''samengesteld1.vb''
<syntaxhighlight lang=vbnet>Imports System
Imports System.Web
Imports System.Web.UI
Imports System.Web.UI.WebControls
Namespace Wikibooks
Public Class Samengesteld1 : Inherits Control : Implements INamingContainer
Public Property Waarde As String
Get
Me.EnsureChildControls()
Dim tb1 As TextBox = Me.FindControl("tb1")
Return tb1.Text
End Get
Set
Me.EnsureChildControls()
Dim tb1 As TextBox = Me.FindControl("tb1")
tb1.Text = Value
End Set
End Property
Protected Overrides Sub CreateChildControls()
' maak hier de child-controls aan
Dim lbl1 As New Label()
lbl1.Text = "Waarde"
Me.Controls.Add(lbl1)
Dim tb1 As New TextBox()
tb1.Text = "0"
tb1.ID="tb1"
Me.Controls.Add(box)
End Sub
End Class
End Namespace</syntaxhighlight>
''samengesteld1.aspx''
<syntaxhighlight lang=html4strict><%@ Page Language="VB" %>
<%@ Register TagPrefix="cc1" Namespace="Wikibooks" %>
<script language="VB" runat=server>
Private Sub VerhoogBtn_Click(Sender As Object, E As EventArgs)
MijnControl.Waarde = MijnControl.Waarde + 1
End Sub
</script>
<html>
<head>
<title>Samengestelde custom control</title>
</head>
<body>
<form runat="server">
<cc1:Samengesteld1 id="MijnControl" Waarde="0" runat="server" />
<br>
<asp:button text="Verhoog" OnClick="VerhoogBtn_Click" runat=server/>
</form>
</body>
</html></syntaxhighlight>
===Oefening===
#Maak een nummervak-control, dit is een tekstbox waar je alleen cijfers kan invullen. Gebruik een tekstvak samen met een validatorcontrol. Zorg ook dat het cijfer rechts uitgelijnd is.
==Events verwerken in een samengestelde control==
Een samengestelde control kan events verwerken die veroorzaakt worden door zijn child controls. Dit gebeurt door event handling-methodes te voorzien voor de events die door de child controls opgewekt worden.
In de volgende samengestelde control, Samengesteld2, zit de verhoogknop in de samengestelde control zelf. Daarom moet de samengestelde control ook zelf de event handling-methode voorzien voor het Click-event van de knop. Deze methode verhoogt de property Waarde van Samengesteld2.
Je kan deze handler niet koppelen aan de knop op de normale manier, met een OnClick-attribuut in de tag, want er zijn hier geen tags. In de plaats daarvan wordt AddHandler gebruikt in de CreateChildControls()-methode.
Het eindresultaat is een control die zijn eigen eventverwerking doet. Wanneer de Verhoog knop aangeklikt wordt, wordt de waarde in het tekstvak verhoogd.
''samengesteld2.vb''
<syntaxhighlight lang=vbnet>Imports System
Imports System.Web
Imports System.Web.UI
Imports System.Web.UI.WebControls
Namespace Wikibooks
Public Class Samengesteld2 : Inherits Control : Implements INamingContainer
Public Property Waarde As Integer
Get
Me.EnsureChildControls()
Dim tb As TextBox = CType(Me.FindControl("tb1"),TextBox)
Return CInt(tb.Text)
End Get
Set
Me.EnsureChildControls()
Dim tb As TextBox = CType(Me.FindControl("tb1"),TextBox)
tb.Text = CStr(Value)
End Set
End Property
Protected Overrides Sub CreateChildControls()
Dim tb As New TextBox()
tb.Text="0"
tb.Style("text-align")="right"
tb.ID="tb1"
Me.Controls.Add(tb)
Dim btn As New Button()
btn.Text="Verhoog"
Me.Controls.Add(btn)
AddHandler btn.Click, AddressOf btn_Click
End Sub
Private Sub btn_Click(Sender As Object,e As EventArgs)
Dim tb As TextBox = CType(Me.FindControl("tb1"),TextBox)
tb.Text = tb.Text + 1
End Sub
End Class
End Namespace</syntaxhighlight>
''samengesteld2.aspx''
<syntaxhighlight lang="HTML"><%@ Page Language="VB" %>
<%@ Register TagPrefix="cc1" Namespace="Wikibooks" %>
<html>
<head>
<title>Samengestelde custom control</title>
</head>
<body>
<form runat="server">
<cc1:Samengesteld2 id="MijnControl" Waarde="0" runat=server/>
</form>
</body>
</html></syntaxhighlight>
===Oefeningen===
#Maak een uitklapbaar panel. Normaal zie je een linkbutton "meer info". Als je erop klikt, zie je meer informatie en verandert de link in "minder info".
==Eigen events opwekken vanuit een samengestelde control ==
In het vorige voorbeeld verwerkte de samengestelde control zelf de events van zijn child-controls. Misschien wil je ook in de pagina deze events nog verder verwerken, of wil je een nieuw event maken waarop de pagina kan reageren.
Een samengestelde control kan eigen events hebben, die de control zelf opwekt als gevolg van events die door zijn child controls doorgegeven worden.
Het volgende voorbeeld toont een samengestelde control, Samengesteld3, die een custom event opwekt, Change, als antwoord op de Click-event van de Button-child-control.
Net zoals we reeds zagen bij de [[Programmeren in ASP.NET/User-controls|user-control]], voeg je een Change-event toe, en een protected OnChange-methode.
Verder roep je OnChange op als er op de knop geklikt wordt.
''samengesteld3.vb''
<syntaxhighlight lang=vbnet>Imports System
Imports System.Web
Imports System.Web.UI
Imports System.Web.UI.WebControls
Namespace Wikibooks
Public Class Samengesteld3 : Inherits Control : Implements INamingContainer
Public Property Waarde As Integer
Get
Me.EnsureChildControls()
Dim tb As TextBox = CType(Me.FindControl("tb1"),TextBox)
Return CInt(tb.Text)
End Get
Set
Me.EnsureChildControls()
Dim tb As TextBox = CType(Me.FindControl("tb1"),TextBox)
tb.Text = CStr(Value)
End Set
End Property
Protected Overrides Sub CreateChildControls()
Dim tb As New TextBox()
tb.Text="0"
tb.Style("text-align")="right"
tb.ID="tb1"
Me.Controls.Add(tb)
Dim btn As New Button()
btn.Text="Verhoog"
Me.Controls.Add(btn)
AddHandler btn.Click, AddressOf Button1_Click
End Sub
Private Sub Button1_Click(Sender As Object,e As EventArgs)
Dim tb As TextBox = CType(Me.FindControl("tb1"),TextBox)
tb.Text = tb.Text + 1
OnChange(EventArgs.Empty)
End Sub
Public Event Change(Sender As Object, e As EventArgs)
Protected Sub OnChange(e As EventArgs)
RaiseEvent Change(Me,e)
End Sub
End Class
End Namespace</syntaxhighlight>
''samengesteld3.aspx''
<syntaxhighlight lang="HTML"><%@ Page Language="VB" %>
<%@ Register TagPrefix="cc1" Namespace="Wikibooks" %>
<script language="VB" runat=server>
Private Sub Samengesteld_Change(Sender As Object, E As EventArgs)
Label1.Text = "De waarde is veranderd!"
End Sub
</script>
<html>
<head>
<title>Samengestelde custom control</title>
</head>
<body>
<form runat="server" >
<cc1:Samengesteld3 id="MijnControl" Waarde="0"
OnChange="Samengesteld_Change" runat=server/>
<asp:Label id="Label1" runat="server" />
</form>
</body>
</html></syntaxhighlight>
Als je deze control toevoegt aan de toolbox in Visual Studio, komt het Change-event ook te voorschijn in de lijst met events die bij de control horen.
===Oefeningen===
#Maak een custom control die werkt zoals een checkbox, maar die dubbel zo groot is. Doe dit door je eigen afbeeldingen te gebruiken voor "aangekruist" en "niet aangekruist".
==Custom controls downloaden==
Op het Internet kan je custom controls vinden die je kan downloaden en zelf installeren op je toolbox. Sommige zijn gratis, anderen niet.
Een goede plaats om te zoeken is [https://www.asp.net www.asp.net] en vervolgens klikken op "Resources" en "Control Gallery".
{{Bladeren2
|Boek=Programmeren in ASP.NET
|vorige=User-controls
|huidige=Custom controls
|volgende=AJAX
}}
{{Sub}}
4scog1qlm1y92vebtx2go6rn29bdq11
Programmeren in ASP.NET/Viewstate
0
4820
428832
425791
2026-05-23T12:17:20Z
Erik Baas
2193
lf
428832
wikitext
text/x-wiki
{{Index Programmeren in ASP.NET}}
==Inleiding==
Viewstate is een belangrijk onderwerp om te begrijpen en voor veel gebruikers (in het bijzonder voor oud-gebruikers van ASP), is het waarschijnlijk de feature die hen het meest programmeerwerk zal uitsparen. Het gaat hier over het bijhouden van de toestand van de objecten op je webpagina's.
==Wat is viewstate?==
Veronderstel dat je iets online wilt kopen. Je hebt je naam, adres en betalingsinformatie ingevuld, en doorgestuurd. Je stuurt het formulier op, en de server antwoordt dat er een fout is en je moet teruggaan en streepjes toevoegen aan je telefoonnummer of een ander detail. Je klikt op de "Back"-knop in je browser en alles wat je invoerde is weer leeg! De site in kwestie heeft je viewstate niet bijgehouden.
Een paar jaar geleden merkte niemand dit op, maar als tegenwoordig je site niet gebruiksvriendelijk genoeg is, zullen je bezoekers eenvoudig ergens anders gaan. Dus in plaats van mensen verplichten terug te gaan en hun informatie opnieuw in te geven, is het beter ze automatisch terug te sturen, en ervoor te zorgen dat het formulier klaarstaat met alle informatie erin, gereed om te wijzigen.
Dankzij viewstate kan een [[Programmeren in ASP.NET/GridView|GridView]] ook na postback de gegevens nog steeds tonen, zonder opnieuw de databank te openen (als er geen wijzigingen zijn natuurlijk).
==Het basisformulier==
Hier is een basisformulier. Het doet niet echt veel. Je kan een naam invoeren en een kleur kiezen uit een lijst. Met deze gegevens wordt een zinnetje geproduceerd.
''form1.aspx''
<pre><%@ Page Language="VB" %>
<script runat="server">
Sub Page_Load(Sender as Object, E as EventArgs)
If Request.Form("tbNaam") <> "" Then
lblZin.Text = Request.Form("tbNaam") _
& " selecteerde " & Request.Form("ddlKleur")
End If
End Sub
</script>
<html>
<head>
<title>ASP.NET Viewstate voorbeeld #1</title>
</head>
<body>
<form action="form1.aspx" method="post">
Voer je naam in:
<input type="text" id="tbNaam" name="tbNaam" />
Kies een kleur:
<select id="ddlKleur" name="ddlKleur">
<option>Rood</option>
<option>Oranje</option>
<option>Geel</option>
<option>Groen</option>
<option>Blauw</option>
<option>Indigo</option>
<option>Violet</option>
</select>
<input type="submit" id="btnSubmit" value="Submit" />
</form>
<asp:label id="lblZin" runat="server" />
</body>
</html></pre>
Het werkt, maar na iedere indiening van het formulier verdwijnt de naam, en gaat de kleur weer naar rood.
==Met viewstate==
Nu je het gezien hebt op de klassieke manier, is hier de nieuwe ASP.NET manier:
''form2.aspx''
<pre><%@ Page Language="VB" %>
<script runat="server">
Sub btnSubmit_Click(Sender as Object, E as EventArgs)
lblSentence.Text = txtName.Text & " selecteerde " _
& ddlColor.SelectedItem.Text
End Sub
</script>
<html>
<head>
<title>ASP.NET Viewstate voorbeeld #2</title>
</head>
<body>
<form id="frmViewState" runat="server">
Typ je naam:
<asp:TextBox id="txtName" runat="server" />
Kies een kleur:
<asp:DropDownList id="ddlColor" runat="server">
<asp:ListItem>Rood</asp:ListItem>
<asp:ListItem>Oranje</asp:ListItem>
<asp:ListItem>Geel</asp:ListItem>
<asp:ListItem>Groen</asp:ListItem>
<asp:ListItem>Blauw</asp:ListItem>
<asp:ListItem>Indigo</asp:ListItem>
<asp:ListItem>Violet</asp:ListItem>
</asp:DropDownList>
<asp:button id="btnSubmit" text="Verzenden"
onClick="btnSubmit_Click" runat="server" />
</form>
<asp:label id="lblSentence" runat="server" />
</body>
</html></pre>
Deze keer wanneer je het formulier indient, behoudt het alle waarden bij elke update.
Merk op dat de twee pagina's bijna exact even lang zijn. Het ASP.NET-framework (en de server-controls) doet al het werk in de tweede. Je hoeft daarvoor zelf niets te doen.
==Hoe werkt het?==
ASP.NET voegt automatisch "viewstate" toe aan de pagina. Dit gebeurt via een verborgen formulierveld.
Als je de broncode van het tweede formulier bekijkt in je browser, zie je een regel die er ongeveer als volgt uitziet:
<input type="hidden" name="__VIEWSTATE"
value="dDwtMTA2Mzk5MTczNDt0PDtsPGk8Mz47PjtsPHQ8cDxwPGw8VGV4dDs+
O2w8Sm9obiBzZWxlY3RlZCBHcmVlbjs+Pjs+Ozs+Oz4+Oz6NaBGW1O3JUoxq0PX rlih3OZ2CTA==" />
Er werden line breaks toegevoegd om het leesbaar te houden.
De server zendt de staat van het formulier naar de client samen met het formulier zelf, in de vorm van dit verborgen veld. Het is belangrijk op te merken dat deze informatie niet op de server bewaard blijft en dat het niet gebeurt via ActiveX-controls of een Java-applet of een of andere client-side truc. De staat wordt behouden via standaard HTML.
==Nadelen van viewstate==
Het enige echte nadeel is de toename in de grootte van de pagina en het erop volgende POST-request. Dat kan de respons van de pagina vertragen.
Daarom kan (en moet) je altijd viewstate uitschakelen waar die niet nodig is.
Dit doe je eenvoudig door het EnableViewState="false"-attribuut toe te voegen.
Dit kan op meerdere niveaus, elk niveau kan het vorige overschrijven, en het is het dichtstbijzijnde niveau dat uiteindelijk telt.
{| {{Wikitable}}
|-
! Niveau van viewstate||waar uitschakelen||voorbeeld
|-
|één control||in de tag van de control||<pre><asp:DataGrid EnableViewState="false" ... /></pre>
|-
|één pagina||in het @Page-directief||<pre><%@Page EnableViewState="false" %></pre>
|-
|één toepassing||in web.config||<pre><pages enableViewState="false" /></pre>
|-
|volledige machine||in machine.config||<pre><Pages enableViewState="false" /></pre>
|}
Dit zijn gevallen waarbij viewstate zeker niet nodig is:
*als de pagina niet naar zichzelf terugpost. Viewstate werkt dan toch niet.
*wanneer alle eigenschappen van de controls in het formulier vast ingesteld blijven.
*wanneer alle eigenschappen van de controls in het formulier bij elke aanvraag toch opnieuw ingesteld worden.
==Variabelen behouden via viewstate==
Het gebeurt dikwijls dat je in je pagina of in je [[Programmeren in ASP.NET/User-controls|user-control]] zelf variabelen definieert. Zo wil je bijvoorbeeld bij een datagrid bijhouden of je bezig bent toe te voegen of te wijzigen, of je wil bij het verwijderen eerst nog een panel tonen om te bevestigen, waarbij je het nummer van het te verwijderen record wil bijhouden.
Normaal gaat de waarde van een variabele telkens verloren als de pagina opnieuw aangemaakt wordt.
Om deze waarde toch te behouden kan je ze bewaren in het Session-object, maar dat is eerder bedoeld om waarden door te geven aan andere pagina's.
Een betere oplossing is deze variabelen te bewaren in de viewstate. Dit doe je met behulp van het Viewstate-object, dat een eigenschap is van elke pagina (en van elke control).
Dit gaat gemakkelijk als je van de variabele een property maakt, en als je dan in de getters en setters de Viewstate gebruikt. Hier is een voorbeeld voor een boolean:
<pre> Property AddingNew() As Boolean
Get
Dim o As Object = ViewState("AddingNew")
If o Is Nothing Then
Return False
End If
Return CBool(o)
End Get
Set(Value As Boolean)
ViewState("AddingNew") = Value
End Set
End Property</pre>
Je kan dit ook gebruiken bij property's van usercontrols en custom controls, als je wil dat de waarde na postback automatisch behouden blijft.
Let op: in de expressie ViewState(“AddingNew”) is het woord “AddingNew” hoofdlettergevoelig!
{{Bladeren2
|Boek=Programmeren in ASP.NET
|vorige=AJAX
|huidige=Viewstate
|volgende=Configuratiebestanden
}}
{{Sub}}
krfy2618pu2daoel834s3wxn9co22u8
Programmeren in ASP.NET/Configuratiebestanden
0
4947
428831
425795
2026-05-23T12:17:19Z
Erik Baas
2193
lf
428831
wikitext
text/x-wiki
{{Index Programmeren in ASP.NET}}
Alle instellingen in ASP.NET gebeuren met behulp van configuratiebestanden. Dit zijn allemaal tekstbestanden en er zijn er verschillende:
{| {{Wikitable}}
|-
!Naam!!Locatie!!Bedoeling!!Geldig voor
|-
|web.config||in elke folder||instellingen voor alle code in die folder||de folder (en alle subfolders waar de instelling niet overschreven wordt)
|-
|global.asax||rootfolder||code om uit te voeren in events die gemeenschappelijk zijn voor de hele applicatie||de gehele applicatie
|-
|machine.config||binnen de Windows-folder||instellingen voor de hele machine (server)||alle applicaties op de machine
|}
Het bestand machine.config wordt hier verder niet besproken. Let op als je daar wijzigingen aanbrengt, want een vergissing kan je server helemaal in de war brengen!
==global.asax==
In de root van elke webapplicatie kan je een bestand met de naam global.asax plaatsen. Dit bestand bevat de code voor events die gemeenschappelijk zijn voor alle bestanden van de applicatie.
Dit bestand kan er bijvoorbeeld zo uitzien:
''global.asax''
<syntaxhighlight lang="asp"><%@ Application Language="VB" %>
<script runat="server">
Sub Application_Start(Sender As Object, E As EventArgs)
Application("bezoekers")=0
End Sub
Sub Application_End(Sender As Object, E As EventArgs)
End Sub
Sub Session_Start(Sender As Object, E As EventArgs)
Application("bezoekers")=Application("bezoekers")+1
Session.LCID=2067
End Sub
Sub Session_End(Sender As Object, E As EventArgs)
Application("bezoekers")=Application("bezoekers")-1
End Sub
</script></syntaxhighlight>
Je merkt dat het bestand code bevat, met enkele subroutines. Deze subroutines hebben vaste namen, en het zijn eigenlijk events. Ze worden op bepaalde momenten automatisch opgeroepen door de applicatie.
In de lijst hieronder vind je enkele van de beschikbare event procedures:
''Event procedures in Global.asax''
{| {{Wikitable}}
|-
!Event Procedure!!Beschrijving
|-
|Application_Start||Wordt uitgevoerd wanneer de toepassing start op de server. Dit event kan maar één maal opgeroepen worden.
|-
|Application_End||Wordt uitgevoerd wanneer de toepassing beëindigd wordt. Wordt gebruikt om indien nodig op te ruimen.
|-
|Application_Error||Wordt uitgevoerd wanneer een fout optreedt in de toepassing
|-
|Session_Start||Wordt uitgevoerd wanneer een nieuwe gebruiker op de website binnenkomt
|-
|Session_End||Wordt uitgevoerd wanneer een gebruikerssessie afgesloten wordt door de gebruiker of door een time-out
|-
|Application_AuthenticateRequest||Wordt uitgevoerd wanneer een beveiligingsmodule de identiteit van de gebruiker vaststelt
|-
|Application_AuthorizeRequest||Wordt uitgevoerd wanneer een beveiligingsmodule de gebruikersrechten controleert
|-
|Application_BeginRequest||Wordt uitgevoerd wanneer ASP.NET start met het verwerken van een request, vooraleer het andere per-request-events verwerkt
|-
|Application_Disposed||Wordt uitgevoerd wanneer ASP.NET de uitvoering voltooit bij het beantwoorden van een request
|-
|Application_EndRequest||Wordt uitgevoerd als laatste event na het verwerken van een request na alle andere pre-request-events
|-
|Application_PreSendRequestContent||Wordt uitgevoerd net voor ASP.NET inhoud naar de client stuurt
|-
|Application_PreSendRequestHeaders||Wordt uitgevoerd net voor ASP.NET HTTP headers naar de client stuurt
|}
Geen enkele van deze events is verplicht. Als je ze niet declareert, dan wordt het event gewoon zonder meer uitgevoerd.
==web.config==
Een tweede manier om je website in te stellen is via een speciaal bestand in je website, web.config. Dit is een XML-bestand waarin alle instellingen staan die van belang zijn voor je website. Je hoeft dus geen instellingen te doen in de webserver zelf (zoals onder andere bij ASP het geval is). Omdat het een XML-bestand is, kan je het gewoon met Notepad wijzigen.
Voorbeelden van instellingen zijn:
*waarden geven aan constanten die in meerdere pagina's gebruikt worden
*connectiestrengen instellen
*eigen 404-foutpagina's
*aanmelding
*taalinstellingen
*gebruikersrechten
*compilatie-opties
*tracing
*debugging
*enz...
Als je in Visual Studio een web.config-bestand maakt (door daarvoor te kiezen in het New File venster), dan krijg je een bestand met daarin al een hoop uitleg over de verschillende onderdelen van het bestand en de belangrijkste instellingen die je kunt doen.
ASP.NET voorziet een veilige manier om web.config te wijzigen. Ga naar Control Panel-Administrative Tools-Internet Information Services (de configuratie van IIS), rechts-klik op je applicatie en kies properties. Onder de klep “ASP.NET” kan je via “Edit configuration” de instellingen wijzigen.
Op je eigen pc kan je sommige instellingen ook vanuit Visual Studio aanpassen. Kies in het menu Website-ASP.NET configuration-Application.
Alle opties die in een website niet ingesteld zijn worden automatisch overgenomen uit een centrale configuratie voor alle websites op de computer, machine.config. Systeembeheerders kunnen dat bestand eventueel aanpassen om de basisconfiguratie van alle websites aan te passen, en sommige mogelijkheden voor afzonderlijke websites te verbieden.
==Structuur==
De root van het XML-bestand is de <configuration>-tag.
De basisstructuur voor een web.config bestand zie je hieronder.
<syntaxhighlight lang="xml"><?xml version="1.0" encoding="UTF-8" ?>
<configuration>
<connectionStrings>
<add name="string1" connectionString="waarde"
providerName="System.Data.SqlClient" />
<!--meer...-->
</connectionStrings>
<appSettings>
<add key="naam" value="waarde"/>
<!--meer...-->
</appSettings>
<system.web>
<!--hier website instellingen-->
</system.web>
</configuration></syntaxhighlight>
De configuratie voor een website bestaat in feite uit drie delen, <connectionStrings>, <appSettings> en <system.web>.
Het <connectionStrings>-element geeft de mogelijkheid om connectiestrings in te stellen voor de hele web site.
Hierin kan je strings toevoegen door de <add ... /> tag te gebruiken.
Zo kun je bijvoorbeeld de verbindingsstreng voor de database hierin opslaan, zoals ook in het voorbeeld in de web.config die Visual Studio maakt.
<syntaxhighlight lang="xml"><connectionStrings>
<add name="connString"
connectionString="Provider=Microsoft.Jet.OLEDB.4.0;blablabla"
providerName="System.Data.OleDb" />
</connectionStrings></syntaxhighlight>
Als je deze wilt gebruiken in een pagina, kan je ze met de volgende code opvragen en in een variabele plaatsen:
Dim strAdres As String = ConfigurationManager.ConnectionStrings("connString").ConnectionString
Declaratief kan je ze ook opvragen:
ConnectionString="<%$ ConnectionStrings:connString %>"
Het <appSettings>- element geeft de mogelijkheid om waardes of instellingen in de website beschikbaar te maken onder bepaalde namen voor de hele folder.
Hierin kan je instellingen toevoegen door de <add ... /> tag te gebruiken.
Zo kun je bijvoorbeeld het e-mail-adres van de administrator instellen:
<syntaxhighlight lang="xml"><appSettings>
<add key="adresAdmin" value="admin@mijnsite.be" />
</appSettings></syntaxhighlight>
Als je dit adres wilt gebruiken in een pagina, kan je dit met de volgende code opvragen en in een variabele plaatsen:
Dim strAdres As String = ConfigurationManager.AppSettings("adresAdmin")
Declaratief kan je het ook opvragen:
Text="<%$ AppSettings:adresAdmin %>"
Het voordeel hiervan is natuurlijk dat je deze instelling maar op één plaats moet wijzigen, maar dat de wijziging ineens voor alle pagina's geldt. De pagina's moeten zelfs niet opnieuw gecompileerd worden, ze halen de nieuwe waarde automatisch op.
Het gedeelte <system.web> bevat de daadwerkelijke instellingen van de website. Voor de verschillende instellingen zijn er aparte elementen die alleen bepaalde waardes kunnen hebben.
Wijzigingen in web.config worden opgepikt zodra de eerstvolgende pagina opgevraagd wordt.
'''Opmerkingen'''
*Elke wijziging in web.config doet de applicatie herstarten. Dit betekent onder andere dat op dat moment alle gebruikers hun Session-instellingen verliezen.
*Zoals alle XML-bestanden is web.config hoofdlettergevoelig.
*Zoals bij alle XML-bestanden heeft witte ruimte geen belang.
Voor meer informatie over deze instellingen:
https://msdn.microsoft.com/library/en-us/cpguide/html/cpconaspnetconfiguration.asp
Een volledige beschrijving van alle elementen die mogelijk zijn vind je hier:
https://msdn.microsoft.com/library/en-us/cpgenref/html/gngrfaspnetconfigurationsectionschema.asp.
==Delen van een website instellen==
Bepaalde instellingen die je met web.config kan doen kan je ook toepassen op slechts een deel van de website. In iedere subfolder van de website kan je een web.config bestand plaatsen met daarin instellingen voor die subfolder. Instellingen die niet gemaakt worden in die subfolder, worden overgenomen van de instellingen die gelden voor een folder hoger.
Je kunt dus voor iedere subfolder in de website bepaalde instellingen overschrijven. Een voorbeeld hiervan zie je hier: https://www.microsoft.com/netherlands/msdn/aspnet/security.asp.
Bovendien kan je sommige instellingen ook nog eens per pagina overschrijven. Dit doe je dan in het Page-directief van die pagina. Deze instellingen hebben dus voorrang op de instellingen in web.config.
Dit is de orde van voorrang (hoe meer naar rechts hoe meer voorrang):
machine.config -> web.config root -> web.config subfolder -> Page-directief
Let er wel op dat sommige instellingen alleen in web.config van de rootfolder gedaan kunnen worden (zoals bv. het soort authenticatie). Je krijgt een foutmelding als je deze instelling toch in een submap van de website probeert te gebruiken.
==Een virtuele map maken==
Binnen IIS (Internet Information Server) kan je virtuele directory's aanmaken. Een virtuele directory werkt als een snelkoppeling naar een bepaalde folder (die zelfs niet binnen wwwroot hoeft te staan). Bovendien kan je in IIS vele instellingen (zoals beveiliging, default document, enz...) per virtuele directory instellen.
Voorbeeld:
*Maak in de map My Documents een map om je ASPX-bestanden in te zetten, bijvoorbeeld MijnASP.
*Open Control Panel-Administrative Tools-Internet Information Services
*Selecteer het snelmenu van de default Web Site en kies New, Virtual Directory. De Virtual Directory Creation Wizard start op.
*Geef als alias "virtueel" en blader naar de folder MijnASP op je harde schijf. Selecteer de Read- en Script-permissons
*Kopieer een testbestand test.aspx in MijnASP
*Open je browser en typ in: https://localhost/virtueel/test.aspx
*Als het goed is zie je de pagina.
Normaal gezien kan je webserver alleen pagina's tonen die binnen wwwroot staan, maar dankzij de virtuele directory zijn andere folders ook te bereiken (bijvoorbeeld bestanden die in My Documents staan).
Merk op dat de echte folder MijnASP heet, maar in de URL moet je de alias "virtueel" gebruiken!
Je zou ook een folder "virtueel2" kunnen maken binnen wwwroot, en die dan ook nog eens instellen als virtuele folder "virtueel2". De virtuele directory verwijst dan niet naar een andere folder, maar het voordeel is dat die folder zijn eigen instellingen kan hebben binnen de website. Soms is dit nodig. Als het geen virtuele folder is, neemt de folder de instellingen over van de "default website" in IIS.
==De website overzetten op de productieserver==
Het overzetten van je website van de ontwikkelserver naar de productieserver is heel eenvoudig. Het enige dat je moet doen is alle bestanden die je gemaakt hebt kopiëren naar de productieserver. Je kan dit doen met FTP.
Je moet ook alle submappen (bin, images, enz...) kopiëren naar dezelfde submappen op de server (men noemt dit ook wel de XCOPY-overdracht).
'''Let op:''' databanken zoals MSDE en SQL Server 2000 bewaren hun bestanden apart, niet binnen de gewone wwwroot. Je kan deze bestanden niet gewoon kopiëren. Deze databanken moet je zelf aanmaken (of laten aanmaken) op de productieserver met behulp van SQL-commando's. Volg daarvoor de instructies van de hostingfirma. SQL Server 2005 ondersteunt wel de XCOPY-overdracht.
{{Bladeren2
|Boek=Programmeren in ASP.NET
|vorige=Viewstate
|huidige=Configuratiebestanden
|volgende=Webservices
}}
{{Sub}}
tb38yjfx01fzhquq0gae4kmjr3mj4qt
Sociale geschiedenis van de late middeleeuwen/Kleding en sieraden
0
21825
428838
353744
2026-05-24T02:52:45Z
Oursana
12605
/* Studenten en scholieren */ -+Konrad Witz - The Queen of Sheba before Solomon (c. 1435).jpg
428838
wikitext
text/x-wiki
{{Sociale geschiedenis van de late middeleeuwen}}
<span style="font-size: large;">'''14. Kleding en sieraden'''</span>
==Kleding en positie==
Mensen die in de middeleeuwen bloot op straat liepen waren ofwel krankzinnig ofwel uit de maatschappij verstoten. In de literatuur werden weliswaar de [[w:wildeman|wildeman]], het [[w:wolfskind|wolfskind]], de [[w:weerwolf|weerwolf]] en de dolende, van zijn zinnen beroofde ridder beschreven, die naakt in het woud der begeerten leefden, maar deze verhalen waren gefantaseerd en bedoeld om de adel te vermaken.<ref>[[Sociale geschiedenis in de literatuur/Het lichaam#Verhalen over naakte mannen|Verhalen over naakte mannen]].</ref><ref>[[Sociale geschiedenis in de literatuur/Het lichaam#Verhalen over naakte kinderen|Verhalen over naakte kinderen]].</ref>
[[Afbeelding:Jewish man - worms - 16th century.jpg|thumb|120px|left|Jood met jodenring, 16de eeuw]]
De middeleeuwse indeling in [[w:Standensamenleving in de middeleeuwen|adel, geestelijkheid en volk]] bestond nog wel, maar door de ontwikkeling van de steden waren er binnen de stadsbevolking (burgers) veel onderverdelingen ontstaan: van rijke producenten tot arme arbeiders. De rijkste producenten konden zich gewapende beschermers veroorloven en voelden zich meer verbonden met de [[w:patriciër|stadspatriciërs]] en de adel dan met de arbeiders en het huispersoneel. Er was enige mobiliteit tussen deze onderverdelingen van de burgerstand: mensen konden wel eens een (paar) stapje(s) stijgen op de maatschappelijke ladder doordat ze rijk werden, of door een gunstig huwelijk. Soms daalden ze ook op de ladder door ziekte of een ongeluk. Persoonlijk succes werd verheerlijkt en iedereen streefde ernaar.
Maar de autoriteiten vonden dat de plaats van elke mens vastlag in een door God geschapen orde, of die mens nu een vorst was of een bedelaar. In stadsvergaderingen, processies en optochten had elk deel van het volk zijn eigen plaats met zijn eigen kleding van een bepaalde vorm en kleur. Maar veel ambachtslieden waren rijk geworden en zij wilden net zulke mooie en dure kleren en juwelen dragen als de stadspatriciërs en de adel. Mede daarom vaardigden de stadsbesturen in de veertiende en vijftiende eeuw strenge weeldeverordeningen uit<ref>[[Sociale geschiedenis van Toscane (1300-1500)/Stadsbestuur|Punt 7: weeldeverordeningen.]]</ref>: de mensen mochten niet arrogant zijn en geen kleding dragen die boven hun stand was.
Ieder beroep en iedere bevolkingsgroep had zijn eigen kleding. <br>
1) Een [[w:Venetië (stad)|Venetiaanse]] senator droeg zwarte kleding. <br>
2) Een Jood droeg een [[w:Jodenhoed|Jodenhoed]] en een [[w:Jodenring|gele Jodenring]].<ref>[[Sociale geschiedenis van de hoge middeleeuwen/Kerk#De kerk en haar tegenstanders|Joden droegen een gele ring en een jodenhoed.]]</ref> <br>
3) Een [[w:prostitutie|prostituee]] droeg een gele jurk. <br>
===Inventarisaties===
In notariële inventarisaties en rekeningen van de veertiende en vijftiende eeuw werd vaak kleding beschreven. Ook op schilderijen werd uiteraard veel kleding afgebeeld, maar daarbij moet worden bedacht dat de meeste afgebeelde personen waarschijnlijk hun beste en mooiste kleding aanhadden als ze zich lieten schilderen.
==Bedelaars==
[[Bestand:Gentile da Fabriano 020.jpg|thumb|120px|left|[[w:Gentile da Fabriano|Gentile da Fabriano]], bedelaar, 1423]]
Bedelaars, keuterboertjes en de laagste ambachtslieden en winkeliers droegen vaak tweedehandse kleding waar een levendige handel in was. Kleding werd gedragen totdat ze tot op de draad versleten was en dan nog werden de "goede" stukken eruit geknipt om eventueel in een ander kledingstuk genaaid te worden.
===Boeren===
We weten iets van de kleding die boeren en boerinnen droegen uit de inventarisaties die notarissen na hun overlijden maakten. Hun basiskleding bestond uit drie delen: <br>
1) Een overkleed. Vrouwen droegen een [[w:fr:Robe (vêtement)|robe]] in plaats van een overkleed. <br>
1a) De mannen droegen ook nog een broek, hoewel wij die broek eerder een [[w:Maillot (kledingstuk)|maillot]] zouden noemen. <br>
2) Een pelsjas: een jas van dierenvellen of konijnenbont waarbij de harige zijde aan de binnenkant gedragen werd.<ref>[[Sociale geschiedenis van de vroege middeleeuwen/Kleding en verzorging#Kleding|In de winter droegen alle boeren dierenhuiden, maar met de harige zijde aan de binnenkant.]]</ref> Bij de rijken was het bovenstuk gevoerd met kattenbont. <br>
3) Een hoed of kap. De vrouwen droegen een [[w:linnen|linnen]] kap die meestal rood was, soms blauw of wit. De kappen van de mannen waren meestal blauw. <br>
Soms ontbreekt een van die kledingsstukken in de inventarisatie. Dan is dat stuk waarschijnlijk verkocht om de begrafenis van te betalen.
Mannen en vrouwen droegen baaien kleren (dik en grof [[w:wol|wollen]] weefsel dat op [[w:molton|molton]] leek). Die stof was van middelmatige kwaliteit maar wel warm. Voor de mannen was die stof ongebleekt (beige) en voor de vrouwen vaak blauw.
Men droeg ook nog ondergoed: linnen hemden en manshemden met twee pijpen.
In [[w:Toscane|Toscane]] droeg men in die tijd twee [[w:Tunica (Rome)|tunieken]] over elkaar heen en daarover eventueel nog een mantel.<ref>[[Sociale geschiedenis van Toscane (1300-1500)/Kleding|Kleding in Toscane.]] </ref>
Op het platteland werd de rijkdom afgemeten aan het aantal kledingsstukken dat men bezat en de mate waarin die versierd waren. Die versieringen werden door [[w:marskramer|marskramer]]s naar het platteland gebracht. Zilveren ceintuur- en schoengespen, metalen sluitingen voor beurzen en knopen voor de kappen. Over het algemeen echter waren sieraden op het platteland zeldzaam behalve ringen. Een rijke boerin kon wel vijf hoeden beziten. Als een boer handschoenen droeg, liep het hele dorp uit om ze te bewonderen. Een jonge boer droeg ze wel eens als hij een vrouw het hof wilde maken.
<gallery>
File:Hieronymus Bosch- The Seven Deadly Sins and the Four Last Things - Gluttony.JPG|[[w:Jheronimus Bosch|Hiëronymus Bosch]], boeren die zich volvreten, 1485, olie op hout
File:Pieter Bruegel d. Ä. 014.jpg|[[w:Pieter Bruegel de Oude|Pieter Bruegel de Oude]], boerendans, 1568
File:Brueghel der Jüngere, Pieter - Bauernhochzeit (München, Alte Pinakothek).jpg|Pieter Bruegel de Oude, boerenbruiloft, 1567
File:Pieter Bruegel the Elder - Peasant Wedding - Google Art Project.jpg|Pieter Bruegel de Oude, boerenbruiloft, 1568
</gallery>
===Kleine burgerij===
De "populo minuto", "populi medio" of de "kleine burgerij" in de stad bestond uit: ambachtslieden, winkeliers en kleine handelaren. Deze mannen en vrouwen uit de werkende klasse droegen allemaal ongeveer dezelfde basiskleding, net als de boeren. Alleen het verschil tussen man en vrouw was goed te zien.
===Grote burgerij===
De "populo grasso" of "grote burgerij" bestond uit: bankiers, succesvolle en internationaal opererende kooplieden, rechtsgeleerden, notarissen, vermaarde artsen en hoge ambtenaren in dienst van de koning.<ref>Zoals: parlementsleden, heren van de rekenkamer, belastingontvangers en schatkistbewaarders.</ref> Zij waren behoorlijk rijk.
In de tijd van [[w:Dante|Dante]] (1265-1321) had de vrouw uit de grote burgerij nog tamelijk gewone kleding, ook al omdat in het [[w:Florence (stad)|Florence]] van voor 1300 er nog niet zoveel stoffen en sieraden te koop waren als na 1350.
Na 1350 wilden de rijke burgers hun vrouwen net zo uitdossen als de vrouwen van de adel en patriciërs en daarvoor waren zij bereid om diep in de buidel te tasten. Maar de stadsbesturen wilden dat iedereen gekleed was conform de maatschappelijke plaats die hem of haar door de [[w:Voorzienigheid Gods|Voorzienigheid Gods]] was toegewezen en daarom vaardigden zij in de veertiende en vijftiende eeuw de weeldeverordeningen uit.
Zo hadden de vrouwen van [[w:Bologna (stad)|Bologna]] op een gegeven moment twee dagen de tijd om hun gewaden voor te leggen aan een commissie. Als deze commissie de gewaden buitensporig duur vond in verhouding tot het gezinsbudget, dan werden zij in beslag genomen. Uit de beschrijvingen van deze "buitensporige" kleding kunnen wij nu veel informatie halen omtrent de galakleding van de grote burgerij in die tijd.
Wat de vrouwen van de grote burgerij niet mochten dragen, waren: zilveren knopen of sterren, koorden van gevlochten gouddraad, geborduurde stralen, bladeren of dieren, bontranden aan kragen en mouwen, opgenaaide [[w:parel|parels]] en edelstenen en afzettingen met [[w:fr:petit gris|petit gris]] (eekhoornbont). Ook mochten de stoffen van hun kleding niet geverfd zijn met dure pigmenten zoals [[w:karmijn|karmijn]] dat gemaakt was van [[w:schildluizen|schildluizen]].
Soms waren deze gala-gewaden dermate versierd dat de prijs van de stoffen en het loon voor het maken samen nog geen 30% van de totale prijs uitmaakten. De rest was voor de versierselen en die waren regelmatig een bedrag waard dat een goede metselaar in 140 dagen of meer verdiende.
*Een Toscaanse vrouw droeg ooit een hoed die meer gekost zou hebben dan een goede metselaar in vijf jaar aan loon ontving.<ref>[[Sociale geschiedenis van Toscane (1300-1500)/Kleding#Statiekleding|Een vrouw kon een hoed dragen die meer kostte dan een goede metselaar in vijf jaar aan loon ontving.]]</ref>
*Een meisje uit de [[w:Strozzi|Strozzi]]familie had in 1447 een [[w:guirlande|guirlande]] op haar trouwjurk laten maken met 100 pauwenogen, met goudkraaltjes, parels, geëmailleerde bloemen en vergulde bladeren, alles tezamen met een waarde waarvoor een geschoolde arbeider 500 dagen moest werken. <br>
Maar de [[w:it:Peruzzi|Peruzzi]]'s, de Strozzi's en de [[w:Medici|Medici]]'s hoefden hun kleren niet aan de commissie voor te leggen. Zij konden ze gemakkelijk betalen omdat zij in een door God beschikte hoge positie verkeerden.
Men kocht voornamelijk galakleding en sieraden voor huwelijken, openbare plechtigheden, als gift voor de bruidsschat of als geschenk. Men gebruikte zwart [[w:Lakenindustrie|laken]], [[w:fluweel|fluweel]], [[w:satijn|satijn]], [[w:Robijn (edelsteen)|robijnen]], [[w:diamant|diamanten]] en [[w:saffier|saffieren]]. Ondanks het bezit van dure galakleding was men in de meeste huishoudens van Florence heel zuinig. De garderobe werd maar spaarzaam vernieuwd. Een vrouw kreeg gemiddeld per vier jaar slechts drie nieuwe kledingstukken. In [[w:Parijs|Parijs]], in [[w:Venetië (stad)|Venetië]] en in de [[w:hanzestad|Hanzesteden]] van Duitsland was men in de veertiende en vijftiende eeuw wat royaler.
*Voor een doorsnee moeder werden de jurken vaak gemaakt van goedkope stof.
*De kleren van de jongens werden gemaakt van warme en dichtgeweven [[w:Stanford-universiteit|stanford]] voor in de winter en van rode [[w:fr:Serge (tissu)|serge]] voor in de zomer.
====Studenten en scholieren====
Het kwam geregeld voor dat men nieuwe kleren kocht voor een zoon als hij naar de universiteit ging, of als hij in de leer ging in een verre stad. Hij kreeg dan een pak van stevig laken van goede kwaliteit en comfortabele schoenen. Schoenen sleten snel en moesten (volgens rekeningen van rond 1520 die zijn gevonden) bijna elke vier maanden verzoold worden.
Ook schoolgaande kinderen kregen af en toe een nieuw pak: dit werd te groot gekocht en werd gedragen tot het te klein was geworden. Ook zo'n pak was niet zozeer mooi als wel sterk en warm: scholieren zaten nog niet in banken, maar vaak op de vloer.
<gallery>
File:Masaccio 030.jpg|[[w:Tommaso Masaccio|Tommaso Masaccio]], 1426
File:Jan van Scorel 004.jpg|[[w:Jan van Scorel|Jan van Scorel]], scholier, 1531
File:Konrad Witz - The Queen of Sheba before Solomon (c. 1435).jpg|[[w:Konrad Witz|Konrad Witz]], 1434
File:Vittore Carpaccio 039.jpg|[[w:Vittore Carpaccio|Vittore Carpaccio]], 1495, olie op linnen
</gallery>
===Vorsten===
[[Bestand:Pintoricchio 002a.jpg|thumb|120px|left|[[w:Paus Pius II|Paus Pius II]] en [[w:Frederik III van het Heilige Roomse Rijk|Frederik III]], [[w:Fresco (schilderterm)|fresco]] ca. 1505]]
Bij de kleding van vorsten is het soms moeilijk om het verschil te zien tussen hun statiekleding en dagelijkse kleding. Het verschil zat waarschijnlijk niet zozeer in de kostbaarheid van de stoffen als wel in de versieringen: geborduurde mouwen, met [[w:parel|parels]] afgezette [[w:Bef (kledij)|befjes]], ingewikkelde hoeden en statiemantels. Overigens zijn de minst kostbare kledingstukken waarschijnlijk in latere tijden uit de collecties verwijderd omdat men ze niet mooi genoeg vond.
==Kleding en leeftijd==
[[Bestand:Andrea Mantegna 083.jpg|thumb|right|120px|[[w:Andrea Mantegna|Andrea Mantegna]], 1474, fresco]]
De kleding die men droeg was mede afhankelijk van de leeftijd. <br>
1) Het eerste kledingstuk van de mens was de luier. <br>
2) In de jeugd droeg men sterke, grijze stoffen. <br>
3) In de puberteit kon men de buitensporige [[w:mode|mode]] dragen. <br>
4) In de volwassenheid droeg men rustige tinten. <br>
5) Op hoge leeftijd schuifelde de man in zijn [[w:tabberd|tabberd]] door het huis. <br>
==Mode: kleding voor pubers==
Met de mode meegaan betekende enerzijds: zich voegen naar de overheersende trend en anderzijds: zich van anderen onderscheiden. Pubers konden via hun kleding uiting geven aan hun persoonlijke gevoelens, voorkeuren en bedoelingen.
Mensen stegen nogal eens op de maatschappelijke ladder doordat ze rijk waren geworden. Omdat de heersende [[w:kastenstelsel|kasten]] zich wilden afsluiten voor deze [[w:Nouveau riche|parvenus]] (nieuwe rijken) volgden de modes elkaar in de loop van de vijftiende eeuw in steeds sneller tempo op. Wie dit niet kon bijbenen was ontmaskerd. Deze modes werden steeds uitzinniger: lichaamsvormen werden door opvulsels geaccentueerd, er werden plooien gebruikt en asymmetrische vormen. Statiekleding, vooral van de vrouwen, werd steeds weelderiger en kostbaarder. Men ging dure [[w:zijde (textiel)|zijde]] gebruiken, [[w:brokaat|brokaat]] en [[w:bont (huid)|bont]] en men omhing zich met zilver en goud.
Er ontstond een [[w:maniërisme|maniëristische]] mode die erop gericht was de charmes en kwaliteiten van de dragers ervan zo voordelig mogelijk te laten uitkomen.<ref>[[Sociale geschiedenis van Toscane (1300-1500)/Kleding#Statiekleding|Deze kleding was uitsluitend nog bedoeld om haar zo goed mogelijk te laten uitkomen en haar ster zo hoog mogelijk te laten rijzen.]]</ref> Deze charmes werden openlijk getoond of gesuggereerd. Jonge helden lieten hun spieren goed uitkomen.
Veel over de mode van de late middeleeuwen hebben we geleerd van het "Trachtenbuch" van [[w:Matthäus Schwarz|Matthäus Schwarz]]. Dit was een soort geschiedenis van het kostuum, geschreven ~1528.
<gallery>
Bestand:Masolino, resurrezione di tabita, dettaglio.jpg|[[w:Masolino da Panicale|Masolino]], fresco, 1426-27
Bestand:Cassone adimari (dettaglio) by lo scheggi, Galleria dell'Accademia, Firenze.jpg|[[w:it:Lo Scheggia|Lo Scheggia]], ca. 1445
Bestand:492px-Vittore Carpaccio 004 detail.jpg|[[w:Vittore Carpaccio|Vittore Carpaccio]], 1494, olie op linnen
Bestand:Bronzino - Eleonora di Toledo col figlio Giovanni - Google Art Project.jpg|[[w:Agnolo Bronzino|Agnolo Bronzino]], 1545, olie op hout
</gallery>
==Harnassen voor strijders==
De strijders droegen [[w:harnas|harnassen]] die uit vele, onderling beweegbare platen bestonden.<ref>[[w:en:Armour|Harnassen (Engelse Wikipedia)]]</ref><ref>[[w:de:Rüstung|Harnas (Duitse Wikipedia)]]</ref> Ook hier werd in de vijftiende eeuw het lichaam beklemtoond, de krijger kreeg door zijn harnas een krijgshaftig en arrogant uiterlijk.
<Gallery>
Bestand:Paolo Uccello 031.jpg|[[w:Paolo Uccello|Paolo Uccello]], 1439
Bestand:Andrea del Castagno 004.jpg|[[w:es:Andrea del Castagno|Andrea del Castagno]], 1450
Bestand:Johann Koerbecke Gefangennahme.jpg|[[w:de:Johann Koerbecke|Johann Koerbecke]], 1457
Bestand:Hans Memling 057.jpg|[[w:Hans Memling|Hans Memling]], 1480
Bestand:Albrecht Duerer- Paumgartner Altar - right wing.JPG|[[w:Albrecht Dürer|Albrecht Dürer]], 1503
Bestand:Francesco Granacci 002.jpg|[[w:Francesco Granacci|Francesco Granacci]], 1510
Bestand:Lucas Cranach d. Ä. 043.jpg|[[w:Lucas Cranach de Oude|Lucas Cranach de Oude]], 1520
</Gallery>
==Kleding voor vrouwen==
Verliefde jongemannen stelden zich op als arrogante goden. Ze veroverden een vrouw alsof het om een militaire expeditie ging. De jongedame uit de betere kringen beantwoordde dit veroveringsgedrag met een afgemeten houding. De jonge vrouw moest weliswaar aantrekkelijk zijn en zich laten veroveren (door een geschikte partij) maar ze mocht niet te snel haar discrete houding laten varen. In Duitsland zou dit liefdesspel mogelijk wat minder geraffineerd en pervers zijn geweest dan in Italië maar de Florentijnse meisjes werden kuis en waardig opgevoed net zoals de meisjes in Frankrijk en Duitsland.
Tegen het einde van de middeleeuwen volgde de vrouwenmode de mannenmode met enige vertraging. Bij de vrouwenkleding werd het accent op de taille gelegd, de schouders werden meer of minder ontbloot, het haar en de aanzet van de borsten werden ofwel met een sluier bedekt ofwel vrij gelaten. De vrouw droeg [[w:kant (textiel)|kanten]] zakdoekjes en op haar hoofd een [[w:kaproen|kap]] of een [[w:hennin|hennin]].
<gallery>
Bestand:Gentile da Fabriano 019.jpg|[[w:Gentile da Fabriano|Gentile da Fabriano]], 1423
Bestand:Meister des Jouvenel des Ursins 001 detail 1.jpg|[[w:de:Barthélemy d’Eyck|Barthélemy d’Eyck]], vrouw met hennin, 1460
Bestand:Carlo Crivelli 018.jpg|[[w:Carlo Crivelli|Carlo Crivelli]], 1470, tempera op hout
Bestand:Pedro Garcia de Benabarre St John Retable.jpg|[[w:es:Pedro García de Benavarre|Pedro Pedro García de Benavarre]], 1470-80
Bestand:Sandro Botticelli 040.jpg|[[w:Sandro Botticelli|Sandro Botticelli]], 1485-87, tempera op hout
Bestand:Young Woman with a Pink MET DT200206.jpg|[[w:Hans Memling|Hans Memling]], vrouw met hennin, 1485-90
</gallery>
==Weeldeverordeningen==
''Zie ook:'' [[Sociale geschiedenis van Toscane (1300-1500)/Huwelijk#Flirten|Flirten in Toscane]] <br>
''Zie ook:'' [[Sociale geschiedenis van Toscane (1300-1500)/Kleding#Statiekleding|Statiekleding in Toscane]] <br>
''Zie ook:'' [[Sociale geschiedenis van Toscane (1300-1500)/Stadsbestuur|Punt 7, weeldeverordeningen in Toscane]]
[[Bestand:Gothaer Liebespaar.jpg|thumb|120px|left|[[w:de:Meister des Hausbuches|Meister des Hausbuches?]], 1480]]
[[Bestand:Jakob Fugger und Sybille Artzt.JPG|thumb|150px|right|1500]]
In de veertiende en vijftiende eeuw vaardigden de stadsbestuurders strenge weeldeverordeningen uit om het dragen van buitensporige kleding door vrouwen tegen te gaan. Deze wetgeving kwam beslist mede voort uit [[w:misogynie|misogynie]] (vrouwenhaat) bij de stadsbesturen, maar het was ook een poging om iedereen op zijn/haar door God bepaalde plaats in de maatschappij te houden.
Zo gauw een meisje "huwbaar" was geworden (vaak al op haar zestiende), probeerden haar ouders via haar een goede huwelijkskandidaat binnen te halen. Ze hoopten op die manier een paar treetjes op de maatschappelijke ladder te kunnen stijgen. Zij werd dus mooi uitgedost om veel huwelijkskandidaten te lokken waaruit de ouders dan de "beste" gingen kiezen en doorgaans was dat een wat oudere man (vaak al tegen de dertig). Dat "mooi uitdossen" kon wel eens te ver gaan. De weeldeverordeningen dienden dan ook tevens om de uitgaven aan de kleding van de aanstaande bruid binnen de perken te houden. En ook wilden de stadsbesturen de uitgaven voor de [[w:bruidsschat|bruidsschat]] binnen de perken houden, want de concurrentie op de huwelijksmarkt was groot en daardoor waren deze twee uitgaveposten flink gestegen.
Als de burger echter eenmaal getrouwd en gevestigd was, hield hij er gauw mee op om zijn vrouw en zichzelf zo buitenissig en duur uit te dossen. Zijn jonge vrouw mocht zich dan binnenshuis niet meer optutten, alleen nog maar bij openbare feesten en plechtigheden. Ze mocht niet meer met zichzelf te koop lopen, haar vormen werden verhuld en de kleuren van haar kleren werden saaier. De edelstenen van de bruidsschat werden opgeborgen in de kisten. De volmaakte koopman had weliswaar een vriendelijk gezicht, maar toch ook een strenge uitdrukking. Hij droeg stijlvolle kleding, had een weloverwogen optreden en maakte gebaren met een berekende elegantie.
==Tekens en codes==
[[w:Wapen (heraldiek)|Wapens]], [[w:motto|deviezen]], [[w:livrei|livreien]] en [[w:blazoen|blazoenen]] lieten zien dat de dragers ervan bij een bepaalde militaire of politieke groep hoorden, of bij een bepaalde familie. Aan het einde van de middeleeuwen kwamen er steeds meer van dat soort tekens want er kwamen steeds meer groepen. De staat was toen al zover ontwikkeld dat de mensen weliswaar geen lijfeigenen meer waren<ref>[[Sociale geschiedenis van de hoge middeleeuwen/Feodalisme en adel#Feodalisme|Het einde van het feodalisme lag rond 1550]]</ref>, maar nu waren ze [[w:onderdaan|onderdanen]] van de staat. En ook allerlei [[w:Institutie (sociologie)|instituties]] waren toen al heel sterk. Daarom sloten veel mensen zich bij een groep aan:
*De "Stuben" (woonkamers) waar groepen notabelen uit het [[w:Rijnland (Duitsland)|Rijnland]], de [[w:Hanzestad|Hanzesteden]] en [[w:Keurvorstendom Saksen|Saksen]] bij elkaar kwamen.
*Gezelschappen van jonge patriciërs zoals de "Calza" in [[w:Venetië (stad)|Venetië ]] die een bepaald uniform kostuum droegen.
*Er ontwikkelden zich steeds meer "broederschappen" die processies en optochten hielden en daarbij pijen en kaarsen droegen in verschillende kleuren, al naar de groep waar zij toe behoorden.
*Er waren openbare feesten zoals de [[w:palio|palio]] (paardenrace) in [[w:Siena (stad)|Siena]] waarbij een massa mensen verdeeld was in groepen volgens [[w:heraldiek|heraldieke figuren]].
*[[w:Ridderorde (organisatie)|Lekenridderorden]] werden vanaf 1325 in heel Europa opgericht. De leden ervan traden toe tot zo'n orde door een belofte af te leggen. Zij onderwierpen zich vrijwillig aan een bepaalde discipline en droegen in het openbaar een kruis, een lint of een speciale mantel.
Vorsten, zoals het Saksische en het [[w:Wittelsbach|Beierse Huis]] begonnen eind vijftiende, begin zestiende eeuw eens per jaar uniforme kledingsstukken van een bepaalde kleur en met een [[w:Wapen (heraldiek)|embleem]] erop, uit te delen aan hun personeel. De vorst, graaf of hertog kon zo laten zien dat hij vrijgevig was, maar ook dat de dragers van die kleren onder zijn gezag vielen. Dit soort livreien kregen van tijd tot tijd nieuwe details om met de mode mee te gaan.
Rijke burgers die een firma leidden, imiteerden dit. Ze gaven aan hun hele personeel een soort uniforme statiekleding: rood voor als het personeel aanwezig moest zijn bij een huwelijk van de familie van de burger en zwart voor bij een begrafenis.
[[Bestand:Gulden vlies-kapittel.jpg|thumb|200px|left|Twee schilden, ca. 1525]]
==Symbolen==
Bij het uitkiezen van kleding, wapens en emblemen kon je flinke flaters slaan. Er zijn in de vijftiende eeuw zelfs boeken over dit onderwerp geschreven. Jongens kregen hulp van de adellijke dames bij wie ze als [[w:Page (jongen)|page]] lessen kregen in de hoofse liefde.<ref>[[Sociale geschiedenis van de hoge middeleeuwen/Leven in de Noord-Franse kastelen#onruststokers|Punt 3: De heer hield bewust zijn echtgenote als een soort worst voor.]]</ref><ref>[[Sociale geschiedenis van de hoge middeleeuwen/Opkomst van het individu#Hoofse liefde|De hoofse liefde was een spel dat goed gespeeld moest worden.]]</ref> Zij leerde hen ook hoe ze hun persoonlijke gevoelens via kleding en symbolen tot uitdrukking moesten brengen.
Er golden codes en afspraken voor het kiezen van wapens op kleding. Iets van zwarte [[w:damast (textiel)|damast]] met zilverdraad en groene, paarse en grijze struisvogelveren bijvoorbeeld, waar [[w:Hermelijn (heraldiek)|hermelijn]] met zwarte toefjes in konden zitten, ging niet zomaar. De codes en afspraken golden ook voor [[w:monogram|monogrammen]] en geborduurde [[w:Motto|deviezen]]. Er waren heraldische emblemen met planten en dieren. De uitgebeelde planten of dieren waren soms uit de fantasie ontsproten.
Toespelingen die men via symbolen maakte, moesten herkenbaar zijn en moesten vooral goed begrepen worden. Er was een hele "kleurentaal". Als een ridder in het groen deelnam aan een [[w:steekspel|steekspel]], wist het hele hof wat hij daarmee bedoelde. In [[w:Florence (stad)|Florence]] stond een rode ridder voor een rijk man.<ref>[[Sociale geschiedenis in de literatuur/Identiteit#Verloren of verborgen identiteit|De kleur rood wees op slechte bedoelingen, groen op een onstuimig karakter, blauw betekende dat iemand incognito wilde blijven en zwart betekende eerst van alles, maar werd later meestal negatief uitgelegd.]]</ref> In sommige streken rouwde men in het zwart, in andere in het wit.
Heel deze gecompliceerde symboliek was door de eeuwen heen gevormd en men kon gemakkelijk iets fout doen.
Veel van die symbolen konden maar op één manier geïnterpreteerd worden. In andere boodschappen was enige vrijheid mogelijk. Ook waren er privé-uitingen die alleen maar door een paar mensen begrepen werden: het werd dan een geheim. Soms is nu niet meer duidelijk wat een bepaald teken toen voorstelde.
==Noten==
{{References|95%}}
{{Sub}}
ef2tv8w4v5y8rlc1nq83kgzkqx4kicu
Gebruiker:Erik Baas/common.js
2
29822
428818
428808
2026-05-23T12:16:13Z
Erik Baas
2193
428818
javascript
text/javascript
// <nowiki>
$(function () {
// importScript('Gebruiker:Erik Baas/markeer.js'); /* markeer & next*/
// watisdit();
// insertTekst();
// massDelete();
automatePurgeConfirmationDialog();
// if (mw.config.get('wgTitle').indexOf("Programmeren in TI-Basic/") > -1) { autoEdit(); } // 20260420
replaceObsoleteHTMLTags();
markeerLintErrors();
addSubpagesLink();
// loadWikidataInfo();
fWikidata();
autoSave();
addPurgeTab(); // check: altijd als laatste!
return;
});
function autoSave() {
if (mw.config.get('wgPageContentModel') != "javascript" &&
mw.config.get('wgNamespaceNumber') != 828) { // -js, -module
if (mw.config.get('wgAction') == 'edit') {
document.getElementById('wpSummary').value = 'lf';
setTimeout(autoSave_sub, 10000);
}
}
return;
}
function autoSave_sub() {
document.getElementById("wpSave").click();
return;
}
function fWikidata() { /* Zoek in Wikidata - bron: [[w:Gebruiker:Zanaq/fwikidata.js]] (c) 2013 Zanaq, GPL
* Voegt een link "Zoek in Wikidata" toe aan de sectie "hulpmiddelen". */
var title = mw.config.get('wgTitle');
title = title.substr(title.lastIndexOf('/') + 1);
mw.util.addPortletLink('p-tb',
'https://www.wikidata.org/w/index.php?button=&title=Special%3ASearch&search=' + encodeURIComponent(title),
'Zoek in WikiData',
'ca-wikidata',
'Zoek "' + title + '" in Wikidata');
return;
};
function watisdit() {
const collection = document.getElementsByClassName("cdx-button");
alert(collection[0].innerHTML + ' *** ' + collection[1].innerHTML);
return;
};
function autoEdit() {
if (mw.config.get('wgNamespaceNumber') == 0) { // 0=(main), 3=Overleg gebruiker, 10=Template
if (mw.config.get('wgAction') == 'view') {
if (mw.config.get('wgDiffOldId') == null) { // of wgDiffNewId ?
window.location += '?action=edit';
}
}
}
return;
}
function loadWikidataInfo() {
/* Wikidata; 20260130
bron: https://nl.wikipedia.org/w/index.php?title=Wikipedia:Wikidata&oldid=70312736#Geschiedenis
geeft onder paginatitel korte info over onderwerp in Wikidata */
if ( mw.config.get( 'wgNamespaceNumber' ) === 0 ) {
// importScriptURI("//www.wikidata.org/w/index.php?title=User:Yair rand/WikidataInfo.js&action=raw&ctype=text/javascript");
importScriptURI("//nl.wikibooks.org/w/index.php?title=User:Erik_Baas/WikidataInfo.js&action=raw&ctype=text/javascript");
}
return;
}
function addSubpagesLink() {
/*
* Voegt een link "Subpagina's" toe aan de sectie "hulpmiddelen".
* Gebaseerd op de code in [[:commons:MediaWiki:Common.js]].
* Bron: https://nl.wikipedia.org/w/index.php?title=MediaWiki:Gadget-subpages.js
* Onderhoud: [[User:Krinkle]]
*/
var i18n = {
en: "Subpages",
fr: "Sous-pages",
nl: "Subpagina's"
};
if ( [ 'Special', 'File', 'Category' ].indexOf( mw.config.get( 'wgCanonicalNamespace' ) ) === -1 ) {
var text = i18n[ mw.config.get( 'wgUserLanguage' ) ] || i18n.nl;
var link = mw.util.getUrl( 'Speciaal:Voorvoegselindex/' + mw.config.get( 'wgPageName' ) + '/' );
mw.util.addPortletLink( 'p-tb', link, text, '', 'Subpagina\'s van deze pagina');
};
return;
}
function replaceObsoleteHTMLTags() {
var prev = '', sub='', subColor='', subFace='', subSize='', found='', text='', res='', X, Y, Z;
var objSummary = document.getElementById('wpSummary');
var obj = document.getElementById('wpTextbox1');
if (obj == null) return; /* exit */
if (! (mw.config.get('wgPageContentModel') == 'wikitext')) return; /* exit */
var text = '' + obj.value;
if (text.search(/{{Wiu[2,3]/i) > -1) {
alert('Stop: werk in uitvoering!');
return; /* exit */
}
createDebug();
/* <font> */
while (true) {
// common pt. 1
X = /<font.*?>/i.exec(text); // .exec: if not found: X=null, X[0] etc. = undefined !!
if (X == null) break; // geen font-tags
X = X + ''; // !!
subColor = subFace = subSize = X.replace(/(\x22|\x27)/g, ""); // - ' en "
/* <font color> */
if (subColor.search(/color/i) > -1) {
subColor = /color *= *[a-z,0-9,#]*/i.exec(subColor) + ''; // !!
if (subColor) {
subColor = subColor.replace(/ *= */, ": ") + ";";
subColor = subColor.toLowerCase();
}
}
else {subColor = null;} // geen color-attribute
/* <font face> */
if (subFace.search(/face/i) > -1) {
subFace = subFace.replace(/ *, */g, ",");
subFace = /face *= *[a-z,0-9,\,]*/i.exec(subFace) + ''; // !!
if (subFace) {
subFace = subFace.replace(/,/g, ', ');
subFace = subFace.replace(/face *= */i, 'font-family: ') + ';';
}
}
else {subFace = null;} // geen face-attribute
/* <font size> */
// todo
// tijdelijk: subSize = null;
if (subSize.search(/size/i) > -1) {
debug(subSize); // <font color=red face=Tahoma size=3>
subSize = /(?<=size *= *).*?(?=(\x20,'>'))/i.exec(subSize) + '';
debug(subSize); //
// subSize = subSize.replace(/.../, "...");
}
else {subSize = null;} // geen size-attribute
// tijdelijk:
subSize = null;
// common pt. 2
Y = '<span style="';
//debug(Y);
if (subColor) Y += subColor;
//debug(Y);
if (subFace) Y += (subColor ? ' ' : '') + subFace;
//debug(Y);
if (subSize) Y += (subColor || subFace ? ' ' : '') + subSize;
//debug(Y);
Y += '">';
//debug(Y);
text = text.replace(X,Y);
text = text.replace(/<\/font/ig, "</span");
} // while (true)
/*
ToDo:
- font color/size/face !!!
- uitzonderingen maken voor elementen tussen blockquote-, nowiki-, pre- en comment-tags !
*/
/*** Obsolete elements:***/
/* <big> */
text = text.replace(/(<big>){3,6}/ig, '<span style="font-size: xx-large;">'); //xxx-large werkt niet in Chrome !
text = text.replace(/(<big>){2}/ig, '<span style="font-size: x-large;">');
// 20220106: x-large voor zon en water
if (mw.config.get('wgTitle').indexOf("Leer jezelf ecologisch tuinieren") > -1) {
text = text.replace(/(?<=\| *zon *=.*)<big>/ig, '<span style="font-size: x-large;">');
text = text.replace(/(?<=\| *water *=.*)<big>/ig, '<span style="font-size: x-large;">');
}
text = text.replace(/<big/ig, '<span style="font-size: large;"');
text = text.replace(/(<\/big *[a-z|0-9]*>){1,6}/ig, "</span>");
/* <center> */
text = text.replace(/<center/ig, '<div style="text-align: center;"');
text = text.replace(/<\/center/ig, "</div");
/* <small> */
text = text.replace(/(<small>){3,6}/ig, '<span style="font-size: xx-small;">');
text = text.replace(/(<small>){2}/ig, '<span style="font-size: x-small;">');
text = text.replace(/<small/ig, '<span style="font-size: smaller;"');
text = text.replace(/(<\/small *[a-z|0-9]*>){1,6}/ig, "</span>");
/* <source> 20220116 */
text = text.replace(/<source/ig,'<syntaxhighlight');
text = text.replace(/<\/source/ig,'</syntaxhighlight');
/* <strike> */
text = text.replace(/<strike/ig, "<s");
text = text.replace(/<\/strike/ig, "</s");
/* <tt> */
text = text.replace(/<tt/ig, "<code");
text = text.replace(/<\/tt/ig, "</code");
/*** Diversen: ***/
/* <br> */
text = text.replace(/\x20*<\/?br\x20?\/? ?>/ig, "<br>");
/* <br clear=left/right/all/both> */
text = text.replace(/\x20*<br clear ?= ?(\x22|\x27)?left(\x22|\x27)?\x20?\/?>/ig, '<br style="clear: left;">');
text = text.replace(/\x20*<br clear ?= ?(\x22|\x27)?right(\x22|\x27)?\x20?\/?>/ig, '<br style="clear: right;">');
text = text.replace(/\x20*<br clear ?= ?(\x22|\x27)?(all|both)(\x22|\x27)?\x20?\/?>/ig, '<br style="clear: both;">');
/* <hr> */
text = text.replace(/<\/?hr\x20?\/?>/ig, "<hr>");
text = text.replace(/\[\[categorie/ig, "[[Categorie");
text = text.replace(/\[\[afbeelding/ig, "[[Afbeelding");
/* prettytable */
text = text.replace(/prettytable/ig, "wikitable");
/* WSBN nummer :-( */
text = text.replace(/\[WSBN( |-|_)?nummer/ig, " [WSBN");
text = text.replace(/.*Hier.*onderhoudsmeldingen.*\n/ig, "");
/* . ná <ref> */
while(true) {
X = /(?<!\.) ?<ref>.*?<\/ref>\./.exec(text);
if (X == null) break;
Y = X[0].replace(/ ?<ref>/,'.<ref>');
Y = Y.replace('</ref>.','</ref>');
text = text.replace(X,Y);
}
/* sjablonen en Magic Words */
text = text.replace(/{{{/g, "aW~d6-8Ht#yV_5"); // vervang "{{{" tijdelijk door code om varabelen te onderscheiden van sjablonen
/* Magic Words - 20230323 */
text = text.replace(/\{\{#categorytree:/g, "{{#Categorytree:");
text = text.replace(/\{\{#expr:/g, "{{#Expr:");
text = text.replace(/\{\{\s?#if:\s?/ig, "{{#If:");
text = text.replace(/\{\{ ?#invoke:/g, "{{#Invoke:");
text = text.replace(/\{\{ ?#pos:/g, "{{#Pos:");
text = text.replace(/\{\{ ?#switch:/g, "{{#Switch:");
/* Magic Words met 2 hoofdletters: 20230421 */
text = text.replace(/\{\{ ?#ife/ig, "{{#IfE");
/* oud:
text = text.replace(/\{\{ ?#iferror:/g, "{{#IfError:");
text = text.replace(/\{\{ ?#ifexpr:/g, "{{#IfExpr:");
text = text.replace(/\{\{ ?#ifexist:/g, "{{#IfExist:");
text = text.replace(/\{\{ ?#ifeq:/g, "{{#IfEq:");
*/
/* ISBN 20230625 */
// text = text.replace(/ISBN\s{1,3}/ig, "{{ISBN|");
// debug ("ISBN checken!");
// text = text.replace(/(?<=\{\{ISBN\|[0-9%s]{8,13})(( )|\.|,|\n)/ig, "}} "); // <-
/* ISBN exp. 20240121 */
text = text.replace(/ISBN\s{1,3}([0-9]\-?)*/ig, "{{$&}}");
text = text.replace(/\{\{ISBN\s{1,3}/ig, "{{ISBN|");
/* Sjabloonredirects vervangen 20220209 */
text = text.replace(/{{Beg(innetje)?}}/ig, "{{Begin}}");
text = text.replace(/{{Alleen afdrukken ?(\|\n|\n\|)/ig, '{{Alleen afdrukken inline\n|\n'); // extra \n tbv. sommige wikicodes
text = text.replace(/{{Alleen afdrukken ?\|/ig, '{{Alleen afdrukken inline|');
text = text.replace(/{{Herhalen ?\|/ig, '{{Repeat|');
text = text.replace(/{{Niet afdrukken ?(\|\n|\n\|)/ig, '{{Niet afdrukken block\n|\n'); // extra \n tbv. sommige wikicodes
text = text.replace(/{{Niet afdrukken ?\|/ig, '{{Niet afdrukken block|');
text = text.replace(/\n\| *Moeilijkheid *= *[ a-zA-Z]*/ig, ''); // 20251012
text = text.replace(/{{Zieook ?(\|\n|\n\|)/ig, '{{Zie ook\n|\n'); // extra \n tbv. sommige wikicodes
text = text.replace(/{{Zieook ?\|/ig, '{{Zie ook|');
/* text = text.replace(/{{Crd ?\|/ig, '{{Akkoord|'); klaar */
/* text = text.replace(/{{Akkoorden ?\|/ig, '{{Akkoord|'); klaar */
// eerst toepassen op _alle_ sjablonen, ipv. check op overbodige "|" ?
/* sjabloonnaam met hoofdletter */
{
while(true){
X = /{{[a-z]/.exec(text);
if (X == null) break;
Y = X[0].toUpperCase();
text = text.replace(X,Y);
}
/* Idem in Sjabloon:Tl: 20230421 -- ToDo
while(true){
X = /{{tl\|[A-Za-z]/i.exec(text);
alert("X1=" + X);
if (X == null) break;
alert("X2=" + X);
Y = X[0].toUpperCase();
alert("Y=" + Y);
text = text.replace(X, "{{Tl|" + Y);
alert("3=" + text.replace(X, "{{Tl|" + Y));
/ alert(X + " - " Y + " - " + text.replace(X, "{{Tl|" + Y));
}
*/
// overbodige pipe na sjabloonnaam
prev = text;
text = text.replace(/(?<={{[a-z,0-9, ,-]*) *\| *\n/ig, '\n|\n');
if (!(prev == text)) {
debug('checken: evt. eerste sjabloonparameter(s)!'); // alert
}
}
text = text.replace(/aW~d6-8Ht#yV_5/g, "{{{"); // herstel code naar "{{{" ---------------
/* {{Sub}} onderaan */
X = text.search(/{{sub}}/i);
if (X > -1 && X < 50) {text = text.replace(/{{sub}}\n?/i, '') + '{{Sub}}';}
/* lege regels voor {{sub}} */
text = text.replace(/\n ?\n*{{sub}}/ig,'\n{{Sub}}');
/* <tr> |- */
text = text.replace(/\|-+/g, "|-");
/* overbodige laatste <tr> */
text = text.replace(/ *\|-\x20*\n *\|}/g, "|}");
/* wikicode hr: 4 streepjes */
text = text.replace(/^-{5,}/g, "----");
text = text.replace(/\n-{5,}/g, "\n----");
/* http:// */
prev = text;
text = text.replace(/http:\/\//ig, 'https://');
if (!(prev == text)) {debug('Check externe links (https)!');} // alert
/* "xxe eeuw" in tekst */ { // 20220119
/* disabled: mag geen _links_ wijzigen ! 20220215
text = text.replace(/(?<=(1|2)?[0-9])e eeuw/g,'<sup>e</sup> eeuw');
text = text.replace(/(?<=(1|2)?[0-9])e-eeuw/g,'<sup>e</sup>-eeuw');
*/
}
text = text.replace(/\[\[categorie:/ig, "[[Categorie:");
text = text.replace(/\[\[:categorie:/ig, "[[:Categorie:");
/* Afsluitende tag op Categorie: 20220124, v2 */
if (mw.config.get('wgNamespaceNumber') == 14) {
text = text.replace(/'''{{PAGENAME}}(?!''')/i, "'''{{PAGENAME}}'''");
}
/* Check op nested span tags - 20220218 */
/*
if (text.search(/<\/span( color)?> ?<\/span>/i) > -1 ){
// alert('Check: nested span tags!?');
text = text.replace(/"><span style="/ig, ' ') // erg bot: alleen voor eco tuin ??
text = text.replace(/<\/span( color)?><\/span>/ig, '</span>'); // ,,
}
*/
/* {{Fase0..4}} -> {{Fase|0..4}} */
text = text.replace(/\{\{Fase(?=[0-4])/ig, '{{Fase|'); // 20250810
text = text.replace(/\{\{Fase([1-4])/ig, "{{Fase|$1"); // 20260514 dubbel
/* geen lege regel na kopje - 20230724 */
text = text.replace(/==\n\n(?!==)/g, "==\n");
// komma vóór <ref> // 20251004
text = text.replace(/ \<\/ref\>/ig, '</ref>');
text = text.replace(/ \<\/cite\>/ig, '</cite>');
// links wp fixen: // 20251004
if (mw.config.get('wgNamespaceNumber') == 0) {
text = text.replace(/\[\[:?w:(nl:)?(.*?)\]\]/ig , '{{Wp|$2}}');
}
text = text.replace(/\{\{W\|/ig, '{{Wp|'); // 20251008
text = text.replace(/\{\{W[^a-zA-Z]/ig, "{{Wp"); // dubbel
// objSummary.value = 'Lintfouten: Verouderde HTML elementen';
// document.getElementById('wpSummary').value = 'lf'; // 20260323
text = text.replace(/\{\{Sjabloon:/ig, "{{");
//aap ******* . + * ? ^ $ ( ) [ ] { } | / \ ********
// template:
// text = text.replace(/\{\{/ig, "{{");
text = text.replace(/\{\{Leer jezelf ecologisch tuinieren/ig, "{{Index Leer jezelf ecologisch tuinieren");
text = text.replace(/\{\{Navigatie([\|,\n])/ig, "{{Bladeren2$1"); // 20260516
text = text.replace(/\{\{Talen/ig, "{{Taal- en letterkunde");
/*
if (mw.config.get('wgTitle').indexOf("Programmeren in TI-Basic/") > -1) { // 20260420
text = text.replace(/\{\{Links\}\}\n/i, "");
// text = text + String.fromCharCode(13, 10) + "{{Links}}";
text = text + "{{Links}}";
}
*/
/*
text = text.replace(/\{\{00%/ig, "{{0%");
text = text.replace(/ategorie:GFDL afbeeldingen/ig, "ategorie:Bestanden met GFDL Licentie");
text = text.replace(/ategorie:Afbeelding naar licentie/ig, "ategorie:Bestand naar licentie");
text = text.replace(/ategorie:Wikibooks:Afbeelding beschikbaar op commons met dezelfde naam/ig, "ategorie:Wikibooks:Bestand beschikbaar op commons met dezelfde naam");
text = text.replace(/ategorie:Wikibooks:Afbeelding beschikbaar op commons/ig, "ategorie:Wikibooks:Bestand beschikbaar op commons");
text = text.replace(/ategorie:Wikibooks:Afbeeldingen niet te verplaatsen naar Wikimedia Commons/ig, "ategorie:Wikibooks:Bestand niet te verplaatsen naar Wikimedia Commons");
text = text.replace(/ategorie:PD-afbeeldingen/ig, "ategorie:Bestanden met PD Licentie");
text = text.replace(/ategorie:Ewmulti-afbeeldingen/ig, "ategorie:Bestanden met Ewmulti Licentie");
text = text.replace(/ategorie:Afbeeldingen zonder geldige licentie/ig, "ategorie:Bestanden zonder geldige licentie");
text = text.replace(/ategorie:Wikibooks:Verplaats naar Wikimedia Commons/ig, "ategorie:Wikibooks:Bestand te verplaatsen naar Wikimedia Commons");
text = text.replace(/ategorie:Afbeeldingen met Creative Commons Licentie by-sa/ig, "ategorie:Bestanden met Creative Commons Licentie by-sa");
text = text.replace(/ategorie:Afbeeldingen met Creative Commons Licentie by/ig, "ategorie:Bestanden met Creative Commons Licentie by");
text = text.replace(/ategorie:Afbeeldingen/ig, "ategorie:Bestand");
text = text.replace(/ategorie:Creative Commons-afbeeldingen/ig, "ategorie:Bestanden met Creative Commons Licentie");
*/
text = text.replace(/\{\{Information/i, "{{Informatie");
//text = text.replace(/\{\{Links\}\}\n/i, ""); // 20260412
//text = text.replace(/\{\{Sub\}\}/i, "{{Sub}}\n{{Links}}");
text = text.replace(/Youtube/g, "YouTube"); // 20260406
text = text.replace(/{{Clearboth/ig, "{{Clear both"); // 20260323
text = text.replace(/{{Clearleft/ig, "{{Clear left");
text = text.replace(/( | ){0,3}<ref(?!erences)/ig, ' <ref'); // 1 spatie voor <ref> 20260121
text = text.replace(/<ref(.*)?> <ref/ig, '<ref$1><ref'); // tenzij 2 x ref na elkaar
text = text.replace(/\{\{L\|(.*)\}\}/ig, '[[../$1/]]'); // {{L|x}} -> [[../x/]] 20251229
text = text.replace(/#DOORVERWIJZING ?/ig, '#Redirect ');
if (mw.config.get('wgPageName').indexOf('Sjabloon:Index_') > -1) { // mw.config.get('wgPageName') geeft {{FULLPAGENAME}} !
text = text.replace(/## ?\[\[/g , '**[[');
text = text.replace(/# ?\[\[/g , '*[[');
// ??? text = text.replace(/\[\[Categorie:Sjablonen index\]\]\n?/ig, '');
}
// {{tl}}:
// text = text.replace(/\{\{tl\|(a-z)/ig, '{{Tl|' + '$1'.toUpperCase()); // werkt niet
// text = text.replace(/\{\{tl\|(a-z)/ig, '{{Tl|' + String($1).charAt(0).toUpperCase()); // crasht
// komma in getal -> punt - verder testen! - werkt maar t/m 999,999! :
// text = text.replace(/([0-9]{1,3}),([0-9]{3})/g, '$1.$2');
text = text.replace(/\{\{Schaak\/Bord\|=/ig , '{{Schaak/Bord2'); // 20251030
text = text.replace(/\|\n\|=/ig , '|\n|');
text = text.replace(/(\n[1-8].*?)= ?\n/ig , '$1\n');
text = text.replace(/(\n[1-8].*?)= ?\n/ig , '$1\n');
text = text.replace(/\{\{HTML-standaardattributen/ig, '{{HTML standaardattributen');
text = text.replace(/\{\{HTML (tags|elementen)/ig, '{{Navigatie HTML elementen'); // 20251016
text = text.replace(/\[\[(:)?File:/ig, '[[$1Bestand:'); // 20251009
text = text.replace(/\[\[(:)?Image:/ig, '[[$1Afbeelding:');
text = text.replace(/\n\n?\{\{Recepten\}\}/ig, '\n{{Navigatie recepten}}'); // 20251012
text = text.replace(/\{\{Beg\}\}/ig, '{{Begin}}'); // 20251022
text = text.replace(/\{\{Boekenplanken\}\}/ig, '{{Navigatie boekenplanken}}'); // 20251022
/*** Eenmalige acties ***/
text = text.replace(/\[\[Kookboek\/\bDessert\b/ig, '[[Kookboek/Nagerecht'); // 20251012
text = text.replace(/\{\{TOCRechts/ig, '{{TOC rechts'); // 20230417
text = text.replace(/\{\{Wikt(?=(\||\}))/ig, '{{Wiktionary'); // 20230514
text = text.replace(/\{\{Woordenboek Index\}/ig, '{{Alfabet met links}'); // 20230520
text = text.replace(/se wikipedia/ig, 'stalige Wikipedia'); // 20230614
text = text.replace(/background: ?none;? ?/ig, ''); // 20250711
text = text.replace(/\n?\n\n\n\{\{Recepten\}\}/ig, '\n\n{{Recepten}}'); // 20250805
text = text.replace(/\{\{Recept\n\|\n/ig, '{{Recept\n'); // 20250805
text = text.replace(/(?<![a-zA-Z])NB(\.(\:)?|\:) ?/g, 'NB '); // 20250817
text = text.replace(/Wiskunde voor MBO techniek\//g, 'Wiskunde voor MBO techniek 1/'); // 20250824
/*** Archief eenmalige acties ***/
/*
text = text.replace(/\{\{Recepten/ig, "{{Navigatie recepten");
text = text.replace(/\{\{Recept/ig, "{{Infobox recept"); // 2260516
text = text.replace(/\{\[Clear both/ig , "{{Clear both");
text = text.replace(/{{Clearright/ig , "{{Clear right");
text = text.replace(/{{Boeken/ig , "{{Post-it/Boeken");
// tbv. Maatschappijleer/Alfabetische woordenlijst maatschappijleer - 20260303:
// text = text.replace(/; ?<<!-- ?/ig , ';<!--');
// text = text.replace(/ ?-->span>/ig , '-->');
// text = text.replace(/;<\/span>/ig , ';');
// text = text.replace(/\[\[Categorie:Land\]\]/ig, '[[Categorie:Land in Europa]]'); // 20260125
if (mw.config.get('wgTitle').indexOf('Atlas van') > -1) { // wd-properties vervangen; 20260119
text = text.replace(/(property|statements):P18/ig, '$1:afbeelding');
text = text.replace(/(property|statements):P31/ig, '$1:is een');
text = text.replace(/(property|statements):P35/ig, '$1:staatshoofd');
text = text.replace(/(property|statements):P47/ig, '$1:grenst aan');
text = text.replace(/(property|statements):P122/ig, '$1:regeringsvorm');
text = text.replace(/(property|statements):P206/ig, '$1:gelegen in of aan waterlichaam');
text = text.replace(/(property|statements):P361/ig, '$1:onderdeel van');
text = text.replace(/(property|statements):P571/ig, '$1:datum van oprichting of creatie');
text = text.replace(/(property|statements):P1539/ig, '$1:vrouwelijke bevolking');
text = text.replace(/(property|statements):P1540/ig, '$1:mannelijke bevolking');
text = text.replace(/(property|statements):P2131/ig, '$1:bruto binnenlands product');
}
// tbv. [[Wikibooks:Lijst van eigenschappen van Wikidata-items]]: (20251211))
text = text.replace(/\<br\>\[\[d:Property talk:P[0-9]{1,5}\|talk\]\]\<br\>\[\[d:Wikidata:Database reports\/Constraint violations\/P[0-9]{1,5}\|covi\]\]\|/ig, '|');
// voor [[Onderwijs in relatie tot P2P]] :
text = text.replace(/tot P2P\/(.*)/g, 'tot P2P/$1|$1]]');
text = text.replace(/{{StringReplace ?\|/ig, '{{Replace|');
if (mw.config.get('wgNamespaceNumber') == 3) { // "Overleg gebruiker"; 20251116
text = text.replace(/\{\{Zandbak\}\}/ig, '{{Zb}}');
}
text = text.replace(/\{\{Bladeren(2|3)/ig, '{{Bladeren4'); // 20230531
text = text.replace(/\[\[Categorie:Weglaten bij afdrukken.*?\]\]\n?/ig, ''); // 20251024
text = text.replace(/\{\{Miljoen/ig, '{{Afronden'); // 20251005
// lintfouten: Ingebedde stijlregel voor de achtergrondkleur zonder bijbehorende tekstkleur // 20250711
text = text.replace(/(color: ?(black|inherit); ?)?background(-color)?:/ig, 'color: inherit; background-color:');
if (mw.config.get('wgNamespaceNumber') == 14) { // 20251009
if (mw.config.get('wgTitle').indexOf('- inhoud') > -1) {
text = text.replace(/\n?\[\[Categorie:Hoofdstuk.*?\]\]\n?/ig, '');
if (text.indexOf('Categorie:Inhoud') > -1) {
// window.location.assign('https://nl.wikibooks.org/w/index.php?title=Categorie:Inhoud');
return;
}
text = text.replace(/\n?\[\[Categorie:Inhoud\]\]\n?/ig, '');
text = text + '[[Categorie:Inhoud]]\n'; // toevoegen indien cat:hoofdstuk nog niet aanwezig
// werkt niet (edit wordt niet opgeslagen):
// var Button = document.getElementById("wpSave");
// Button.click();
}
}
var X = mw.config.get('wgPageName');
document.write(X + '__');
var Y = X.search('Wikibooks:Infobox/');
document.write(Y + '__');
if (Y > -1) {
document.write('ja__');
text = text.replace(/--\>\|.*boekenplank.*(taal( en letterkunde)?|talen)/ig, '-->| boekenplank = Taal en letterkunde');// 2025100?
}
text = text.replace(/\{\{Abc\}\}/ig, '{{Alfabet met ankers}}'); // 20230414
text = text.replace(/\[\[Categorie\:Sjablonen sjabloondocumentatie/ig, '[[Categorie:Sjabloondocumentatie');
text = text.replace(/Moderne/g , 'moderne'); // 20251006
text = text.replace(/Hedendaagse/g , 'hedendaagse');
text = text.replace(/Architectuur/g , 'architectuur');
// rode (wp-)links ontlinken:
// tbv. [[Veelvoorkomende misvattingen/Wetenschap en technologie]]
// "lazy" mode: (.*?) - https://javascript.info/regexp-greedy-and-lazy ! :-)
// problemen:
// * afb. met link(s) in de caption gaan stuk -> handmatig op te lossen
// * links met afwijkende omschrijving worden zichtbaar -> niet ,,
// 2: te behouden links veiligstellen:
text = text.replace(/\[\[((Afbeelding|Bestand|bibcode|doi|File|Image|Media):.*?)\]\]/ig, 'REPL251005pre$1REPL251005post');
// 3: alle overige links omzetten naar tekst:
text = text.replace(/\[\[(.*?)\]\]/ig, '$1');
text = text.replace(/\[\[(.*?)\]\]/ig, '$1'); // 2e keer tbv. geneste links!
// 4: te behouden links herstellen:
text = text.replace(/REPL251005pre/g, '[[');
text = text.replace(/REPL251005post/g, ']]');
*/
/*
text = text.replace(/{{Receptmetafbeelding/ig, '{{Infobox recept'); // 20230312, 20251011
te gretig; text = text.replace(/,\<ref\>(.*)\<\/ref\>/ig , '<ref>$1</ref>,'); // 20251004
text = text.replace(/\[Spaans\/Les( |_)0/ig , '[Spaans/Les '); // 20250930
text = text.replace(/Categorie\:Ingrediënt\/Drank/ig , 'Categorie:Drank') // 20250929
text = text.replace(/Categorie\:Kookboek\/Ingrediënt\/Fruit/ig , 'Categorie:Fruit') // ,,
text = text.replace(/Categorie\:Kookboek\/Ingrediënt\/Gevogelte/ig , 'Categorie:Gevogelte') // ,,
text = text.replace(/Categorie\:Kookboek\/Ingrediënt\/Graan/ig , 'Categorie:Graan') // ,,
text = text.replace(/Categorie\:Kookboek\/Ingrediënt\/Groente/ig , 'Categorie:Groente') // ,,
text = text.replace(/Categorie\:Kookboek\/Ingrediënt\/Zuivel/ig , 'Categorie:Zuivel') // ,,
text = text.replace(/Categorie\:Kookboek\/Ingrediënt\/Vruchtensap/ig , 'Categorie:Vruchtensap') // ,,
*/
/* text = text.replace(/Italiaans.*Antwoorden.*\]\]/g, mw.config.get('wgTitle') + '/Antwoorden]]'); // 20250920 */
/* text = text.replace(/Italiaans\/Les0?/g, 'Italiaans/Les '); // 20250920 */
/* text = text.replace(/ hele )/ig, ' heel '); //20250920 */
/* text = text.replace(/WikiJunior/g, 'Wikijunior'); // 20250718 */
/* text = text.replace(/\{\{TOCLinks/ig, '{{TOC links'); // 20230417 */
/* text = text.replace(/\/(.{1,65})\]\]/ig, '/$1|$1]]'); // 20250903 */
/* text = text.replace(/\{\{Uitleg\|(.{5,43})\|(.{5,43})\}\}/ig, '{{Hover|tekst=$2|hovertekst=$1}}'); // 20250901 */
/* text = text.replace(/\{\{Tuin(\n|\|)/i, '{{Tuinkalender'); // 20250803 */
/* text = text.replace(/\{\{Tuinkalender\|Pagina.*tuinieren\/(.*)\|tuinkalender\]\]\n?\|Onderdeel\=(.*)\n\}\}/i, '{{Tuinkalender|$1|$2}}'); // 20250831 */
/* text = text.replace(/(?<=g)allerij/ig, 'alerij'); // 20230614 */
/* text = text.replace(/(?<=t)utti frutti/ig, 'uttifrutti'); // 20250817 */
/* text = text.replace(/\{\{\#babel\:/ig, '{{Babel|'); // 20250813 */
/* text = text.replace(/\n/g, ']]\n'); // 20250812 */
/* text = text.replace(/gerbuik/g, 'gebruik'); // 20250806 */
/* text = text.replace(/\{\{Noindex\}\}/ig, '__NOINDEX__'); */
/* text = text.replace(/\{\{Clear\}\}/ig, '{{Clearboth}}'); */
/* text = text.replace(/\| ?Naam ? ?= ? ?{{PAGENAME}}/, '| Naam = '); // 20250805 */
/* text = text.replace(/Categorie:Sjablonen voor een bepaald boek/ig, 'Categorie:Sjablonen talen en dialecten'); */
/* text = text.replace(/Categorie\:Fase(?=[0-4])/ig, 'Categorie:Fase ');*/ // 20250803
/* 1e img van Sjabloon:Gestarte boeken verwijderen */
// text = text.replace(/ ?\[\[Bestand:.-4\.svg\|.px\]\] ?/ig , '\n'); // 20250722
// text = text.replace(/ /ig , ' ');
// text = text.replace(/\* ? ?/ig , '<br>\n');
// text = text.replace(/\]\] \{\{/ig , ']]{{');
// text = text.replace(/\{\{0%/ig , '00%');
//text = text.replace(/Chillipepers\.nl/ig, 'chillipepers.nl'); // 20250722
//text = text.replace(/Chillipeper\.nl/ig, 'chillipeper.nl'); // ,,
// text = text.replace(/Basiskennis( |_)chemie6\//g, 'Basiskennis chemie 6/'); // 20250906
// // document.getElementById('wpSummary').value = 'lf'; werkt niet!??
// ---------------------------------------------------------------------------------------------
/* tbv. lintfouten op overleg gebruiker */
// text = text.replace(/('''|\<\/?b\>)/ig, ""); /* 20230627 */
/* tbv. verkeerd geneste tags op overleg:gebruiker */
// text = text.replace(/\<\/?span.*?\>/ig, ""); /* 20230627 */
// obj.value = 'Lintfouten: Verkeerd geneste tags';
/* test: CSS beter leesbaar maken - 20230519 */
text = text.replace(/(?<=style\=\".*): *(?=\>)/ig, ": "); /* too greedy; check "http(s):, /File: etc. ! */
text = text.replace(/(?<=style\=\"); ?(?=\")/ig, "; ");
/* ------ oud -------------
text = text.replace(/\[\[Categor(ie|y):Sjablonen(?=[\||\]\]])/ig, '[[Categorie:Sjablonen Wikibooks-gebruikers');
text = text.replace(/\[\[Categor(ie|y):Sjablonen(?=[\||\]\]])/ig, '[[Categorie:Sjablonen voor een bepaald boek');
// "xxe eeuw" in titel { // 20220119
var title = mw.config.get('wgTitle');
var pattern = /(?<=(1|2)?[0-9])e-eeuw/;
if (text.search(/{{DISPLAYTITLE:/) == -1) {
if (title.search(pattern) > -1) {
text = '{{DISPLAYTITLE:' + title.replace(pattern,'<sup>e</sup>-eeuw') + '}}' j+ text;
}
}
else debug('{{DISPLAYTITLE: is niet vervangen');
}
// tijdelijk (tbv "Lintfouten: Afsluitende tag ontbreekt")
text = text.replace(/{{cat\|?/ig, "{{Cat");
text = text.replace(/{{boekcat\|/ig, "{{Boekcat");
text = text.replace("'''{{PAGENAME}}", "'''{{PAGENAME}}'''");
*/
/* verplaatsen naar andere categorie:
text = text.replace(/\[\[Categorie:Aardrijkskunde/ig, "[[Categorie:Geografie");
*/
/* sig BeeBringer:
text = text.replace(/\[\[Bestand:BeeBringer.png\]\].*?\<\/sup>/, '\n[[Gebruiker:BeeBringer|BeeBringer]] [[Overleg_gebruiker:BeeBringer|overleg]]');
text = text.replace(/u wijzingen/, 'uw wijzigingen');
*/
/* div. typefouten */
// text = text.replace(/(?<=w)ijzingen/, 'ijzigingen');
text = text.replace(/paramaters/, 'parameters');
/*** Einde ***/
/* niets veranderd? */
if (obj.value == text) return; /* exit */
obj.value = text; /* klaar om op te slaan */
// obj.value = obj.value + '\n\n' + text; // TIJDELIJK!!
/*** Samenvatting ***/
var obj = document.getElementById('wpSummary');
// obj.value = 'cat';
// obj.value = 'Lintfouten: Verouderde HTML-elementen';
// obj.value = 'Lintfouten: Afsluitende tag ontbreekt';
/* tijdelijk (voor eenmalige acties): */
// obj.value = '[[Categorie:Sjablonen voor een bepaald boek]]';
// obj.value = '[[Categorie:Sjablonen Wikibooks-gebruikers]]';
/*** Niet volgen tenzij reeds eerder gevolgd ***/
var obj = document.getElementById('ca-watch');
if (obj) {document.getElementById('wpWatchthis').checked = false;}
return;
}
function addPurgeTab() {
/* Voegt een "purge" tabje toe
(bron: https://nl.wikipedia.org/wiki/Gebruiker:Pjetter/monobook.js) */
if(!document.getElementById) return;
var x = document.getElementById('ca-history');
if(! x) { return; }
var tabs = document.getElementById('p-cactions').getElementsByTagName('ul')[0];
if(x.children) { x = x.children[0]; }
else { x = x.childNodes[0]; }
addlilink(tabs, x.href.replace(/=history/, "=purge"), 'purge', 'ca-purge');
// ta['ca-purge'] = ['g', 'Purge the internal cache for this page']; // "ta is not defined"
}
function addlilink(tabs, url, name, id) {
/* voegt tabjes toe
(bron: https://nl.wikipedia.org/wiki/Gebruiker:Pjetter/monobook.js) */
var na = document.createElement('a');
na.href = url;
na.appendChild(document.createTextNode(name));
var li = document.createElement('li');
li.id = id;
li.appendChild(na);
tabs.appendChild(li);
return li;
}
function experiment() { // (om 'Inklappen' resp. 'Uitklappen' te vervangen)
UitklapDivHide = '▲'; // U+25B2 kleiner: ▴ u+25B4 werkt niet
UitklapDivShow = '▼'; // U+25BC kleiner: ▾ u+25BE ,, ,,
}
function automatePurgeConfirmationDialog() {
/* Automate purge confirmation dialog. (https://en.wikipedia.org/wiki/Wikipedia:Purge) */
if (mw.config.get('wgAction') === 'purge' ) {
$('form[action*="action=purge"]').submit();
}
return;
}
function markeerLintErrors() { // 20220114
// Markeert aantallen > 0 op Speciaal:LintErrors met een rode achtergrond.
if (! (mw.config.get('wgPageName') == 'Speciaal:LintErrors')) return; /* exit */
var list = document.getElementsByTagName("BDI");
if (list.length == 0) return;
for (i=0; i<list.length; i++) {
if (! (list[i].innerHTML == '(0 fouten)')) {
list[i].style.background = '#ff8080';
}
}
return;
}
function createDebug() { // v2, 20220113
// Creëert een debug-venster direct boven het bewerkingsvak.
var obj = document.getElementById('wpTextbox1');
var parent = document.getElementById('editform');
var newItem = document.createElement("DIV");
newItem.id = 'debug';
newItem.style.display='none';
var textnode = document.createTextNode("");
newItem.appendChild(textnode);
parent.insertBefore(newItem, obj);
}
function debug(txt) {
// Voegt een regel tekst toe aan het debug-venster.
var obj = document.getElementById('debug');
if (obj == null) return; /* exit */
obj.style.display = 'block';
obj.innerHTML = obj.innerHTML + txt.replace(/</g,'<') + '<br>';
}
function massDelete() { /* tbv. verwijderen ~450 pagina's, zie lijst op LJET/Gewenste pagina's */
if (mw.config.get('wgTitle').indexOf('Leer jezelf') == -1) return;
if (mw.config.get('wgAction') != 'delete') return;
document.getElementById('ooui-php-2').value = 'Verwijdersessie 3 september 2025';
document.getElementById("deleteconfirm").submit();
return;
}
function insertTekst() {
var title = mw.config.get('wgTitle');
if ((title.search(/Kookboek [0-9]{1,2} /i)) == 0) {
if (mw.config.get('wgNamespaceNumber') == 10) {
if (mw.config.get('wgAction') == 'view') {
window.location += '?action=edit';
var text = document.getElementById('wpTextbox1').value;
text = '__EXPECTUNUSEDCATEGORY__\n' + text;
}
}
}
return;
}
function capFirst(str) {
/* fix all-caps en camel-case */
return str[0].toUpperCase() + str.slice(1).toLowerCase();
}
// </nowiki>
q3fjxqrx07rpph2ujquweorr0gvqgv2
428837
428818
2026-05-23T12:18:13Z
Erik Baas
2193
428837
javascript
text/javascript
// <nowiki>
$(function () {
// importScript('Gebruiker:Erik Baas/markeer.js'); /* markeer & next*/
// watisdit();
// insertTekst();
// massDelete();
automatePurgeConfirmationDialog();
// if (mw.config.get('wgTitle').indexOf("Programmeren in TI-Basic/") > -1) { autoEdit(); } // 20260420
replaceObsoleteHTMLTags();
markeerLintErrors();
addSubpagesLink();
// loadWikidataInfo();
fWikidata();
// autoSave();
addPurgeTab(); // check: altijd als laatste!
return;
});
function autoSave() {
if (mw.config.get('wgPageContentModel') != "javascript" &&
mw.config.get('wgNamespaceNumber') != 828) { // -js, -module
if (mw.config.get('wgAction') == 'edit') {
document.getElementById('wpSummary').value = 'lf';
setTimeout(autoSave_sub, 10000);
}
}
return;
}
function autoSave_sub() {
document.getElementById("wpSave").click();
return;
}
function fWikidata() { /* Zoek in Wikidata - bron: [[w:Gebruiker:Zanaq/fwikidata.js]] (c) 2013 Zanaq, GPL
* Voegt een link "Zoek in Wikidata" toe aan de sectie "hulpmiddelen". */
var title = mw.config.get('wgTitle');
title = title.substr(title.lastIndexOf('/') + 1);
mw.util.addPortletLink('p-tb',
'https://www.wikidata.org/w/index.php?button=&title=Special%3ASearch&search=' + encodeURIComponent(title),
'Zoek in WikiData',
'ca-wikidata',
'Zoek "' + title + '" in Wikidata');
return;
};
function watisdit() {
const collection = document.getElementsByClassName("cdx-button");
alert(collection[0].innerHTML + ' *** ' + collection[1].innerHTML);
return;
};
function autoEdit() {
if (mw.config.get('wgNamespaceNumber') == 0) { // 0=(main), 3=Overleg gebruiker, 10=Template
if (mw.config.get('wgAction') == 'view') {
if (mw.config.get('wgDiffOldId') == null) { // of wgDiffNewId ?
window.location += '?action=edit';
}
}
}
return;
}
function loadWikidataInfo() {
/* Wikidata; 20260130
bron: https://nl.wikipedia.org/w/index.php?title=Wikipedia:Wikidata&oldid=70312736#Geschiedenis
geeft onder paginatitel korte info over onderwerp in Wikidata */
if ( mw.config.get( 'wgNamespaceNumber' ) === 0 ) {
// importScriptURI("//www.wikidata.org/w/index.php?title=User:Yair rand/WikidataInfo.js&action=raw&ctype=text/javascript");
importScriptURI("//nl.wikibooks.org/w/index.php?title=User:Erik_Baas/WikidataInfo.js&action=raw&ctype=text/javascript");
}
return;
}
function addSubpagesLink() {
/*
* Voegt een link "Subpagina's" toe aan de sectie "hulpmiddelen".
* Gebaseerd op de code in [[:commons:MediaWiki:Common.js]].
* Bron: https://nl.wikipedia.org/w/index.php?title=MediaWiki:Gadget-subpages.js
* Onderhoud: [[User:Krinkle]]
*/
var i18n = {
en: "Subpages",
fr: "Sous-pages",
nl: "Subpagina's"
};
if ( [ 'Special', 'File', 'Category' ].indexOf( mw.config.get( 'wgCanonicalNamespace' ) ) === -1 ) {
var text = i18n[ mw.config.get( 'wgUserLanguage' ) ] || i18n.nl;
var link = mw.util.getUrl( 'Speciaal:Voorvoegselindex/' + mw.config.get( 'wgPageName' ) + '/' );
mw.util.addPortletLink( 'p-tb', link, text, '', 'Subpagina\'s van deze pagina');
};
return;
}
function replaceObsoleteHTMLTags() {
var prev = '', sub='', subColor='', subFace='', subSize='', found='', text='', res='', X, Y, Z;
var objSummary = document.getElementById('wpSummary');
var obj = document.getElementById('wpTextbox1');
if (obj == null) return; /* exit */
if (! (mw.config.get('wgPageContentModel') == 'wikitext')) return; /* exit */
var text = '' + obj.value;
if (text.search(/{{Wiu[2,3]/i) > -1) {
alert('Stop: werk in uitvoering!');
return; /* exit */
}
createDebug();
/* <font> */
while (true) {
// common pt. 1
X = /<font.*?>/i.exec(text); // .exec: if not found: X=null, X[0] etc. = undefined !!
if (X == null) break; // geen font-tags
X = X + ''; // !!
subColor = subFace = subSize = X.replace(/(\x22|\x27)/g, ""); // - ' en "
/* <font color> */
if (subColor.search(/color/i) > -1) {
subColor = /color *= *[a-z,0-9,#]*/i.exec(subColor) + ''; // !!
if (subColor) {
subColor = subColor.replace(/ *= */, ": ") + ";";
subColor = subColor.toLowerCase();
}
}
else {subColor = null;} // geen color-attribute
/* <font face> */
if (subFace.search(/face/i) > -1) {
subFace = subFace.replace(/ *, */g, ",");
subFace = /face *= *[a-z,0-9,\,]*/i.exec(subFace) + ''; // !!
if (subFace) {
subFace = subFace.replace(/,/g, ', ');
subFace = subFace.replace(/face *= */i, 'font-family: ') + ';';
}
}
else {subFace = null;} // geen face-attribute
/* <font size> */
// todo
// tijdelijk: subSize = null;
if (subSize.search(/size/i) > -1) {
debug(subSize); // <font color=red face=Tahoma size=3>
subSize = /(?<=size *= *).*?(?=(\x20,'>'))/i.exec(subSize) + '';
debug(subSize); //
// subSize = subSize.replace(/.../, "...");
}
else {subSize = null;} // geen size-attribute
// tijdelijk:
subSize = null;
// common pt. 2
Y = '<span style="';
//debug(Y);
if (subColor) Y += subColor;
//debug(Y);
if (subFace) Y += (subColor ? ' ' : '') + subFace;
//debug(Y);
if (subSize) Y += (subColor || subFace ? ' ' : '') + subSize;
//debug(Y);
Y += '">';
//debug(Y);
text = text.replace(X,Y);
text = text.replace(/<\/font/ig, "</span");
} // while (true)
/*
ToDo:
- font color/size/face !!!
- uitzonderingen maken voor elementen tussen blockquote-, nowiki-, pre- en comment-tags !
*/
/*** Obsolete elements:***/
/* <big> */
text = text.replace(/(<big>){3,6}/ig, '<span style="font-size: xx-large;">'); //xxx-large werkt niet in Chrome !
text = text.replace(/(<big>){2}/ig, '<span style="font-size: x-large;">');
// 20220106: x-large voor zon en water
if (mw.config.get('wgTitle').indexOf("Leer jezelf ecologisch tuinieren") > -1) {
text = text.replace(/(?<=\| *zon *=.*)<big>/ig, '<span style="font-size: x-large;">');
text = text.replace(/(?<=\| *water *=.*)<big>/ig, '<span style="font-size: x-large;">');
}
text = text.replace(/<big/ig, '<span style="font-size: large;"');
text = text.replace(/(<\/big *[a-z|0-9]*>){1,6}/ig, "</span>");
/* <center> */
text = text.replace(/<center/ig, '<div style="text-align: center;"');
text = text.replace(/<\/center/ig, "</div");
/* <small> */
text = text.replace(/(<small>){3,6}/ig, '<span style="font-size: xx-small;">');
text = text.replace(/(<small>){2}/ig, '<span style="font-size: x-small;">');
text = text.replace(/<small/ig, '<span style="font-size: smaller;"');
text = text.replace(/(<\/small *[a-z|0-9]*>){1,6}/ig, "</span>");
/* <source> 20220116 */
text = text.replace(/<source/ig,'<syntaxhighlight');
text = text.replace(/<\/source/ig,'</syntaxhighlight');
/* <strike> */
text = text.replace(/<strike/ig, "<s");
text = text.replace(/<\/strike/ig, "</s");
/* <tt> */
text = text.replace(/<tt/ig, "<code");
text = text.replace(/<\/tt/ig, "</code");
/*** Diversen: ***/
/* <br> */
text = text.replace(/\x20*<\/?br\x20?\/? ?>/ig, "<br>");
/* <br clear=left/right/all/both> */
text = text.replace(/\x20*<br clear ?= ?(\x22|\x27)?left(\x22|\x27)?\x20?\/?>/ig, '<br style="clear: left;">');
text = text.replace(/\x20*<br clear ?= ?(\x22|\x27)?right(\x22|\x27)?\x20?\/?>/ig, '<br style="clear: right;">');
text = text.replace(/\x20*<br clear ?= ?(\x22|\x27)?(all|both)(\x22|\x27)?\x20?\/?>/ig, '<br style="clear: both;">');
/* <hr> */
text = text.replace(/<\/?hr\x20?\/?>/ig, "<hr>");
text = text.replace(/\[\[categorie/ig, "[[Categorie");
text = text.replace(/\[\[afbeelding/ig, "[[Afbeelding");
/* prettytable */
text = text.replace(/prettytable/ig, "wikitable");
/* WSBN nummer :-( */
text = text.replace(/\[WSBN( |-|_)?nummer/ig, " [WSBN");
text = text.replace(/.*Hier.*onderhoudsmeldingen.*\n/ig, "");
/* . ná <ref> */
while(true) {
X = /(?<!\.) ?<ref>.*?<\/ref>\./.exec(text);
if (X == null) break;
Y = X[0].replace(/ ?<ref>/,'.<ref>');
Y = Y.replace('</ref>.','</ref>');
text = text.replace(X,Y);
}
/* sjablonen en Magic Words */
text = text.replace(/{{{/g, "aW~d6-8Ht#yV_5"); // vervang "{{{" tijdelijk door code om varabelen te onderscheiden van sjablonen
/* Magic Words - 20230323 */
text = text.replace(/\{\{#categorytree:/g, "{{#Categorytree:");
text = text.replace(/\{\{#expr:/g, "{{#Expr:");
text = text.replace(/\{\{\s?#if:\s?/ig, "{{#If:");
text = text.replace(/\{\{ ?#invoke:/g, "{{#Invoke:");
text = text.replace(/\{\{ ?#pos:/g, "{{#Pos:");
text = text.replace(/\{\{ ?#switch:/g, "{{#Switch:");
/* Magic Words met 2 hoofdletters: 20230421 */
text = text.replace(/\{\{ ?#ife/ig, "{{#IfE");
/* oud:
text = text.replace(/\{\{ ?#iferror:/g, "{{#IfError:");
text = text.replace(/\{\{ ?#ifexpr:/g, "{{#IfExpr:");
text = text.replace(/\{\{ ?#ifexist:/g, "{{#IfExist:");
text = text.replace(/\{\{ ?#ifeq:/g, "{{#IfEq:");
*/
/* ISBN 20230625 */
// text = text.replace(/ISBN\s{1,3}/ig, "{{ISBN|");
// debug ("ISBN checken!");
// text = text.replace(/(?<=\{\{ISBN\|[0-9%s]{8,13})(( )|\.|,|\n)/ig, "}} "); // <-
/* ISBN exp. 20240121 */
text = text.replace(/ISBN\s{1,3}([0-9]\-?)*/ig, "{{$&}}");
text = text.replace(/\{\{ISBN\s{1,3}/ig, "{{ISBN|");
/* Sjabloonredirects vervangen 20220209 */
text = text.replace(/{{Beg(innetje)?}}/ig, "{{Begin}}");
text = text.replace(/{{Alleen afdrukken ?(\|\n|\n\|)/ig, '{{Alleen afdrukken inline\n|\n'); // extra \n tbv. sommige wikicodes
text = text.replace(/{{Alleen afdrukken ?\|/ig, '{{Alleen afdrukken inline|');
text = text.replace(/{{Herhalen ?\|/ig, '{{Repeat|');
text = text.replace(/{{Niet afdrukken ?(\|\n|\n\|)/ig, '{{Niet afdrukken block\n|\n'); // extra \n tbv. sommige wikicodes
text = text.replace(/{{Niet afdrukken ?\|/ig, '{{Niet afdrukken block|');
text = text.replace(/\n\| *Moeilijkheid *= *[ a-zA-Z]*/ig, ''); // 20251012
text = text.replace(/{{Zieook ?(\|\n|\n\|)/ig, '{{Zie ook\n|\n'); // extra \n tbv. sommige wikicodes
text = text.replace(/{{Zieook ?\|/ig, '{{Zie ook|');
/* text = text.replace(/{{Crd ?\|/ig, '{{Akkoord|'); klaar */
/* text = text.replace(/{{Akkoorden ?\|/ig, '{{Akkoord|'); klaar */
// eerst toepassen op _alle_ sjablonen, ipv. check op overbodige "|" ?
/* sjabloonnaam met hoofdletter */
{
while(true){
X = /{{[a-z]/.exec(text);
if (X == null) break;
Y = X[0].toUpperCase();
text = text.replace(X,Y);
}
/* Idem in Sjabloon:Tl: 20230421 -- ToDo
while(true){
X = /{{tl\|[A-Za-z]/i.exec(text);
alert("X1=" + X);
if (X == null) break;
alert("X2=" + X);
Y = X[0].toUpperCase();
alert("Y=" + Y);
text = text.replace(X, "{{Tl|" + Y);
alert("3=" + text.replace(X, "{{Tl|" + Y));
/ alert(X + " - " Y + " - " + text.replace(X, "{{Tl|" + Y));
}
*/
// overbodige pipe na sjabloonnaam
prev = text;
text = text.replace(/(?<={{[a-z,0-9, ,-]*) *\| *\n/ig, '\n|\n');
if (!(prev == text)) {
debug('checken: evt. eerste sjabloonparameter(s)!'); // alert
}
}
text = text.replace(/aW~d6-8Ht#yV_5/g, "{{{"); // herstel code naar "{{{" ---------------
/* {{Sub}} onderaan */
X = text.search(/{{sub}}/i);
if (X > -1 && X < 50) {text = text.replace(/{{sub}}\n?/i, '') + '{{Sub}}';}
/* lege regels voor {{sub}} */
text = text.replace(/\n ?\n*{{sub}}/ig,'\n{{Sub}}');
/* <tr> |- */
text = text.replace(/\|-+/g, "|-");
/* overbodige laatste <tr> */
text = text.replace(/ *\|-\x20*\n *\|}/g, "|}");
/* wikicode hr: 4 streepjes */
text = text.replace(/^-{5,}/g, "----");
text = text.replace(/\n-{5,}/g, "\n----");
/* http:// */
prev = text;
text = text.replace(/http:\/\//ig, 'https://');
if (!(prev == text)) {debug('Check externe links (https)!');} // alert
/* "xxe eeuw" in tekst */ { // 20220119
/* disabled: mag geen _links_ wijzigen ! 20220215
text = text.replace(/(?<=(1|2)?[0-9])e eeuw/g,'<sup>e</sup> eeuw');
text = text.replace(/(?<=(1|2)?[0-9])e-eeuw/g,'<sup>e</sup>-eeuw');
*/
}
text = text.replace(/\[\[categorie:/ig, "[[Categorie:");
text = text.replace(/\[\[:categorie:/ig, "[[:Categorie:");
/* Afsluitende tag op Categorie: 20220124, v2 */
if (mw.config.get('wgNamespaceNumber') == 14) {
text = text.replace(/'''{{PAGENAME}}(?!''')/i, "'''{{PAGENAME}}'''");
}
/* Check op nested span tags - 20220218 */
/*
if (text.search(/<\/span( color)?> ?<\/span>/i) > -1 ){
// alert('Check: nested span tags!?');
text = text.replace(/"><span style="/ig, ' ') // erg bot: alleen voor eco tuin ??
text = text.replace(/<\/span( color)?><\/span>/ig, '</span>'); // ,,
}
*/
/* {{Fase0..4}} -> {{Fase|0..4}} */
text = text.replace(/\{\{Fase(?=[0-4])/ig, '{{Fase|'); // 20250810
text = text.replace(/\{\{Fase([1-4])/ig, "{{Fase|$1"); // 20260514 dubbel
/* geen lege regel na kopje - 20230724 */
text = text.replace(/==\n\n(?!==)/g, "==\n");
// komma vóór <ref> // 20251004
text = text.replace(/ \<\/ref\>/ig, '</ref>');
text = text.replace(/ \<\/cite\>/ig, '</cite>');
// links wp fixen: // 20251004
if (mw.config.get('wgNamespaceNumber') == 0) {
text = text.replace(/\[\[:?w:(nl:)?(.*?)\]\]/ig , '{{Wp|$2}}');
}
text = text.replace(/\{\{W\|/ig, '{{Wp|'); // 20251008
text = text.replace(/\{\{W[^a-zA-Z]/ig, "{{Wp"); // dubbel
// objSummary.value = 'Lintfouten: Verouderde HTML elementen';
// document.getElementById('wpSummary').value = 'lf'; // 20260323
text = text.replace(/\{\{Sjabloon:/ig, "{{");
//aap ******* . + * ? ^ $ ( ) [ ] { } | / \ ********
// template:
// text = text.replace(/\{\{/ig, "{{");
text = text.replace(/\{\{Leer jezelf ecologisch tuinieren/ig, "{{Index Leer jezelf ecologisch tuinieren");
text = text.replace(/\{\{Navigatie([\|,\n])/ig, "{{Bladeren2$1"); // 20260516
text = text.replace(/\{\{Talen/ig, "{{Taal- en letterkunde");
/*
if (mw.config.get('wgTitle').indexOf("Programmeren in TI-Basic/") > -1) { // 20260420
text = text.replace(/\{\{Links\}\}\n/i, "");
// text = text + String.fromCharCode(13, 10) + "{{Links}}";
text = text + "{{Links}}";
}
*/
/*
text = text.replace(/\{\{00%/ig, "{{0%");
text = text.replace(/ategorie:GFDL afbeeldingen/ig, "ategorie:Bestanden met GFDL Licentie");
text = text.replace(/ategorie:Afbeelding naar licentie/ig, "ategorie:Bestand naar licentie");
text = text.replace(/ategorie:Wikibooks:Afbeelding beschikbaar op commons met dezelfde naam/ig, "ategorie:Wikibooks:Bestand beschikbaar op commons met dezelfde naam");
text = text.replace(/ategorie:Wikibooks:Afbeelding beschikbaar op commons/ig, "ategorie:Wikibooks:Bestand beschikbaar op commons");
text = text.replace(/ategorie:Wikibooks:Afbeeldingen niet te verplaatsen naar Wikimedia Commons/ig, "ategorie:Wikibooks:Bestand niet te verplaatsen naar Wikimedia Commons");
text = text.replace(/ategorie:PD-afbeeldingen/ig, "ategorie:Bestanden met PD Licentie");
text = text.replace(/ategorie:Ewmulti-afbeeldingen/ig, "ategorie:Bestanden met Ewmulti Licentie");
text = text.replace(/ategorie:Afbeeldingen zonder geldige licentie/ig, "ategorie:Bestanden zonder geldige licentie");
text = text.replace(/ategorie:Wikibooks:Verplaats naar Wikimedia Commons/ig, "ategorie:Wikibooks:Bestand te verplaatsen naar Wikimedia Commons");
text = text.replace(/ategorie:Afbeeldingen met Creative Commons Licentie by-sa/ig, "ategorie:Bestanden met Creative Commons Licentie by-sa");
text = text.replace(/ategorie:Afbeeldingen met Creative Commons Licentie by/ig, "ategorie:Bestanden met Creative Commons Licentie by");
text = text.replace(/ategorie:Afbeeldingen/ig, "ategorie:Bestand");
text = text.replace(/ategorie:Creative Commons-afbeeldingen/ig, "ategorie:Bestanden met Creative Commons Licentie");
*/
text = text.replace(/\{\{Information/i, "{{Informatie");
//text = text.replace(/\{\{Links\}\}\n/i, ""); // 20260412
//text = text.replace(/\{\{Sub\}\}/i, "{{Sub}}\n{{Links}}");
text = text.replace(/Youtube/g, "YouTube"); // 20260406
text = text.replace(/{{Clearboth/ig, "{{Clear both"); // 20260323
text = text.replace(/{{Clearleft/ig, "{{Clear left");
text = text.replace(/( | ){0,3}<ref(?!erences)/ig, ' <ref'); // 1 spatie voor <ref> 20260121
text = text.replace(/<ref(.*)?> <ref/ig, '<ref$1><ref'); // tenzij 2 x ref na elkaar
text = text.replace(/\{\{L\|(.*)\}\}/ig, '[[../$1/]]'); // {{L|x}} -> [[../x/]] 20251229
text = text.replace(/#DOORVERWIJZING ?/ig, '#Redirect ');
if (mw.config.get('wgPageName').indexOf('Sjabloon:Index_') > -1) { // mw.config.get('wgPageName') geeft {{FULLPAGENAME}} !
text = text.replace(/## ?\[\[/g , '**[[');
text = text.replace(/# ?\[\[/g , '*[[');
// ??? text = text.replace(/\[\[Categorie:Sjablonen index\]\]\n?/ig, '');
}
// {{tl}}:
// text = text.replace(/\{\{tl\|(a-z)/ig, '{{Tl|' + '$1'.toUpperCase()); // werkt niet
// text = text.replace(/\{\{tl\|(a-z)/ig, '{{Tl|' + String($1).charAt(0).toUpperCase()); // crasht
// komma in getal -> punt - verder testen! - werkt maar t/m 999,999! :
// text = text.replace(/([0-9]{1,3}),([0-9]{3})/g, '$1.$2');
text = text.replace(/\{\{Schaak\/Bord\|=/ig , '{{Schaak/Bord2'); // 20251030
text = text.replace(/\|\n\|=/ig , '|\n|');
text = text.replace(/(\n[1-8].*?)= ?\n/ig , '$1\n');
text = text.replace(/(\n[1-8].*?)= ?\n/ig , '$1\n');
text = text.replace(/\{\{HTML-standaardattributen/ig, '{{HTML standaardattributen');
text = text.replace(/\{\{HTML (tags|elementen)/ig, '{{Navigatie HTML elementen'); // 20251016
text = text.replace(/\[\[(:)?File:/ig, '[[$1Bestand:'); // 20251009
text = text.replace(/\[\[(:)?Image:/ig, '[[$1Afbeelding:');
text = text.replace(/\n\n?\{\{Recepten\}\}/ig, '\n{{Navigatie recepten}}'); // 20251012
text = text.replace(/\{\{Beg\}\}/ig, '{{Begin}}'); // 20251022
text = text.replace(/\{\{Boekenplanken\}\}/ig, '{{Navigatie boekenplanken}}'); // 20251022
/*** Eenmalige acties ***/
text = text.replace(/\[\[Kookboek\/\bDessert\b/ig, '[[Kookboek/Nagerecht'); // 20251012
text = text.replace(/\{\{TOCRechts/ig, '{{TOC rechts'); // 20230417
text = text.replace(/\{\{Wikt(?=(\||\}))/ig, '{{Wiktionary'); // 20230514
text = text.replace(/\{\{Woordenboek Index\}/ig, '{{Alfabet met links}'); // 20230520
text = text.replace(/se wikipedia/ig, 'stalige Wikipedia'); // 20230614
text = text.replace(/background: ?none;? ?/ig, ''); // 20250711
text = text.replace(/\n?\n\n\n\{\{Recepten\}\}/ig, '\n\n{{Recepten}}'); // 20250805
text = text.replace(/\{\{Recept\n\|\n/ig, '{{Recept\n'); // 20250805
text = text.replace(/(?<![a-zA-Z])NB(\.(\:)?|\:) ?/g, 'NB '); // 20250817
text = text.replace(/Wiskunde voor MBO techniek\//g, 'Wiskunde voor MBO techniek 1/'); // 20250824
/*** Archief eenmalige acties ***/
/*
text = text.replace(/\{\{Recepten/ig, "{{Navigatie recepten");
text = text.replace(/\{\{Recept/ig, "{{Infobox recept"); // 2260516
text = text.replace(/\{\[Clear both/ig , "{{Clear both");
text = text.replace(/{{Clearright/ig , "{{Clear right");
text = text.replace(/{{Boeken/ig , "{{Post-it/Boeken");
// tbv. Maatschappijleer/Alfabetische woordenlijst maatschappijleer - 20260303:
// text = text.replace(/; ?<<!-- ?/ig , ';<!--');
// text = text.replace(/ ?-->span>/ig , '-->');
// text = text.replace(/;<\/span>/ig , ';');
// text = text.replace(/\[\[Categorie:Land\]\]/ig, '[[Categorie:Land in Europa]]'); // 20260125
if (mw.config.get('wgTitle').indexOf('Atlas van') > -1) { // wd-properties vervangen; 20260119
text = text.replace(/(property|statements):P18/ig, '$1:afbeelding');
text = text.replace(/(property|statements):P31/ig, '$1:is een');
text = text.replace(/(property|statements):P35/ig, '$1:staatshoofd');
text = text.replace(/(property|statements):P47/ig, '$1:grenst aan');
text = text.replace(/(property|statements):P122/ig, '$1:regeringsvorm');
text = text.replace(/(property|statements):P206/ig, '$1:gelegen in of aan waterlichaam');
text = text.replace(/(property|statements):P361/ig, '$1:onderdeel van');
text = text.replace(/(property|statements):P571/ig, '$1:datum van oprichting of creatie');
text = text.replace(/(property|statements):P1539/ig, '$1:vrouwelijke bevolking');
text = text.replace(/(property|statements):P1540/ig, '$1:mannelijke bevolking');
text = text.replace(/(property|statements):P2131/ig, '$1:bruto binnenlands product');
}
// tbv. [[Wikibooks:Lijst van eigenschappen van Wikidata-items]]: (20251211))
text = text.replace(/\<br\>\[\[d:Property talk:P[0-9]{1,5}\|talk\]\]\<br\>\[\[d:Wikidata:Database reports\/Constraint violations\/P[0-9]{1,5}\|covi\]\]\|/ig, '|');
// voor [[Onderwijs in relatie tot P2P]] :
text = text.replace(/tot P2P\/(.*)/g, 'tot P2P/$1|$1]]');
text = text.replace(/{{StringReplace ?\|/ig, '{{Replace|');
if (mw.config.get('wgNamespaceNumber') == 3) { // "Overleg gebruiker"; 20251116
text = text.replace(/\{\{Zandbak\}\}/ig, '{{Zb}}');
}
text = text.replace(/\{\{Bladeren(2|3)/ig, '{{Bladeren4'); // 20230531
text = text.replace(/\[\[Categorie:Weglaten bij afdrukken.*?\]\]\n?/ig, ''); // 20251024
text = text.replace(/\{\{Miljoen/ig, '{{Afronden'); // 20251005
// lintfouten: Ingebedde stijlregel voor de achtergrondkleur zonder bijbehorende tekstkleur // 20250711
text = text.replace(/(color: ?(black|inherit); ?)?background(-color)?:/ig, 'color: inherit; background-color:');
if (mw.config.get('wgNamespaceNumber') == 14) { // 20251009
if (mw.config.get('wgTitle').indexOf('- inhoud') > -1) {
text = text.replace(/\n?\[\[Categorie:Hoofdstuk.*?\]\]\n?/ig, '');
if (text.indexOf('Categorie:Inhoud') > -1) {
// window.location.assign('https://nl.wikibooks.org/w/index.php?title=Categorie:Inhoud');
return;
}
text = text.replace(/\n?\[\[Categorie:Inhoud\]\]\n?/ig, '');
text = text + '[[Categorie:Inhoud]]\n'; // toevoegen indien cat:hoofdstuk nog niet aanwezig
// werkt niet (edit wordt niet opgeslagen):
// var Button = document.getElementById("wpSave");
// Button.click();
}
}
var X = mw.config.get('wgPageName');
document.write(X + '__');
var Y = X.search('Wikibooks:Infobox/');
document.write(Y + '__');
if (Y > -1) {
document.write('ja__');
text = text.replace(/--\>\|.*boekenplank.*(taal( en letterkunde)?|talen)/ig, '-->| boekenplank = Taal en letterkunde');// 2025100?
}
text = text.replace(/\{\{Abc\}\}/ig, '{{Alfabet met ankers}}'); // 20230414
text = text.replace(/\[\[Categorie\:Sjablonen sjabloondocumentatie/ig, '[[Categorie:Sjabloondocumentatie');
text = text.replace(/Moderne/g , 'moderne'); // 20251006
text = text.replace(/Hedendaagse/g , 'hedendaagse');
text = text.replace(/Architectuur/g , 'architectuur');
// rode (wp-)links ontlinken:
// tbv. [[Veelvoorkomende misvattingen/Wetenschap en technologie]]
// "lazy" mode: (.*?) - https://javascript.info/regexp-greedy-and-lazy ! :-)
// problemen:
// * afb. met link(s) in de caption gaan stuk -> handmatig op te lossen
// * links met afwijkende omschrijving worden zichtbaar -> niet ,,
// 2: te behouden links veiligstellen:
text = text.replace(/\[\[((Afbeelding|Bestand|bibcode|doi|File|Image|Media):.*?)\]\]/ig, 'REPL251005pre$1REPL251005post');
// 3: alle overige links omzetten naar tekst:
text = text.replace(/\[\[(.*?)\]\]/ig, '$1');
text = text.replace(/\[\[(.*?)\]\]/ig, '$1'); // 2e keer tbv. geneste links!
// 4: te behouden links herstellen:
text = text.replace(/REPL251005pre/g, '[[');
text = text.replace(/REPL251005post/g, ']]');
*/
/*
text = text.replace(/{{Receptmetafbeelding/ig, '{{Infobox recept'); // 20230312, 20251011
te gretig; text = text.replace(/,\<ref\>(.*)\<\/ref\>/ig , '<ref>$1</ref>,'); // 20251004
text = text.replace(/\[Spaans\/Les( |_)0/ig , '[Spaans/Les '); // 20250930
text = text.replace(/Categorie\:Ingrediënt\/Drank/ig , 'Categorie:Drank') // 20250929
text = text.replace(/Categorie\:Kookboek\/Ingrediënt\/Fruit/ig , 'Categorie:Fruit') // ,,
text = text.replace(/Categorie\:Kookboek\/Ingrediënt\/Gevogelte/ig , 'Categorie:Gevogelte') // ,,
text = text.replace(/Categorie\:Kookboek\/Ingrediënt\/Graan/ig , 'Categorie:Graan') // ,,
text = text.replace(/Categorie\:Kookboek\/Ingrediënt\/Groente/ig , 'Categorie:Groente') // ,,
text = text.replace(/Categorie\:Kookboek\/Ingrediënt\/Zuivel/ig , 'Categorie:Zuivel') // ,,
text = text.replace(/Categorie\:Kookboek\/Ingrediënt\/Vruchtensap/ig , 'Categorie:Vruchtensap') // ,,
*/
/* text = text.replace(/Italiaans.*Antwoorden.*\]\]/g, mw.config.get('wgTitle') + '/Antwoorden]]'); // 20250920 */
/* text = text.replace(/Italiaans\/Les0?/g, 'Italiaans/Les '); // 20250920 */
/* text = text.replace(/ hele )/ig, ' heel '); //20250920 */
/* text = text.replace(/WikiJunior/g, 'Wikijunior'); // 20250718 */
/* text = text.replace(/\{\{TOCLinks/ig, '{{TOC links'); // 20230417 */
/* text = text.replace(/\/(.{1,65})\]\]/ig, '/$1|$1]]'); // 20250903 */
/* text = text.replace(/\{\{Uitleg\|(.{5,43})\|(.{5,43})\}\}/ig, '{{Hover|tekst=$2|hovertekst=$1}}'); // 20250901 */
/* text = text.replace(/\{\{Tuin(\n|\|)/i, '{{Tuinkalender'); // 20250803 */
/* text = text.replace(/\{\{Tuinkalender\|Pagina.*tuinieren\/(.*)\|tuinkalender\]\]\n?\|Onderdeel\=(.*)\n\}\}/i, '{{Tuinkalender|$1|$2}}'); // 20250831 */
/* text = text.replace(/(?<=g)allerij/ig, 'alerij'); // 20230614 */
/* text = text.replace(/(?<=t)utti frutti/ig, 'uttifrutti'); // 20250817 */
/* text = text.replace(/\{\{\#babel\:/ig, '{{Babel|'); // 20250813 */
/* text = text.replace(/\n/g, ']]\n'); // 20250812 */
/* text = text.replace(/gerbuik/g, 'gebruik'); // 20250806 */
/* text = text.replace(/\{\{Noindex\}\}/ig, '__NOINDEX__'); */
/* text = text.replace(/\{\{Clear\}\}/ig, '{{Clearboth}}'); */
/* text = text.replace(/\| ?Naam ? ?= ? ?{{PAGENAME}}/, '| Naam = '); // 20250805 */
/* text = text.replace(/Categorie:Sjablonen voor een bepaald boek/ig, 'Categorie:Sjablonen talen en dialecten'); */
/* text = text.replace(/Categorie\:Fase(?=[0-4])/ig, 'Categorie:Fase ');*/ // 20250803
/* 1e img van Sjabloon:Gestarte boeken verwijderen */
// text = text.replace(/ ?\[\[Bestand:.-4\.svg\|.px\]\] ?/ig , '\n'); // 20250722
// text = text.replace(/ /ig , ' ');
// text = text.replace(/\* ? ?/ig , '<br>\n');
// text = text.replace(/\]\] \{\{/ig , ']]{{');
// text = text.replace(/\{\{0%/ig , '00%');
//text = text.replace(/Chillipepers\.nl/ig, 'chillipepers.nl'); // 20250722
//text = text.replace(/Chillipeper\.nl/ig, 'chillipeper.nl'); // ,,
// text = text.replace(/Basiskennis( |_)chemie6\//g, 'Basiskennis chemie 6/'); // 20250906
// // document.getElementById('wpSummary').value = 'lf'; werkt niet!??
// ---------------------------------------------------------------------------------------------
/* tbv. lintfouten op overleg gebruiker */
// text = text.replace(/('''|\<\/?b\>)/ig, ""); /* 20230627 */
/* tbv. verkeerd geneste tags op overleg:gebruiker */
// text = text.replace(/\<\/?span.*?\>/ig, ""); /* 20230627 */
// obj.value = 'Lintfouten: Verkeerd geneste tags';
/* test: CSS beter leesbaar maken - 20230519 */
text = text.replace(/(?<=style\=\".*): *(?=\>)/ig, ": "); /* too greedy; check "http(s):, /File: etc. ! */
text = text.replace(/(?<=style\=\"); ?(?=\")/ig, "; ");
/* ------ oud -------------
text = text.replace(/\[\[Categor(ie|y):Sjablonen(?=[\||\]\]])/ig, '[[Categorie:Sjablonen Wikibooks-gebruikers');
text = text.replace(/\[\[Categor(ie|y):Sjablonen(?=[\||\]\]])/ig, '[[Categorie:Sjablonen voor een bepaald boek');
// "xxe eeuw" in titel { // 20220119
var title = mw.config.get('wgTitle');
var pattern = /(?<=(1|2)?[0-9])e-eeuw/;
if (text.search(/{{DISPLAYTITLE:/) == -1) {
if (title.search(pattern) > -1) {
text = '{{DISPLAYTITLE:' + title.replace(pattern,'<sup>e</sup>-eeuw') + '}}' j+ text;
}
}
else debug('{{DISPLAYTITLE: is niet vervangen');
}
// tijdelijk (tbv "Lintfouten: Afsluitende tag ontbreekt")
text = text.replace(/{{cat\|?/ig, "{{Cat");
text = text.replace(/{{boekcat\|/ig, "{{Boekcat");
text = text.replace("'''{{PAGENAME}}", "'''{{PAGENAME}}'''");
*/
/* verplaatsen naar andere categorie:
text = text.replace(/\[\[Categorie:Aardrijkskunde/ig, "[[Categorie:Geografie");
*/
/* sig BeeBringer:
text = text.replace(/\[\[Bestand:BeeBringer.png\]\].*?\<\/sup>/, '\n[[Gebruiker:BeeBringer|BeeBringer]] [[Overleg_gebruiker:BeeBringer|overleg]]');
text = text.replace(/u wijzingen/, 'uw wijzigingen');
*/
/* div. typefouten */
// text = text.replace(/(?<=w)ijzingen/, 'ijzigingen');
text = text.replace(/paramaters/, 'parameters');
/*** Einde ***/
/* niets veranderd? */
if (obj.value == text) return; /* exit */
obj.value = text; /* klaar om op te slaan */
// obj.value = obj.value + '\n\n' + text; // TIJDELIJK!!
/*** Samenvatting ***/
var obj = document.getElementById('wpSummary');
// obj.value = 'cat';
// obj.value = 'Lintfouten: Verouderde HTML-elementen';
// obj.value = 'Lintfouten: Afsluitende tag ontbreekt';
/* tijdelijk (voor eenmalige acties): */
// obj.value = '[[Categorie:Sjablonen voor een bepaald boek]]';
// obj.value = '[[Categorie:Sjablonen Wikibooks-gebruikers]]';
/*** Niet volgen tenzij reeds eerder gevolgd ***/
var obj = document.getElementById('ca-watch');
if (obj) {document.getElementById('wpWatchthis').checked = false;}
return;
}
function addPurgeTab() {
/* Voegt een "purge" tabje toe
(bron: https://nl.wikipedia.org/wiki/Gebruiker:Pjetter/monobook.js) */
if(!document.getElementById) return;
var x = document.getElementById('ca-history');
if(! x) { return; }
var tabs = document.getElementById('p-cactions').getElementsByTagName('ul')[0];
if(x.children) { x = x.children[0]; }
else { x = x.childNodes[0]; }
addlilink(tabs, x.href.replace(/=history/, "=purge"), 'purge', 'ca-purge');
// ta['ca-purge'] = ['g', 'Purge the internal cache for this page']; // "ta is not defined"
}
function addlilink(tabs, url, name, id) {
/* voegt tabjes toe
(bron: https://nl.wikipedia.org/wiki/Gebruiker:Pjetter/monobook.js) */
var na = document.createElement('a');
na.href = url;
na.appendChild(document.createTextNode(name));
var li = document.createElement('li');
li.id = id;
li.appendChild(na);
tabs.appendChild(li);
return li;
}
function experiment() { // (om 'Inklappen' resp. 'Uitklappen' te vervangen)
UitklapDivHide = '▲'; // U+25B2 kleiner: ▴ u+25B4 werkt niet
UitklapDivShow = '▼'; // U+25BC kleiner: ▾ u+25BE ,, ,,
}
function automatePurgeConfirmationDialog() {
/* Automate purge confirmation dialog. (https://en.wikipedia.org/wiki/Wikipedia:Purge) */
if (mw.config.get('wgAction') === 'purge' ) {
$('form[action*="action=purge"]').submit();
}
return;
}
function markeerLintErrors() { // 20220114
// Markeert aantallen > 0 op Speciaal:LintErrors met een rode achtergrond.
if (! (mw.config.get('wgPageName') == 'Speciaal:LintErrors')) return; /* exit */
var list = document.getElementsByTagName("BDI");
if (list.length == 0) return;
for (i=0; i<list.length; i++) {
if (! (list[i].innerHTML == '(0 fouten)')) {
list[i].style.background = '#ff8080';
}
}
return;
}
function createDebug() { // v2, 20220113
// Creëert een debug-venster direct boven het bewerkingsvak.
var obj = document.getElementById('wpTextbox1');
var parent = document.getElementById('editform');
var newItem = document.createElement("DIV");
newItem.id = 'debug';
newItem.style.display='none';
var textnode = document.createTextNode("");
newItem.appendChild(textnode);
parent.insertBefore(newItem, obj);
}
function debug(txt) {
// Voegt een regel tekst toe aan het debug-venster.
var obj = document.getElementById('debug');
if (obj == null) return; /* exit */
obj.style.display = 'block';
obj.innerHTML = obj.innerHTML + txt.replace(/</g,'<') + '<br>';
}
function massDelete() { /* tbv. verwijderen ~450 pagina's, zie lijst op LJET/Gewenste pagina's */
if (mw.config.get('wgTitle').indexOf('Leer jezelf') == -1) return;
if (mw.config.get('wgAction') != 'delete') return;
document.getElementById('ooui-php-2').value = 'Verwijdersessie 3 september 2025';
document.getElementById("deleteconfirm").submit();
return;
}
function insertTekst() {
var title = mw.config.get('wgTitle');
if ((title.search(/Kookboek [0-9]{1,2} /i)) == 0) {
if (mw.config.get('wgNamespaceNumber') == 10) {
if (mw.config.get('wgAction') == 'view') {
window.location += '?action=edit';
var text = document.getElementById('wpTextbox1').value;
text = '__EXPECTUNUSEDCATEGORY__\n' + text;
}
}
}
return;
}
function capFirst(str) {
/* fix all-caps en camel-case */
return str[0].toUpperCase() + str.slice(1).toLowerCase();
}
// </nowiki>
4bhuoeseeqxf16ey1qjh8vsmnpcdlio