#ASP.NET: UserControl dynamisch laden

Webseiten sind nicht immer statisch verdrahtet. Manchmal benötigt man eine Möglichkeit, UserControls dynamisch nachzuladen. Mit Hilfe von ein wenig Code geht sowas ohne großen Aufwand.

Gegeben sei ein einfaches UserControl TextDisplay.ascx, das eine TextBox anzeigt oder alternativ den eingegebenen Text darstellt:

<%@ Control Language="C#" ClassName="TextDisplayControl" %>
<script runat="server">
   /// <summary>
   /// Zugriff auf den angezeigten Namen
   /// </summary>
   public String Text
   {
      get
      {
         return tbName.Text;
      }
      set
      {
         tbName.Text = value;
      }
   }

   /// <summary>
   /// Behandelt das PreRender-Ereignis
   /// </summary>
   protected override void OnPreRender(EventArgs e)
   {
      // Überprüfen, ob ein PostBack stattgefunden hat
      if(!IsPostBack)
      {
         // Initial das Eingabefeld anzeigen
         ToggleVisibility(true);
      }

      // Daten binden lassen
      DataBind();

      // Weiter verarbeiten lassen
      base.OnPreRender(e);
   }

   /// <summary>
   /// Schaltet die Sichtbarkeit der PlaceHolder um
   /// </summary>
   private void ToggleVisibility(bool showEnterText)
   {
      // Anzeige umschalten
      phEnterText.Visible = showEnterText;
      phShowText.Visible = !showEnterText;
   }

   /// <summary>
   /// Aktiviert die Texteingabe
   /// </summary>
   protected void EditText(object sender, EventArgs e)
   {
      // Eingabefeld anzeigen lassen
      ToggleVisibility(true);
   }

   /// <summary>
   /// Aktiviert die Textausgabe
   /// </summary>
   protected void ShowText(object sender, EventArgs e)
   {
      // Ausgabefeld anzeigen lassen
      ToggleVisibility(false);
   }
</script>
<asp:PlaceHolder runat="server" ID="phEnterText">
   <div>Ihr Name</div>
   <div><asp:TextBox runat="server" ID="tbName" /></div>
   <div><asp:Button runat="server" ID="tbButtonShow"
      Text="Anzeigen" OnClick="ShowText" /></div>
</asp:PlaceHolder>
<asp:PlaceHolder runat="server" ID="phShowText">
   <div>Hallo, <asp:Label runat="server" Text="<%# tbName.Text %>" /></div>
   <div><asp:Button runat="server" ID="tbButtonEdit"
      Text="Bearbeiten" OnClick="EditText" /></div>
</asp:PlaceHolder>

Dieses Steuerelement verfügt über zwei Buttons, deren Ereignisbehandlungsmethoden ShowText und EditText die Umschaltung der beiden Platzhalter, in denen sich die Eingabe- bzw. Ausgabe-Elemente befinden, steuern. Dabei kommt der Standard-ASP.NET-Ereignisverarbeitungsmechanismus zu Einsatz.

In einer Page oder einem übergeordneten Steuerelement wird dieses Control nun dynamisch geladen. Dabei kommt die Methode LoadControl() der Page- bzw. Control-Klasse zum Einsatz. Diese nimmt als Parameter den relativen oder absoluten Pfad zum zu ladenden Steuerelement entgegen. Wichtig dabei ist, das sich das Steuerelement innerhalb des Applikationsverzeichnisses befinden muss – ein Steuerelement aus einem anderen Verzeichnis lässt sich so nicht laden.

Beim Init-Ereignis des ladenden Steuerelements findet der eigentliche Aufruf von LoadControl() statt. Bezogen auf die Ereignisreihenfolge ist Init eines der sehr am Anfang stehenden Ereignisse und möglicherweise nicht ideal bezogen auf das Auslesen von Informationen aus dem Benutzerkontext (Session), denn dieser steht hier noch nicht zur Verfügung. Soll jedoch die Ereignisbehandlung innerhalb des zu ladenden Steuerelements wie gewohnt ablaufen, ist der Eintritt des Init-Ereignisses der beste Zeitpunkt – spätere Events würden dazu führen, das innerhalb des geladenen Steuerelements unter Umständen keine ordnungsgemäße Abarbeitung der Lebenszyklen stattfinden kann (ViewState wird nicht richtig geladen, Events werden nicht korrekt geworfen, etc.).

Nachdem das Steuerelement geladen worden ist, liegt es als Instanz vom Typ Control vor, ist also eher generischen Charakter. Ist jedoch der Klassenname bekannt, kann die geladene Instanz in den konkreten Typ konvertiert werden. Damit sind sämtliche typspezifische Eigenschaften und Methoden erreichbar und können manipuliert werden.

Zuletzt muss das Steuerelement einem anderen, in der Seite befindlichen Steuerelement zur Anzeige zugewiesen werden. Dies geschieht mit Hilfe der Add()-Methode von dessen Controls-Auflistung.

Der Code einer Seite, die das Steuerelement TextDisplay.ascx lädt und einbindet, sieht letztlich so aus:

<%@ Page Language="C#" %>
<script runat="server">

   /// <summary>
   /// Behandelt das Init-Ereignis der Seite
   /// </summary>
   protected override void OnInit(EventArgs e)
   {
      // Laden des Controls
      Control textDisplay = LoadControl("~/TextDisplay.ascx");

      if(!IsPostBack)
      {
         // Control in den konkreten Typ umwandeln
         TextDisplayControl tdc = textDisplay as TextDisplayControl;

         // Initialen Text setzen
         tdc.Text = "Karsten";
      }

      // Control an den PlaceHolder anfügen
      phData.Controls.Add(textDisplay);

      base.OnInit(e);
   }

</script>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
   "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
   <head runat="server">
      <title>Eingabeseite</title>
   </head>
   <body>
      <form id="form1" runat="server">
         <h1>Hier können Sie Ihren Namen eingeben</h1>
         <div>
            <asp:PlaceHolder runat="server" ID="phData" />
         </div>
      </form>
   </body>
</html>

Falls Sie sich fragen, woher in Zeile 15 der Klassenname TextDisplayControl stammt: Der wurde in der Control-Deklaration mit Hilfe des Attributs ClassName definiert:

<%@ Control Language="C#" ClassName="TextDisplayControl" %>

Ruft ein Benutzer die Seite im Browser auf, erhält er initial folgende Ausgabe:

Eingabeseite - Opera

Gibt er einen Namen ein und betätigt die Schaltfläche Anzeigen, wird zur zweiten Ansicht gewechselt:

Eingabeseite - Opera (2)

Der Wechsel auf die Eingabeseite zurück geschieht durch Klick auf die Schaltfläche Bearbeiten.

Zusammenfassend bleibt festzuhalten: Steuerelemente lassen sich dynamisch über die Methode LoadControl() nachladen. Sie können anschließend in ihren konkreten Typ konvertiert werden. Wichtig ist, das dieser Prozess so zeitig wie möglich im Lebenszyklus der Seite stattfindet, damit die Ereignisse und Verarbeitungen des dynamisch nachgeladenen Steuerelements korrekt verarbeitet werden können.

Kategorie: ASP.NET, Tipp Kommentieren »


Kommentar schreiben

Kommentar