ASP.NET

Mit ParseControl Steuerelemente dynamisch zur Laufzeit erzeugen

Erstellung eines Seitennavigators mit dem StringBuilder

Aufgrund des aktuell recht miesen Ladeverhaltens der auf zerbit.de bislang verwendeten live-Searchbox für die Suche in diesem Web, habe ich mich entschlossen BOSS (Build your own Search Engine) von Yahoo einmal auszuprobieren. Schön an dieser Lösung ist, daß man die Suchergebnisse über eine API im XML-Format abrufen und sie dann nahtlos in das Layout der eigenen Seite integrieren kann.

Notwendig war in diesem Zusammenhang natürlich auch ein Seiten-Navigator, wie man ihn auf Suchergebnisseiten gewohnt ist. Je nachdem wieviele Gesamttreffer eine Suche ergibt und wieviele Treffer auf einer Seite dargestellt werden, sollten unterschiedlich viele Seiten-Links (dargestellt als kleine Buttons) im Navigator enthalten sein, jedoch maximal 15 um einzeilig zu bleiben. Bei der Anzeige einer Seite größer als 15, sollte der Navigator "nach rechts rollen", d.h. der erste darzustellende Seiten-Link sollte sich um eins verschieben, bis die maximale Anzahl an Seiten erreicht ist.

Möglichkeiten

Eine mögliche Lösung für die Implementierung des Navigators wären statische Hyperlink-Controls gewesen, die in Abhängigkeit der anzuzeigenden Trefferseite ihren Text und ihren Link ändern, aber damit wäre die maximale Anzahl an Seitenlinks per Code auf 15 zementiert und wenig Raum für eine schnelle Anpassung, wenn es dann doch einmal mehr sein sollten. Die größte Flexibilität wäre erreicht, wenn man in der web-config definieren könnte, wie "breit" der Navigator sein soll und der Code dies dynamisch in HTML umsetzt.

Für dieses Problem bietet ASP.NET über die Methode Controls.Add die Möglichkeit zur Laufzeit Steuerelemente in einen beliebigen Container einzufügen, wie unter anderem Uwe Grone in seinem MSDN Solve Artikel beschreibt.

  Dim lnk As HyperLink = New HyperLink()
  lnk.Text = "..."
  lnk.NavigateUrl = "..."
  Me.Panel1.Controls.Add(lnk)

Dieser Ansatz hat allerdings den Haken, dass das Hyperlink-Control keinen Konstruktor bietet, mit dem man die notwendigen Attribute direkt übergeben kann. Bei einer nicht bekannten Anzahl an zu erzeugenden Controls kommt da recht viel Code zustande, vor allem, wenn man zwei Navigatoren braucht: einen oben auf der Seite und den anderen unten.

Das weit aus Beste wäre, schlicht puren HTML-Code als Text in einer Schleife zu erzeugen und diesen dann in den Container zu "injizieren". Man hätte die größtmögliche Kontrolle über die Ausgabe und könnte den HTML-Code mehrmals verwenden.

ParseControl

Auch dafür bietet ASP.NET eine Lösung. Eine recht unscheinbare, aber wenn man genauer darüber nachdenkt, wohl eine der mächtigsten Methoden bei der Erstellung von HTML-Code: ParseControl. Sie ist in der Lage zur Laufzeit aus übergebenem Markup Steuerelemente zu erstellen. Dies funktioniert nicht nur mit simplen HTML-Controls, sondern ebenfalls mit WebServer- und anderen Controls. Abgeleitet von TemplateControl steht ParseControl in allen UserControls und vor allem im Page-Objekt zur Verfügung und stellt eine Art Control-Evaluator dar.

Der Seitennavigator

Mit dieser Methode ist die Erstellung des dynamischen Seitennavigators ein Kinderspiel. Zur Erstellung des Navigator-Control-Strings, den ParseControl auswerten soll, sind zuvor allerdings ein paar Berechnungen notwendig.

Zunächst wird die Gesamtzahl der Treffer benötigt, die Yahoo BOSS im XML mitliefert: intTotalHits. Die maximale Anzahl an Suchtreffern pro Seite (intMaxHitsPerPage) und die maximale Anzahl der Seiten-Links im Navigator (intMaxPages) wird aus der web.config ausgelesen. Um die erste und die letzte anzuzeigende Seite im Navigator zu bestimmen, müssen die Rotationspunkte errechnet werden, sprich ab welcher Seite verschiebt sich die erste Seite um eins (intRotationLeft) und wann hört die Verschiebung auf (intRotationRight).

Mit Übergabe der anzuzeigenden Trefferseite (intPage) sieht die Berechnung dann wie folgt aus:

   Dim intTotalHits As Integer = (... aus Yahoo-BOSS-XML)
   Dim intMaxHitsPerPage As Integer = (...aus web-config)
   Dim intMaxPages As Integer = (...aus web-config)
   Dim intPage As Integer = (... aus Request.QueryString)

   'Gesamtseitenzahl ermitteln
   Dim intTotalPages As Integer = intTotalHits \ intMaxHitsPerPage
   If intTotalHits Mod intMaxHitsPerPage > 0 Then intTotalPages += 1

   'Erste und letzte Seite im Navigator errechnen
   Dim intFirstPage As Integer = 1
   Dim intLastPage As Integer = intMaxPages
   If intMaxPages > intTotalPages Then intLastPage = intTotalPages

   Dim intRotationLeft As Integer = intMaxPages \ 2
   If intMaxPages Mod 2 > 0 Then intRotationLeft += 1

   Dim intRotationRight As Integer = intTotalPages - intRotationLeft - 1

   If intTotalPages > intMaxPages And intPage > intRotationLeft Then
      If intPage <= intRotationRight Then
         intFirstPage = intPage - intRotationLeft + 1
      Else
         intFirstPage = intTotalPages - intMaxPages + 1
      End If

      If intPage <= intRotationRight Then
         intLastPage = intFirstPage + intMaxPages - 1
      Else
         intLastPage = intTotalPages
      End If

   End If

Der Rest ist ein simples Zusammenstellen eines Strings aus A-Elementen und einem STRONG-Element mittels des StringBuilders...

   Dim stbNav As New StringBuilder
   Dim strPage As String = ResolveClientUrl("~/search.aspx?s=" & strSearchString)

   'eine Seite zurück
   If intPage > 1 Then
      stbNav.Append("<a href=""" & strPage & "&page=" & intPage - 1 & """>zurück</a>")
   End If

   'Seiten bis aktuelle
   For i As Integer = intFirstPage To intPage - 1
      stbNav.Append("<a href=""" & strPage & "&page=" & i & """>" & i & "</a>")
   Next

   'aktuelle Seite
   stbNav.Append("<strong>" & intPage & "</strong>")

   'Seiten ab aktueller
   For i As Integer = intPage + 1 To intMaxPages
      stbNav.Append("<a href=""" & strPage & "&page=" & i & """>" & i & "</a>")
   Next

   'eine Seite vor
   If intPage < intLastPage Then
      stbNav.Append("<a href=""" & strPage & "&page=" & intPage + 1 & """>weiter</a>")
   End If

... und die Ausgabe des Strings über ParseControl in je einen Panel-Container am Anfang und am Ende der Seite.

   'Navigator in Container einfügen
   Me.panNavTop.Controls.Add(ParseControl(stbNav.ToString))
   Me.panNavBottom.Controls.Add(ParseControl(stbNav.ToString))

Fazit

Anhand dieses Beispiels kann man sich vorstellen, wie schnell und einfach man über ParseControl Seiten dynamisch generieren kann. Machbar wären so zum Beispiel auch komplett aus Datenbanken heraus erzeugte Web-Seiten.


kick it on dotnet-kicks.de
kick it on dotnet-kicks.de AddThis 0 wikio-Stimme(n) Trackback-Url...

Keine Kommentare bislang...

Dein Kommentar hierzu...


Kommentar-Feed für diesen Beitrag
Gravatare werden unterstützt .:. eMail-Adressen werden nicht veröffentlicht
 

RSS-Feed

Die URL des Standard-Newsfeed von zerbit.de lautet:

http://www.zerbit.de/rssfeed.aspx

Login


 

 

Statistik



kürzlich kommentiert

Artikel 269

  • Datum: 15.09.2008
    Kategorie: ASP.NET
    Zugriffe: 2.631
    Kommentare: 0
    Trackbacks: 0

Letzte Beiträge

Kategorien

Buttons & More

Blog-Roll

Banner Piraten-Partei