Share via


Programmgesteuertes Festlegen der Masterseite (C#)

von Scott Mitchell

Hier wird die master Seite der Inhaltsseite programmgesteuert über den PreInit-Ereignishandler festgelegt.

Einführung

Seit dem ersten Beispiel in Erstellen eines Site-Wide Layouts mithilfe von Gestaltungsvorlagen haben alle Inhaltsseiten über das Attribut in der @Page Direktive deklarativ auf ihre MasterPageFile master Seite verwiesen. Die folgende @Page Direktive verknüpft beispielsweise die Inhaltsseite mit der master SeiteSite.master:

<%@ Page Language="C#" MasterPageFile="~/Site.master" ... %>

Die Page -Klasse im System.Web.UI Namespace enthält eine MasterPageFile Eigenschaft, die den Pfad zur master Seite der Inhaltsseite zurückgibt. Diese Eigenschaft wird von der @Page -Direktive festgelegt. Diese Eigenschaft kann auch verwendet werden, um die master Seite der Inhaltsseite programmgesteuert anzugeben. Dieser Ansatz ist nützlich, wenn Sie die master Seite basierend auf externen Faktoren dynamisch zuweisen möchten, z. B. der Benutzer, der die Seite besucht.

In diesem Tutorial fügen wir unserer Website eine zweite master Seite hinzu und entscheiden dynamisch, welche master Seite zur Laufzeit verwendet werden soll.

Schritt 1: Ein Blick auf den Seitenlebenszyklus

Wenn eine Anforderung auf dem Webserver für eine ASP.NET Seite eingeht, die eine Inhaltsseite ist, muss das ASP.NET-Modul die Inhaltssteuerelemente der Seite mit den entsprechenden ContentPlaceHolder-Steuerelementen der master Seite verschmelzen. Durch diese Fusion wird eine einzelne Steuerungshierarchie erstellt, die dann den typischen Seitenlebenszyklus durchlaufen kann.

Abbildung 1 veranschaulicht diese Fusion. Schritt 1 in Abbildung 1 zeigt den anfänglichen Inhalt und master Seitensteuerungshierarchien. Am Ende der PreInit-Phase werden die Inhaltssteuerelemente auf der Seite zu den entsprechenden ContentPlaceHolders auf der seite master (Schritt 2) hinzugefügt. Nach dieser Fusion dient die Seite master als Stamm der Hierarchie des fusionierten Steuerelements. Diese fusionierte Steuerelementhierarchie wird dann der Seite hinzugefügt, um die endgültige Steuerelementhierarchie zu erzeugen (Schritt 3). Das Nettoergebnis besteht darin, dass die Steuerelementhierarchie der Seite die Hierarchie des fusionierten Steuerelements enthält.

Die Steuerelementhierarchien der Gestaltungsvorlage und der Inhaltsseite werden während der PreInit-Phase miteinander verschmolzen

Abbildung 01: Die Gestaltungsvorlage und die Inhaltsseite-Steuerelementhierarchien werden während der PreInit-Phase miteinander verschmolzen (Klicken Sie hier, um das bild in voller Größe anzuzeigen)

Schritt 2: Festlegen derMasterPageFileEigenschaft über Code

Welche master Seite an dieser Fusion beteiligt ist, hängt vom Wert der -Eigenschaft des PageMasterPageFile Objekts ab. Das Festlegen des MasterPageFile Attributs in der @Page -Anweisung hat den Nettoeffekt, dass die PageEigenschaft der 's MasterPageFile während der Initialisierungsphase zugewiesen wird, die die erste Phase des Lebenszyklus der Seite ist. Alternativ können wir diese Eigenschaft programmgesteuert festlegen. Es ist jedoch zwingend erforderlich, dass diese Eigenschaft festgelegt wird, bevor die Fusion in Abbildung 1 erfolgt.

Am Anfang der PreInit-Phase löst das Page Objekt sein Ereignis aus PreInit und ruft seine OnPreInit -Methode auf. Um die master Seite programmgesteuert festzulegen, können wir dann entweder einen Ereignishandler für das PreInit Ereignis erstellen oder die OnPreInit -Methode überschreiben. Sehen wir uns beide Ansätze an.

Öffnen Default.aspx.csSie zunächst die CodeBehind-Klassendatei für die Homepage unserer Website. Fügen Sie einen Ereignishandler für das Ereignis der Seite PreInit hinzu, indem Sie den folgenden Code eingeben:

protected void Page_PreInit(object sender, EventArgs e) 
{ 
}

Hier können wir die MasterPageFile -Eigenschaft festlegen. Aktualisieren Sie den Code so, dass er den Wert "~/Site" zuweist. master" an die MasterPageFile -Eigenschaft.

protected void Page_PreInit(object sender, EventArgs e) 
{
    this.MasterPageFile = "~/Site.master"; 
}

Wenn Sie einen Haltepunkt festlegen und mit dem Debuggen beginnen, sehen Sie, dass der Ereignishandler bei jedem Besuch der Default.aspx Seite oder bei einem Postback auf dieser Seite Page_PreInit ausgeführt wird und die MasterPageFile Eigenschaft "~/Site.master" zugewiesen ist.

Alternativ können Sie die -Methode der Page -Klasse OnPreInit überschreiben und die MasterPageFile -Eigenschaft dort festlegen. In diesem Beispiel legen wir nicht die master Seite auf einer bestimmten Seite fest, sondern in BasePage. Denken Sie daran, dass wir im Tutorial Angeben von Titel, Metatags und anderen HTML-Headern im Gestaltungsvorlagen-Tutorial eine benutzerdefinierte Basisseitenklasse (BasePage) erstellt haben. Derzeit BasePage überschreibt die -Methode der Page -Klasse OnLoadComplete , bei der die Eigenschaft der Seite Title basierend auf den Siteübersichtsdaten festgelegt wird. Aktualisieren wir, BasePage um auch die OnPreInit -Methode außer Kraft zu setzen, um die master Seite programmgesteuert anzugeben.

protected override void OnPreInit(EventArgs e) 
{ 
    this.MasterPageFile = "~/Site.master"; 
    base.OnPreInit(e); 
}

Da alle Unsere Inhaltsseiten von BasePageabgeleitet sind, wird ihnen jetzt ihre master Seite programmgesteuert zugewiesen. An diesem Punkt ist der PreInit Ereignishandler in Default.aspx.cs überflüssig. Sie können ihn entfernen.

Was ist mit der@PageRichtlinie?

Was etwas verwirrend sein kann, ist, dass die Eigenschaften der Inhaltsseiten MasterPageFile jetzt an zwei Stellen angegeben werden: programmgesteuert in der Methode der BasePage Klasse OnPreInit sowie über das Attribut in der MasterPageFile Anweisung jeder Inhaltsseite @Page .

Die erste Phase des Seitenlebenszyklus ist die Initialisierungsphase. Während dieser Phase wird der Page -Eigenschaft des Objekts der Wert des MasterPageFile Attributs MasterPageFile in der @Page Direktive zugewiesen (sofern er angegeben wird). Die PreInit-Phase folgt der Initialisierungsphase, und hier legen wir die Eigenschaft des PageMasterPageFile Objekts programmgesteuert fest, wodurch der wert überschrieben wird, der aus der @Page Direktive zugewiesen wurde. Da wir die Page Eigenschaft des MasterPageFile Objekts programmgesteuert festlegen, können wir das Attribut aus der MasterPageFile@Page Direktive entfernen, ohne die Benutzeroberfläche des Endbenutzers zu beeinträchtigen. Um sich davon zu überzeugen, entfernen Sie das Attribut aus der MasterPageFile@Page Direktive in Default.aspx , und besuchen Sie die Seite dann über einen Browser. Wie zu erwarten, ist die Ausgabe die gleiche wie vor der Entfernung des Attributs.

Ob die MasterPageFile -Eigenschaft über die @Page -Direktive festgelegt wird oder programmgesteuert festgelegt wird, ist für die Benutzeroberfläche des Endbenutzers inkonsequent. Das MasterPageFile Attribut in der @Page Direktive wird jedoch während der Entwurfszeit von Visual Studio verwendet, um die WYSIWYG-Ansicht im Designer zu erstellen. Wenn Sie in Visual Studio zur Default.aspx Designer navigieren, wird die Meldung "Gestaltungsvorlagenfehler: Die Seite enthält Steuerelemente, die einen Gestaltungsvorlagenverweis erfordern, aber keines angegeben ist" (siehe Abbildung 2).

Kurz gesagt, Sie müssen das MasterPageFile Attribut in der @Page Direktive belassen, um eine umfassende Entwurfszeit in Visual Studio nutzen zu können.

Visual Studio verwendet das masterPageFile-Attribut der <span class=@Page-Direktive , um die Entwurfsansicht zu rendern" />

Abbildung 02: Visual Studio verwendet das Attribut der @Page Direktive MasterPageFile , um die Entwurfsansicht zu rendern (Klicken Sie hier, um das bild in voller Größe anzuzeigen)

Schritt 3: Erstellen einer alternativen Gestaltungsvorlage

Da die master Seite einer Inhaltsseite programmgesteuert zur Laufzeit festgelegt werden kann, ist es möglich, eine bestimmte master Seite basierend auf einigen externen Kriterien dynamisch zu laden. Diese Funktionalität kann in Situationen nützlich sein, in denen das Layout der Website je nach Benutzer variieren muss. Für instance kann es eine Webanwendung der Blog-Engine ihren Benutzern ermöglichen, ein Layout für ihren Blog auszuwählen, in dem jedes Layout einer anderen master Seite zugeordnet ist. Wenn ein Besucher den Blog eines Benutzers zur Laufzeit anzeigt, muss die Webanwendung das Layout des Blogs bestimmen und die entsprechende master Seite dynamisch der Inhaltsseite zuordnen.

Sehen wir uns an, wie eine master Seite zur Laufzeit basierend auf einigen externen Kriterien dynamisch geladen wird. Unsere Website enthält derzeit nur eine master Seite (Site.master). Wir benötigen eine weitere master Seite, um die Auswahl einer master Seite zur Laufzeit zu veranschaulichen. Dieser Schritt konzentriert sich auf das Erstellen und Konfigurieren der neuen master Seite. Schritt 4 untersucht, welche master Seite zur Laufzeit verwendet werden soll.

Erstellen Sie eine neue master Seite im Stammordner mit dem Namen Alternate.master. Fügen Sie der Website auch ein neues Stylesheet mit dem Namen AlternateStyles.csshinzu.

Hinzufügen einer weiteren Gestaltungsvorlage und einer CSS-Datei zur Website

Abbildung 03: Hinzufügen einer weiteren Gestaltungsvorlage und einer CSS-Datei zur Website (Klicken Sie hier, um das bild in voller Größe anzuzeigen)

Ich habe die Alternate.master master Seite so entworfen, dass der Titel oben auf der Seite zentriert und auf einem marinen Hintergrund angezeigt wird. Ich habe die linke Spalte entfernt und diesen Inhalt unter das MainContent ContentPlaceHolder-Steuerelement verschoben, das sich jetzt über die gesamte Breite der Seite erstreckt. Darüber hinaus habe ich die ungeordnete Lektionenliste nixed und sie durch eine horizontale Liste oben MainContentersetzt. Ich habe auch die Schriftarten und Farben aktualisiert, die von der master Seite verwendet werden (und damit auch die Inhaltsseiten). Abbildung 4 zeigt Default.aspx die Verwendung der Alternate.master master Seite.

Hinweis

ASP.NET umfasst die Möglichkeit, Designs zu definieren. Ein Design ist eine Sammlung von Bildern, CSS-Dateien und stilbezogenen Websteuerelementeigenschafteneinstellungen, die zur Laufzeit auf eine Seite angewendet werden können. Designs sind der weg, wenn sich die Layouts Ihrer Website nur in den angezeigten Bildern und ihren CSS-Regeln unterscheiden. Wenn sich die Layouts wesentlich unterscheiden, z. B. die Verwendung verschiedener Websteuerelemente oder ein radikal anderes Layout, müssen Sie separate master Seiten verwenden. Weitere Informationen zu Designs finden Sie im Abschnitt Weitere Informationen am Ende dieses Tutorials.

Unsere Inhaltsseiten können jetzt ein neues Erscheinungsbild verwenden

Abbildung 04: Unsere Inhaltsseiten können jetzt ein neues Erscheinungsbild verwenden (Klicken Sie hier, um das bild in voller Größe anzuzeigen)

Wenn das Markup der master- und Inhaltsseiten fusioniert wird, überprüft die MasterPage Klasse, um sicherzustellen, dass jedes Content-Steuerelement auf der Inhaltsseite auf einen ContentPlaceHolder in der master Seite verweist. Eine Ausnahme wird ausgelöst, wenn ein Content-Steuerelement gefunden wird, das auf einen nicht vorhandenen ContentPlaceHolder verweist. Mit anderen Worten, es ist zwingend erforderlich, dass die master Seite, die der Inhaltsseite zugewiesen wird, über einen ContentPlaceHolder für jedes Content-Steuerelement auf der Inhaltsseite verfügen.

Die Site.master seite master enthält vier ContentPlaceHolder-Steuerelemente:

  • head
  • MainContent
  • QuickLoginUI
  • LeftColumnContent

Einige der Inhaltsseiten unserer Website enthalten nur ein oder zwei Inhaltssteuerelemente; andere enthalten ein Content-Steuerelement für jeden verfügbaren ContentPlaceHolders. Wenn unsere neue master Seite (Alternate.master) jemals diesen Inhaltsseiten zugewiesen wurde, die Über Content-Steuerelemente für alle ContentPlaceHolders verfügenSite.master, ist es wichtig, dass Alternate.master auch die gleichen ContentPlaceHolder-Steuerelemente wie Site.masterenthalten.

Damit Ihre Alternate.master master Seite meiner ähnelt (siehe Abbildung 4), definieren Sie zunächst die Formatvorlagen der master Seite im AlternateStyles.css Stylesheet. Fügen Sie die folgenden Regeln hinzu AlternateStyles.css:

body 
{ 
 font-family: Comic Sans MS, Arial; 
 font-size: medium; 
 margin: 0px; 
} 
#topContent 
{ 
 text-align: center; 
 background-color: Navy; 
 color: White; 
 font-size: x-large;
 text-decoration: none; 
 font-weight: bold; 
 padding: 10px; 
 height: 50px;
} 
#topContent a 
{ 
 text-decoration: none; 
 color: White; 
} 
#navContent 
{ 
 font-size: small; 
 text-align: center; 
} 
#footerContent 
{ 
 padding: 10px; 
 font-size: 90%; 
 text-align: center; 
 border-top: solid 1px black; 
} 
#mainContent 
{ 
 text-align: left; 
 padding: 10px; 
}

Fügen Sie als Nächstes das folgende deklarative Markup hinzu Alternate.master. Wie Sie sehen können, Alternate.master enthält vier ContentPlaceHolder-Steuerelemente mit den gleichen ID Werten wie die ContentPlaceHolder-Steuerelemente in Site.master. Darüber hinaus enthält es ein ScriptManager-Steuerelement, das für die Seiten auf unserer Website erforderlich ist, die das ASP.NET AJAX-Framework verwenden.

<!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 id="Head1" runat="server"> 
 <title>Untitled Page</title>
 <asp:ContentPlaceHolder id="head" runat="server">
 </asp:ContentPlaceHolder> 
 <link href="AlternateStyles.css" rel="stylesheet" type="text/css" /> 
</head> 
<body> 
 <form id="form1" runat="server"> 
 <asp:ScriptManager ID="MyManager" runat="server"> 
 </asp:ScriptManager>
 <div id="topContent">
 <asp:HyperLink ID="lnkHome" runat="server" NavigateUrl="~/Default.aspx" 
 Text="Master Pages Tutorials" /> 
 </div>
 <div id="navContent">
 <asp:ListView ID="LessonsList" runat="server" 
 DataSourceID="LessonsDataSource">
 <LayoutTemplate>
 <asp:PlaceHolder runat="server" ID="itemPlaceholder" /> 
 </LayoutTemplate>
 <ItemTemplate>
 <asp:HyperLink runat="server" ID="lnkLesson" 
 NavigateUrl='<%# Eval("Url") %>' 
 Text='<%# Eval("Title") %>' /> 
 </ItemTemplate>
 <ItemSeparatorTemplate> | </ItemSeparatorTemplate> 
 </asp:ListView>
 <asp:SiteMapDataSource ID="LessonsDataSource" runat="server" 
 ShowStartingNode="false" /> 
 </div>
 <div id="mainContent">
 <asp:ContentPlaceHolder id="MainContent" runat="server"> 
 </asp:ContentPlaceHolder>
 </div> 
 <div id="footerContent">
 <p> 
 <asp:Label ID="DateDisplay" runat="server"></asp:Label> 
 </p>
 <asp:ContentPlaceHolder ID="QuickLoginUI" runat="server"> 
 </asp:ContentPlaceHolder>
 <asp:ContentPlaceHolder ID="LeftColumnContent" runat="server"> 
 </asp:ContentPlaceHolder>
 </div> 
 </form>
</body> 
</html>

Testen der neuen Gestaltungsvorlage

Um diese neue master Seite zu testen, aktualisieren Sie die Methode der BasePage KlasseOnPreInit, sodass der MasterPageFile Eigenschaft der Wert "~/Alternate.master" zugewiesen wird, und besuchen Sie dann die Website. Jede Seite sollte ohne Fehler funktionieren, mit Ausnahme von zwei: ~/Admin/AddProduct.aspx und ~/Admin/Products.aspx. Das Hinzufügen eines Produkts zu DetailsView in ~/Admin/AddProduct.aspx führt zu einer NullReferenceException aus der Codezeile, die versucht, die Eigenschaft der master Seite GridMessageText festzulegen. Beim Aufrufen ~/Admin/Products.aspx einer InvalidCastException wird beim Laden der Seite mit der Meldung "Objekt vom Typ 'ASP.alternate_master' kann nicht in den Typ 'ASP.site_master' umgewandelt werden' ausgelöst."

Diese Fehler treten auf, weil die Site.master CodeBehind-Klasse öffentliche Ereignisse, Eigenschaften und Methoden enthält, die nicht in Alternate.masterdefiniert sind. Der Markupteil dieser beiden Seiten verfügt über eine @MasterType -Direktive, die auf die Site.master master Seite verweist.

<%@ MasterType VirtualPath="~/Site.master" %>

Außerdem enthält der Ereignishandler von ItemInserted DetailsView in ~/Admin/AddProduct.aspx Code, der die lose typisierte Eigenschaft in ein Objekt vom Typ SitewandeltPage.Master. Die @MasterType -Direktive (auf diese Weise verwendet) und die Umwandlung im ItemInserted Ereignishandler verknüpfen die ~/Admin/AddProduct.aspx Seiten und ~/Admin/Products.aspx eng mit der Site.master seite master.

Um diese enge Kopplung zu unterbrechen, können Site.master wir eine gemeinsame Basisklasse haben, Alternate.master die Definitionen für die öffentlichen Member enthält. Danach können wir die @MasterType -Direktive aktualisieren, um auf diesen allgemeinen Basistyp zu verweisen.

Erstellen einer benutzerdefinierten Masterpage-Basisklasse

Fügen Sie dem Ordner eine neue Klassendatei mit dem App_Code Namen BaseMasterPage.cs hinzu, und lassen Sie sie von abgeleitet werden System.Web.UI.MasterPage. Wir müssen die RefreshRecentProductsGrid Methode und die GridMessageText Eigenschaft in BaseMasterPagedefinieren, aber wir können sie nicht einfach aus Site.master dorthin verschieben, da diese Member mit Websteuerelementen arbeiten, die für die Site.master master Seite (GridView RecentProducts und GridMessage Label) spezifisch sind.

Was wir tun müssen, ist, so zu konfigurieren BaseMasterPage , dass diese Member dort definiert sind, aber tatsächlich von BaseMasterPageden abgeleiteten Klassen (Site.master und Alternate.master) implementiert werden. Diese Art der Vererbung ist möglich, indem die -Klasse und ihre Member als abstractgekennzeichnet werden. Kurz gesagt, das Hinzufügen des abstract Schlüsselwort (keyword) zu diesen beiden Membern gibt an, dass BaseMasterPage und GridMessageTextnicht implementiert RefreshRecentProductsGrid wurde, sondern dass die abgeleiteten Klassen dies ausführen.

Außerdem müssen wir das PricesDoubled Ereignis in BaseMasterPage definieren und von den abgeleiteten Klassen ein Mittel bereitstellen, um das Ereignis auszulösen. Das Muster, das im .NET Framework verwendet wird, um dieses Verhalten zu erleichtern, besteht darin, virtual ein öffentliches Ereignis in der Basisklasse zu erstellen und eine geschützte Methode namens OnEventNamehinzuzufügen. Abgeleitete Klassen können dann diese Methode aufrufen, um das Ereignis auszulösen, oder sie überschreiben, um Code unmittelbar vor oder nach dem Auslösen des Ereignisses auszuführen.

Aktualisieren Sie Ihre BaseMasterPage Klasse, sodass sie den folgenden Code enthält:

using System; public abstract class BaseMasterPage : System.Web.UI.MasterPage
{ 
    public event EventHandler PricesDoubled; 
    protected virtual void OnPricesDoubled(EventArgs e) 
    { 
        if (PricesDoubled != null) 
        PricesDoubled(this, e); 
    } 
    public abstract void RefreshRecentProductsGrid();
    public abstract string GridMessageText 
    { 
        get; 
        set; 
    } 
}

Wechseln Sie als Nächstes Site.master zur CodeBehind-Klasse, und lassen Sie sie von abgeleitet werden BaseMasterPage. Da BaseMasterPage müssen abstract wir diese abstract Member hier in Site.masterüberschreiben. Fügen Sie die override Schlüsselwort (keyword) den Methoden- und Eigenschaftendefinitionen hinzu. Aktualisieren Sie außerdem den Code, der das PricesDoubled Ereignis im Ereignishandler des ClickDoublePrice Button-Objekts auslöst, mit einem Aufruf der -Methode der BasisklasseOnPricesDoubled.

Nach diesen Änderungen sollte die Site.master CodeBehind-Klasse den folgenden Code enthalten:

public partial class Site : BaseMasterPage { 
    protected void Page_Load(object sender, EventArgs e) 
    { 
        DateDisplay.Text = DateTime.Now.ToString("dddd, MMMM dd"); 
    } 
    public override void RefreshRecentProductsGrid()
    { 
        RecentProducts.DataBind();
    } 
    public override string GridMessageText
    { 
        get 
        {
            return GridMessage.Text;
        } 
        set
        {
            GridMessage.Text = value; 
        } 
    }
    protected void DoublePrice_Click(object sender, EventArgs e) 
    { 
        // Double the prices 
        DoublePricesDataSource.Update();
        // Refresh RecentProducts 
        RecentProducts.DataBind();
        // Raise the PricesDoubled event
        base.OnPricesDoubled(EventArgs.Empty);
    } 
}

Außerdem müssen Alternate.masterwir die CodeBehind-Klasse aktualisieren, um von BaseMasterPage den beiden abstract Membern abzuleiten und sie zu überschreiben. Da Alternate.master jedoch keine GridView enthält, die die neuesten Produkte auflistet, noch ein Label, das eine Meldung anzeigt, nachdem ein neues Produkt zur Datenbank hinzugefügt wurde, müssen diese Methoden nichts tun.

public partial class Alternate : BaseMasterPage 
{ 
    public override void RefreshRecentProductsGrid() 
    { 
        // Do nothing 
    } 
    public override string GridMessageText 
    { 
        get
        { 
            return string.Empty;
        } 
        set
        {
            // Do nothing 
        } 
    }
}

Verweisen auf die Masterpage-Basisklasse

Nachdem wir die BaseMasterPage Klasse abgeschlossen haben und unsere beiden master Seiten erweitert haben, besteht unser letzter Schritt darin, die ~/Admin/AddProduct.aspx Seiten und ~/Admin/Products.aspx zu aktualisieren, um auf diesen allgemeinen Typ zu verweisen. Ändern Sie zunächst die @MasterType -Direktive auf beiden Seiten von:

<%@ MasterType VirtualPath="~/Site.master" %>

Nach:

<%@ MasterType TypeName="BaseMasterPage" %>

Anstatt auf einen Dateipfad zu verweisen, verweist die @MasterType Eigenschaft jetzt auf den Basistyp (BaseMasterPage). Folglich ist die stark typisierte Master Eigenschaft, die in den CodeBehind-Klassen beider Seiten verwendet wird, jetzt vom Typ BaseMasterPage (anstelle des Typs Site). Mit dieser Änderung können Sie erneut besuchen ~/Admin/Products.aspx. Zuvor führte dies zu einem Umwandlungsfehler, da die Seite für die Verwendung der Alternate.master master-Seite konfiguriert ist, aber die @MasterType Direktive auf die Site.master Datei verwiesen hat. Jetzt wird die Seite jedoch ohne Fehler gerendert. Dies liegt daran, dass die Alternate.master master Seite in ein Objekt vom Typ BaseMasterPage umgewandelt werden kann (da es erweitert wird).

Es gibt eine kleine Änderung, die in ~/Admin/AddProduct.aspxvorgenommen werden muss. Der Ereignishandler des ItemInserted DetailsView-Steuerelements verwendet sowohl die stark typisierte Master Eigenschaft als auch die lose typisierte Page.Master Eigenschaft. Wir haben den stark typisierten Verweis behoben, als wir die @MasterType -Direktive aktualisiert haben, aber wir müssen den lose typisierten Verweis trotzdem aktualisieren. Ersetzen Sie die folgende Codezeile:

Site myMasterPage = Page.Master as Site;

Mit folgendem , der in den Basistyp umgewandelt wird Page.Master :

BaseMasterPage myMasterPage = Page.Master as BaseMasterPage;

Schritt 4: Bestimmen, welche Gestaltungsvorlage an die Inhaltsseiten gebunden werden soll

Unsere BasePage -Klasse legt derzeit die Eigenschaften aller Inhaltsseiten MasterPageFile auf einen hartcodierten Wert in der PreInit-Phase des Seitenlebenszyklus fest. Wir können diesen Code aktualisieren, um die seite master auf einem externen Faktor zu basieren. Möglicherweise hängt die master Seite, die geladen werden soll, von den Einstellungen des derzeit angemeldeten Benutzers ab. In diesem Fall müssten wir Code in die -Methode BasePage schreiben, die OnPreInit die master Seiteneinstellungen des aktuell besuchenden Benutzers sucht.

Erstellen Wir nun eine Webseite, auf der der Benutzer auswählen kann, welche master Seite verwendet werden soll ( Site.master oder Alternate.master ) und diese Auswahl in einer Sitzungsvariablen speichern kann. Erstellen Sie zunächst eine neue Webseite im Stammverzeichnis namens ChooseMasterPage.aspx. Wenn Sie diese Seite (oder fortan andere Inhaltsseiten) erstellen, müssen Sie sie nicht an eine master-Seite binden, da die master Seite programmgesteuert in BasePagefestgelegt wird. Wenn Sie die neue Seite jedoch nicht an eine master Seite binden, enthält das standardmäßige deklarative Markup der neuen Seite ein Webformular und andere Inhalte, die von der master Seite bereitgestellt werden. Sie müssen dieses Markup manuell durch die entsprechenden Inhaltssteuerelemente ersetzen. Aus diesem Grund finde ich es einfacher, die neue ASP.NET-Seite an eine master-Seite zu binden.

Hinweis

Da Site.master und Alternate.master über denselben Satz von ContentPlaceHolder-Steuerelementen verfügen, spielt es keine Rolle, welche master Seite Sie beim Erstellen der neuen Inhaltsseite auswählen. Aus Gründen der Konsistenz würde ich die Verwendung von vorschlagen Site.master.

Hinzufügen einer neuen Inhaltsseite zur Website

Abbildung 05: Hinzufügen einer neuen Inhaltsseite zur Website (Klicken Sie hier, um das Bild in voller Größe anzuzeigen)

Aktualisieren Sie die Web.sitemap Datei so, dass sie einen Eintrag für diese Lektion enthält. Fügen Sie das folgende Markup unter dem <siteMapNode> für die Gestaltungsvorlagen und ASP.NET AJAX-Lektion hinzu:

<siteMapNode url="~/ChooseMasterPage.aspx" title="Choose a Master Page" />

Vor dem Hinzufügen von Inhalten zur Seite nehmen Sie sich einen Moment Zeit, ChooseMasterPage.aspx um die CodeBehind-Klasse der Seite zu aktualisieren, sodass sie von (statt System.Web.UI.Page) BasePage abgeleitet wird. Fügen Sie als Nächstes der Seite ein DropDownList-Steuerelement hinzu, legen Sie dessen ID Eigenschaft auf MasterPageChoicefest, und fügen Sie zwei ListItems mit den Text Werten "~/Site.master" und "~/Alternate.master" hinzu.

Fügen Sie der Seite ein Button-Websteuerelement hinzu, und legen Sie dessen ID Eigenschaften und Text auf SaveLayout bzw. "Layoutauswahl speichern" fest. An diesem Punkt sollte das deklarative Markup Ihrer Seite in etwa wie folgt aussehen:

<p> 
 Your layout choice: 
 <asp:DropDownList ID="MasterPageChoice" runat="server"> 
 <asp:ListItem>~/Site.master</asp:ListItem>
 <asp:ListItem>~/Alternate.master</asp:ListItem>
 </asp:DropDownList> 
</p> 
<p> 
 <asp:Button ID="SaveLayout" runat="server" Text="Save Layout Choice" /> 
</p>

Wenn die Seite zum ersten Mal aufgerufen wird, müssen wir die aktuell ausgewählte master Seitenauswahl des Benutzers anzeigen. Erstellen Sie einen Page_Load Ereignishandler, und fügen Sie den folgenden Code hinzu:

protected void Page_Load(object sender, EventArgs e) 
{ 
    if (!Page.IsPostBack) 
    { 
        if (Session["MyMasterPage"] != null)
        {
            ListItem li = MasterPageChoice.Items.FindByText(Session["MyMasterPage"].ToString());
            if (li != null) 
                li.Selected = true; 
        } 
    }
}

Der obige Code wird nur beim ersten Seitenbesuch (und nicht bei nachfolgenden Postbacks) ausgeführt. Zuerst wird überprüft, ob die Sitzungsvariable MyMasterPage vorhanden ist. Wenn dies der Fall ist, wird versucht, das übereinstimmende ListItem in der MasterPageChoice DropDownList zu finden. Wenn ein übereinstimmende ListItem gefunden wird, wird dessen Selected Eigenschaft auf truefestgelegt.

Außerdem benötigen wir Code, der die Auswahl des Benutzers in der MyMasterPage Sitzungsvariablen speichert. Erstellen Sie einen Ereignishandler für das SaveLayout Button-Ereignis Click , und fügen Sie den folgenden Code hinzu:

protected void SaveLayout_Click(object sender, EventArgs e)
{
    Session["MyMasterPage"] = MasterPageChoice.SelectedValue;
    Response.Redirect("ChooseMasterPage.aspx"); 
}

Hinweis

Zu dem Zeitpunkt, zu dem der Click Ereignishandler beim Postback ausgeführt wird, wurde die Seite master bereits ausgewählt. Daher wird die Dropdownliste des Benutzers erst beim nächsten Seitenbesuch wirksam. Erzwingt Response.Redirect den Browser, erneut anzufordern ChooseMasterPage.aspx.

Nach Abschluss der ChooseMasterPage.aspx Seite besteht unsere letzte Aufgabe darin, die MasterPageFile -Eigenschaft basierend auf dem Wert der MyMasterPage Sitzungsvariablen zuzuweisenBasePage. Wenn die Sitzungsvariable nicht festgelegt ist, haben Sie BasePage den Standardwert auf Site.master.

protected override void OnPreInit(EventArgs e) 
{ 
    SetMasterPageFile();
    base.OnPreInit(e); 
} 
protected virtual void SetMasterPageFile()
{ 
    this.MasterPageFile = GetMasterPageFileFromSession();
} 
protected string GetMasterPageFileFromSession() 
{ 
    if (Session["MyMasterPage"] == null) 
        return "~/Site.master";
    else
        return Session["MyMasterPage"].ToString(); 
}

Hinweis

Ich habe den Code, der die Page Eigenschaft des MasterPageFile Objekts zuweist, aus dem OnPreInit Ereignishandler in zwei separate Methoden verschoben. Diese erste Methode weist die -Eigenschaft dem MasterPageFile Wert zu, SetMasterPageFileder von der zweiten Methode zurückgegeben wird. GetMasterPageFileFromSession Ich habe die SetMasterPageFile -Methode virtual so erstellt, dass zukünftige Klassen, die erweitern BasePage , sie optional überschreiben können, um bei Bedarf benutzerdefinierte Logik zu implementieren. Ein Beispiel für das Überschreiben BasePageder -Eigenschaft finden SetMasterPageFile Sie im nächsten Tutorial.

Wenn dieser Code vorhanden ist, besuchen Sie die ChooseMasterPage.aspx Seite. Zunächst ist die Site.master Seite master ausgewählt (siehe Abbildung 6), aber der Benutzer kann eine andere master Seite aus der Dropdownliste auswählen.

Inhaltsseiten werden mithilfe der Website angezeigt. master Gestaltungsvorlage

Abbildung 06: Inhaltsseiten werden mithilfe der Gestaltungsvorlage Site.master angezeigt (Klicken Sie hier, um das Bild in voller Größe anzuzeigen)

Inhaltsseiten werden jetzt mithilfe des Alternativen angezeigt. master Gestaltungsvorlage

Abbildung 07: Inhaltsseiten werden jetzt mithilfe der Gestaltungsvorlage Alternate.master angezeigt (Klicken Sie hier, um das Bild in voller Größe anzuzeigen)

Zusammenfassung

Wenn eine Inhaltsseite besucht wird, werden ihre Inhaltssteuerelemente mit den ContentPlaceHolder-Steuerelementen der master Seite verschmolzen. Die master Seite der Inhaltsseite wird durch die -Eigenschaft der Page -Klasse MasterPageFile bezeichnet, die dem Attribut der @Page Direktive MasterPageFile während der Initialisierungsphase zugewiesen wird. Wie in diesem Tutorial gezeigt, können wir der MasterPageFile Eigenschaft einen Wert zuweisen, solange dies vor dem Ende der PreInit-Phase der Fall ist. Die Möglichkeit, die master Seite programmgesteuert anzugeben, öffnet die Tür für komplexere Szenarien, z. B. das dynamische Binden einer Inhaltsseite an eine master-Seite basierend auf externen Faktoren.

Viel Spaß beim Programmieren!

Weitere Informationen

Weitere Informationen zu den in diesem Tutorial behandelten Themen finden Sie in den folgenden Ressourcen:

Zum Autor

Scott Mitchell, Autor mehrerer ASP/ASP.NET-Bücher und Gründer von 4GuysFromRolla.com, arbeitet seit 1998 mit Microsoft-Webtechnologien. Scott arbeitet als unabhängiger Berater, Trainer und Autor. Sein neuestes Buch ist Sams Teach Yourself ASP.NET 3.5 in 24 Stunden. Scott kann unter mitchell@4GuysFromRolla.com oder über seinen Blog unter http://ScottOnWriting.NETerreicht werden.

Besonderen Dank an

Diese Tutorialreihe wurde von vielen hilfreichen Prüfern überprüft. Lead Reviewer für dieses Tutorial war Suchi Banerjee. Möchten Sie meine anstehenden MSDN-Artikel lesen? Wenn dies der Fall ist, legen Sie mir eine Zeile unter mitchell@4GuysFromRolla.com