Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
von Scott Mitchell
Untersucht wird, wie die Masterseite der Inhaltsseite programmgesteuert über den PreInit-Ereignishandler festgelegt wird.
Einführung
Da im ersten Beispiel beim Erstellen eines websiteweiten Layouts mithilfe von Gestaltungsvorlagen auf alle Inhaltsseiten deklarativ über das MasterPageFile Attribut in der @Page Direktive verwiesen wurde, haben alle Inhaltsseiten deklarativ auf ihre Gestaltungsvorlage verwiesen. Die folgende @Page Direktive verknüpft die Inhaltsseite beispielsweise mit der Masterseite Site.master.
<%@ Page Language="C#" MasterPageFile="~/Site.master" ... %>
Die PageKlasse im System.Web.UI Namespace enthält eine Eigenschaft, die den Pfad zur Gestaltungsvorlage der Inhaltsseite zurückgibt; diese Eigenschaft wird durch die @Page Direktive festgelegt. Diese Eigenschaft kann auch verwendet werden, um die Masterseite der Inhaltsseite programmgesteuert festzulegen. Dieser Ansatz ist nützlich, wenn Sie die Masterseite dynamisch basierend auf externen Faktoren zuweisen möchten, z. B. auf den Benutzer, der die Seite besucht.
In diesem Tutorial fügen wir unserer Website eine zweite Gestaltungsvorlage hinzu und entscheiden dynamisch, welche Gestaltungsvorlage 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 in die entsprechenden ContentPlaceHolder-Steuerelemente der Masterseite integrieren. Diese Fusion erstellt eine einzelne Steuerelementhierarchie, die dann den typischen Seitenlebenszyklus durchlaufen kann.
Abbildung 1 veranschaulicht diese Fusion. Schritt 1 in Abbildung 1 zeigt die Anfangshierarchien der Inhalts- und Masterseitensteuerelemente. Am Ende der PreInit-Phase werden die Inhaltssteuerelemente auf der Seite den entsprechenden ContentPlaceHolders in der Gestaltungsvorlage (Schritt 2) hinzugefügt. Nach dieser Fusion dient die Masterseite als Stamm der fusionierten Steuerelementhierarchie. Diese Fused-Steuerelementhierarchie wird dann der Seite hinzugefügt, um die endgültige Steuerelementhierarchie (Schritt 3) zu erzeugen. Das Endergebnis ist, dass die Steuerelementhierarchie der Seite die verschmolzene Steuerelementhierarchie umfasst.
Abbildung 01: Während der PreInit-Phase werden die Steuerelementhierarchien der Masterseite und der Inhaltsseite miteinander zusammengeführt (Klicken Sie hier, um das vollständige Bild anzuzeigen)
Schritt 2: Festlegen derMasterPageFileEigenschaft im Code
Welche Gestaltungsvorlage in dieser Fusion beteiligt ist, hängt vom Wert der Eigenschaft des PageMasterPageFile Objekts ab. Das Festlegen des MasterPageFile-Attributs in der @Page-Direktive hat den Effekt der Zuweisung der Page-Eigenschaft MasterPageFile während der Initialisierungsphase, welche die erste Phase des Lebenszyklus der Seite ist. Wir können diese Eigenschaft auch programmgesteuert festlegen. Es ist jedoch zwingend erforderlich, dass diese Eigenschaft vor der Fusion in Abbildung 1 festgelegt wird.
Am Anfang der PreInit-Phase löst das Page Objekt sein PreInit Ereignis aus und ruft seine OnPreInit Methode auf. Um die Masterseite programmgesteuert festzulegen, können wir entweder einen Ereignishandler für das PreInit-Ereignis erstellen oder die OnPreInit-Methode überschreiben. Sehen wir uns beide Ansätze an.
Default.aspx.csÖffnen Sie 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)
{
}
Von hier aus können wir die MasterPageFile Eigenschaft festlegen. Aktualisieren Sie den Code so, dass er der Eigenschaft den Wert "~/Site.master" zuweist MasterPageFile .
protected void Page_PreInit(object sender, EventArgs e)
{
this.MasterPageFile = "~/Site.master";
}
Wenn Sie einen Haltepunkt festlegen und mit dem Debuggen beginnen, wird angezeigt, dass immer, wenn die Default.aspx Seite besucht wird oder wenn ein Postback zu dieser Seite vorhanden ist, der Page_PreInit Ereignishandler 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 richten wir die Master-Seite nicht auf einer bestimmten Seite ein, sondern über BasePage. Erinnern Sie sich daran, dass wir bereits im Tutorial 'Titel, Metatags und andere HTML-Kopfzeilen auf der Master-Seite spezifizieren' eine benutzerdefinierte Basisseitenklasse (BasePage) erstellt haben. Derzeit überschreibt BasePage die OnLoadComplete-Methode der Page-Klasse, wobei die Eigenschaft Title der Seite basierend auf den Daten der Sitemap festgelegt wird. Lassen Sie uns BasePage aktualisieren und auch die Methode OnPreInit überschreiben, um die Masterseite programmgesteuert anzugeben.
protected override void OnPreInit(EventArgs e)
{
this.MasterPageFile = "~/Site.master";
base.OnPreInit(e);
}
Da alle unsere Inhaltsseiten von BasePage abgeleitet sind, wird ihnen allen jetzt programmatisch ihre Masterseite zugewiesen. An diesem Punkt ist der PreInit Ereignishandler in Default.aspx.cs überflüssig; entfernen Sie ihn einfach.
Was ist mit der@PageRichtlinie?
Möglicherweise ist es etwas verwirrend, dass die Eigenschaften der Inhaltsseiten MasterPageFile nun an zwei Stellen angegeben werden: programmgesteuert in der Methode der BasePage Klasse OnPreInit sowie über das Attribut in der MasterPageFile Direktive jeder Inhaltsseite @Page .
Die erste Phase im Seitenlebenszyklus ist die Initialisierungsphase. In dieser Phase wird die Page Eigenschaft des Objekts dem Wert des MasterPageFile Attributs MasterPageFile in der @Page Direktive (sofern angegeben) zugewiesen. Die PreInit-Phase folgt der Initialisierungsphase, und an dieser Stelle legen wir die Eigenschaft des PageMasterPageFile Objekts programmgesteuert fest, wodurch der Wert aus der @Page Direktive überschrieben wird. Da wir die Eigenschaft des PageMasterPageFile Objekts programmgesteuert festlegen, könnten wir das MasterPageFile Attribut aus der @Page Direktive entfernen, ohne die Benutzererfahrung des Endbenutzers zu beeinträchtigen. Um sich selbst davon zu überzeugen, entfernen Sie das MasterPageFile-Attribut aus der @Page-Direktive in Default.aspx und besuchen Sie dann die Seite über einen Browser. Wie Sie erwarten, ist die Ausgabe identisch mit dem, bevor das Attribut entfernt wurde.
Egal, ob die MasterPageFile Eigenschaft über die @Page Direktive oder programmatisch festgelegt wird, ist dies für das Erlebnis des Endbenutzers unerheblich. Das MasterPageFile-Attribut in der @Page-Direktive wird jedoch von Visual Studio während der Entwurfszeit verwendet, um die WYSIWYG-Ansicht im Designer zu erzeugen. Wenn Sie in Visual Studio zu Default.aspx zurückkehren und zum Designer navigieren, wird die Meldung "Fehler der Masterseite: Die Seite hat Steuerelemente, die einen Verweis auf eine Masterseite erfordern, aber keiner ist angegeben" (siehe Abbildung 2) angezeigt.
Kurz gesagt, Sie müssen das MasterPageFile-Attribut in der @Page-Direktive belassen, um ein reichhaltiges Entwurfserlebnis in Visual Studio zu nutzen.
Abbildung 02: Visual Studio verwendet das @Page Direktive-Attribut MasterPageFile zum Rendern der Entwurfsansicht (Klicken, um das Bild in voller Größe anzuzeigen)
Schritt 3: Erstellen einer alternativen Masterseite
Da die Masterseite einer Inhaltsseite zur Laufzeit dynamisch festgelegt werden kann, ist es möglich, basierend auf einigen externen Kriterien eine bestimmte Masterseite dynamisch zu laden. Diese Funktionalität kann in Situationen nützlich sein, in denen das Layout der Website je nach Benutzer variieren muss. Eine Blog-Engine-Webanwendung kann es Benutzern beispielsweise ermöglichen, ein Layout für ihren Blog auszuwählen, wobei jedes Layout mit einer anderen Masterseite verknüpft ist. Während der Laufzeit, wenn ein Besucher den Blog eines Benutzers anzeigt, muss die Webanwendung das Layout des Blogs ermitteln und die entsprechende Masterseite dynamisch der Inhaltsseite zuordnen.
Schauen wir uns an, wie eine Masterseite zur Laufzeit basierend auf einigen externen Kriterien dynamisch geladen wird. Unsere Website enthält derzeit nur eine Masterseite (Site.master). Wir benötigen eine weitere Masterseite, um die Auswahl einer Masterseite zur Laufzeit zu veranschaulichen. Dieser Schritt konzentriert sich auf das Erstellen und Konfigurieren der neuen Masterseite. In Schritt 4 wird untersucht, welche Masterseite zur Laufzeit verwendet werden soll.
Erstellen Sie eine neue Masterseite im Stammordner mit dem Namen Alternate.master. Fügen Sie der Website auch ein neues Stylesheet mit dem Namen hinzu AlternateStyles.css.
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 Masterseite so entworfen, dass der Titel oben auf der Seite angezeigt wird, zentriert und auf einem marineblauen Hintergrund. Ich habe die linke Spalte weggelassen und diesen Inhalt unter das MainContent ContentPlaceHolder-Steuerelement verschoben, der nun die gesamte Breite der Seite umfasst. Darüber hinaus habe ich die ungeordnete Lektionenliste entfernt und durch eine horizontale Liste oben MainContent ersetzt. Außerdem habe ich die Schriftarten und Farben aktualisiert, die von der Masterseite (und damit auch deren Inhaltsseiten) verwendet werden. Abbildung 4 zeigt Default.aspx, wenn die Gestaltungsvorlage Alternate.master verwendet wird.
Hinweis
ASP.NET umfasst die Möglichkeit, Themen zu definieren. Ein Design ist eine Sammlung von Bildern, CSS-Dateien und stilbezogenen Websteuerelement-Eigenschafteneinstellungen, die zur Laufzeit auf eine Seite angewendet werden können. Themes sind die richtige Wahl, wenn sich die Layouts Ihrer Website nur durch die angezeigten Bilder und ihre CSS-Regeln unterscheiden. Wenn sich die Layouts wesentlich unterscheiden, zum Beispiel durch den Einsatz unterschiedlicher Websteuerelemente oder ein radikal anderes Layout, müssen Sie separate Masterseiten verwenden. Weitere Informationen zu Themen finden Sie im Abschnitt "Weiterführende Literatur" am Ende dieses Lernprogramms.
Abbildung 04: Unsere Inhaltsseiten können jetzt ein neues Aussehen und Verhalten verwenden (Klicken Sie hier, um das Bild in voller Größe anzuzeigen)
Wenn das Markup der Master- und Inhaltsseiten zusammengeführt wird, überprüft die MasterPage Klasse, ob jedes Inhaltssteuerelement auf der Inhaltsseite auf einen ContentPlaceHolder in der Masterseite verweist. Eine Ausnahme wird ausgelöst, wenn ein Inhaltssteuerelement gefunden wird, das auf einen nicht vorhandenen ContentPlaceHolder verweist. Mit anderen Worten, es ist zwingend erforderlich, dass die Masterseite, die der Inhaltsseite zugewiesen wird, einen ContentPlaceHolder für jedes Inhaltssteuerelement auf der Inhaltsseite aufweist.
Die Masterseite Site.master enthält vier ContentPlaceHolder-Steuerelemente.
headMainContentQuickLoginUILeftColumnContent
Einige der Inhaltsseiten auf unserer Website umfassen nur ein oder zwei Inhaltssteuerelemente; andere enthalten ein Inhaltssteuerelement für jeden der verfügbaren ContentPlaceHolders. Wenn unsere neue Gestaltungsvorlage (Alternate.master) möglicherweise jemals diesen Inhaltsseiten zugewiesen wird, die Inhaltssteuerelemente für alle ContentPlaceHolders in Site.master enthalten, dann ist es wichtig, dass Alternate.master auch dieselben ContentPlaceHolder-Steuerelemente enthält wie Site.master.
Um Ihre Alternate.master Master-Seite so zu gestalten, dass sie ähnlich wie meine (siehe Abbildung 4) aussieht, definieren Sie zunächst die Stile 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 zu Alternate.master. Wie Sie sehen können, enthält Alternate.master vier ContentPlaceHolder-Steuerelemente mit denselben ID-Werten wie die ContentPlaceHolder-Steuerelemente in Site.master. Darüber hinaus enthält es ein ScriptManager-Steuerelement, das für diese 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 Masterseite
Um diese neue Master-Seite zu testen, aktualisieren Sie die Methode der BasePage Klasse, so dass der OnPreInit 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 zur DetailsView führt in ~/Admin/AddProduct.aspx zu einem NullReferenceException, wenn in einer Codezeile versucht wird, die Eigenschaft der Masterseite GridMessageText festzulegen. Beim Aufrufen eines Vorgangs ~/Admin/Products.aspx wird das Laden der InvalidCastException Seite mit der Meldung ausgelöst: "Objekt vom Typ 'ASP.alternate_master' kann nicht in den Typ 'ASP.site_master' umwandeln."
Diese Fehler treten auf, weil die Site.master-CodeBehind-Klasse öffentliche Ereignisse, Eigenschaften und Methoden enthält, die in Alternate.master nicht definiert sind. Der Markup-Bereich dieser beiden Seiten enthält eine @MasterType Direktive, die auf die Site.master Masterseite verweist.
<%@ MasterType VirtualPath="~/Site.master" %>
Außerdem enthält der Ereignishandler ItemInserted in ~/Admin/AddProduct.aspxDetailsView Code, der die lose typisierte Eigenschaft Page.Master in ein Objekt vom Typ Site konvertiert. Die @MasterType-Direktive (so verwendet) und die Typumwandlung im ItemInserted-Ereignishandler koppeln die ~/Admin/AddProduct.aspx- und ~/Admin/Products.aspx-Seiten eng an die Site.master-Masterseite.
Um diese enge Kopplung zu durchbrechen, können Site.master und Alternate.master von einer gemeinsamen Basisklasse abgeleitet werden, die Definitionen für die öffentlichen Mitglieder enthält. Anschließend können wir die @MasterType Direktive aktualisieren, um auf diesen gemeinsamen Basistyp zu verweisen.
Erstellen einer benutzerdefinierten Basis-Masterseite-Klasse
Fügen Sie dem App_Code Ordner namens BaseMasterPage.cs eine neue Klassendatei hinzu und leiten Sie sie von System.Web.UI.MasterPage. Wir müssen die RefreshRecentProductsGrid Methode und die GridMessageText Eigenschaft in BaseMasterPage definieren, aber wir können sie nicht einfach dorthin von Site.master verschieben, da diese Mitglieder mit Websteuerelementen arbeiten, die spezifisch für die Site.master Masterseite sind (die RecentProducts GridView und das GridMessage Label).
Was wir tun müssen, ist, BaseMasterPage so zu konfigurieren, dass diese Member dort definiert sind, aber tatsächlich von den von BaseMasterPage abgeleiteten Klassen (Site.master und Alternate.master) implementiert werden. Diese Art der Vererbung ist möglich, indem die Klasse und ihre Member als abstractmarkiert werden. Kurz gesagt, durch das Hinzufügen des abstract-Schlüsselworts zu diesen beiden Membern wird angekündigt, dass BaseMasterPageRefreshRecentProductsGrid und GridMessageText nicht implementiert hat, aber dass die abgeleiteten Klassen es implementieren werden.
Darüber hinaus müssen wir das PricesDoubled-Ereignis in BaseMasterPage definieren und es den abgeleiteten Klassen ermöglichen, das Ereignis auszulösen. Das Muster, das in .NET Framework verwendet wird, um dieses Verhalten zu vereinfachen, besteht darin, ein öffentliches Ereignis in der Basisklasse zu erstellen und eine geschützte Methode virtual namens OnEventNamehinzuzufügen. Abgeleitete Klassen können diese Methode dann aufrufen, um das Ereignis auszulösen oder ihn außer Kraft zu setzen, um Code unmittelbar vor oder nach dem Auslösen des Ereignisses auszuführen.
Aktualisieren Sie Ihre BaseMasterPage Klasse so, dass 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 zur Site.master Code-Behind-Klasse, und leiten Sie sie von BaseMasterPage ab.
BaseMasterPage Da abstract wir diese abstract Mitglieder hier Site.masteraußer Kraft setzen müssen. Fügen Sie das override Schlüsselwort zu den Methoden- und Eigenschaftendefinitionen hinzu. Aktualisieren Sie außerdem den Code, der das PricesDoubled Ereignis im Ereignishandler der DoublePrice Schaltfläche Click auslöst, mit einem Aufruf der Methode der Basisklasse OnPricesDoubled .
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 wir die Code-Behind-Klasse von BaseMasterPage ableiten und die beiden abstract-Member außer Kraft setzen. Da Alternate.master jedoch keine GridView enthält, die die neuesten Produkte oder eine Bezeichnung auflistet, die eine Meldung anzeigt, nachdem ein neues Produkt der 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 Basismasterseite-Klasse
Nachdem wir die BaseMasterPage-Klasse abgeschlossen haben und unsere beiden Masterseiten erweitert haben, besteht der letzte Schritt darin, die ~/Admin/AddProduct.aspx- und ~/Admin/Products.aspx-Seiten zu aktualisieren, sodass sie auf diesen gemeinsamen Typ verweisen. Ändern Sie zunächst die @MasterType Direktive auf beiden Seiten von:
<%@ MasterType VirtualPath="~/Site.master" %>
An:
<%@ MasterType TypeName="BaseMasterPage" %>
Anstatt auf einen Dateipfad zu verweisen, verweist die @MasterType Eigenschaft jetzt auf den Basistyp (BaseMasterPage). Folglich ist die stark typierte Master-Eigenschaft, die in den Code-Behind-Klassen beider Seiten verwendet wird, nun vom Typ BaseMasterPage (statt vom Typ Site). Mit dieser Änderung überprüfen Sie ~/Admin/Products.aspx erneut. Zuvor führte dies zu einem Umwandlungsfehler, da die Seite für die Verwendung der Alternate.master Gestaltungsvorlage konfiguriert ist, die @MasterType Direktive jedoch auf die Site.master Datei verweist. Jetzt wird die Seite jedoch ohne Fehler gerendert. Dies liegt daran, dass die Alternate.master Gestaltungsvorlage in ein Objekt des Typs BaseMasterPage umgewandelt werden kann, da sie es erweitert.
Es gibt eine kleine Änderung, die in ~/Admin/AddProduct.aspx vorgenommen werden muss. Der Ereignishandler des DetailsView-Steuerelements ItemInserted verwendet sowohl die stark typierte Master Eigenschaft als auch die lose typierte Page.Master Eigenschaft. Wir haben den stark typierten Verweis beim Aktualisieren der @MasterType Direktive behoben, aber wir müssen den lose typierten Verweis aktualisieren. Ersetzen Sie die folgende Codezeile:
Site myMasterPage = Page.Master as Site;
Mit der folgenden Umwandlung Page.Master in den Basistyp:
BaseMasterPage myMasterPage = Page.Master as BaseMasterPage;
Schritt 4: Bestimmen, welche Masterseite mit den Inhaltsseiten verknüpft werden soll
Unsere BasePage Klasse legt derzeit alle Eigenschaften von Inhaltsseiten MasterPageFile auf einen hartcodierten Wert in der PreInit-Phase des Seitenlebenszyklus fest. Wir können diesen Code aktualisieren, um die Masterseite auf einem externen Faktor zu basieren. Möglicherweise hängt die zu ladende Masterseite von den Präferenzen des aktuell angemeldeten Benutzers ab. In diesem Fall müssen wir Code in der OnPreInit-Methode in BasePage schreiben, die die aktuellen Masterseitenpräferenzen des Benutzers nachschlägt.
Erstellen wir nun eine Webseite, die es dem Benutzer ermöglicht, auszuwählen, welche Gestaltungsvorlage verwendet werden soll – Site.master oder Alternate.master - und diese Auswahl in einer Sitzungsvariable zu speichern. Erstellen Sie zunächst eine neue Webseite im Stammverzeichnis namens ChooseMasterPage.aspx. Beim Erstellen dieser Seite (oder anderer Inhaltsseiten) müssen Sie sie nicht an eine Masterseite binden, da die Masterseite in BasePage programmgesteuert festgelegt ist. Wenn Sie die neue Seite jedoch nicht an eine Gestaltungsvorlage binden, enthält das standardmäßige deklarative Markup der neuen Seite ein Webformular und andere Inhalte, die von der Gestaltungsvorlage 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 Masterseite zu binden.
Hinweis
Da Site.master und Alternate.master über dieselbe Gruppe von ContentPlaceHolder-Steuerelementen verfügen, spielt es keine Rolle, welche Masterseite Sie beim Erstellen der neuen Inhaltsseite auswählen. Aus Gründen der Konsistenz würde ich die Verwendung Site.mastervorschlagen.
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 der <siteMapNode> Lektion für Gestaltungsvorlagen und ASP.NET AJAX hinzu:
<siteMapNode url="~/ChooseMasterPage.aspx" title="Choose a Master Page" />
Bevor Sie Inhalte zur Seite ChooseMasterPage.aspx hinzufügen, nehmen Sie sich einen Moment Zeit, um die Code-Behind-Klasse der Seite zu aktualisieren, sodass sie von BasePage (anstelle von System.Web.UI.Page) abgeleitet wird. Fügen Sie als Nächstes der Seite ein DropDownList-Steuerelement hinzu, legen Sie dessen ID Eigenschaft auf MasterPageChoice fest, und fügen Sie zwei Listenelemente mit den Text Werten "~/Site.master" und "~/Alternate.master" hinzu.
Fügen Sie der Seite ein Schaltflächen-Websteuerelement hinzu und legen Sie seine ID- und Text-Eigenschaften auf SaveLayout und "Layoutauswahl speichern" fest. An diesem Punkt sollte das deklarative Markup Ihrer Seite 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 besucht wird, müssen wir die aktuell vom Benutzer ausgewählte Masterseite 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 auf der ersten Seite ausgeführt (und nicht bei nachfolgenden Postbacks). Zunächst wird überprüft, ob die Sitzungsvariable MyMasterPage vorhanden ist. Wenn dies der Fall ist, wird versucht, das entsprechende ListItem in der MasterPageChoice DropDownList zu finden. Wenn ein übereinstimmendes ListItem gefunden wird, wird dessen Selected-Eigenschaft auf true gesetzt.
Außerdem benötigen wir Code, der die Auswahl des Benutzers in der MyMasterPage Sitzungsvariable speichert. Erstellen Sie einen Ereignishandler für das Ereignis der SaveLayout Schaltfläche 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
Wenn der Click Ereignishandler bei der Rücksendung ausgeführt wird, wurde die Masterseite bereits ausgewählt. Daher wird die Dropdownlistenauswahl des Benutzers erst wirksam, wenn die nächste Seite besucht wird. Der Response.Redirect zwingt den Browser, eine erneute Anfrage zu stellen ChooseMasterPage.aspx.
Nachdem die ChooseMasterPage.aspx Seite abgeschlossen ist, besteht die letzte Aufgabe darin, die BasePage Eigenschaft basierend auf dem Wert der MasterPageFile Sitzungsvariablen zuzuweisenMyMasterPage. Wenn die Session-Variable nicht festgelegt ist, steht BasePage standardmäßig 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 Eigenschaft des PageMasterPageFile Objekts zuweist, aus dem OnPreInit Ereignishandler herausgenommen und in zwei separate Methoden verschoben. Diese erste Methode SetMasterPageFile weist die Eigenschaft MasterPageFile dem Wert zu, der von der zweiten Methode GetMasterPageFileFromSession zurückgegeben wird. Ich habe die SetMasterPageFile Methode virtual so gestaltet, dass zukünftige Klassen, die BasePage erweitern, sie optional überschreiben können, um bei Bedarf benutzerdefinierte Logik zu implementieren. Im nächsten Tutorial werden wir ein Beispiel für das Überschreiben der BasePage-Eigenschaft von SetMasterPageFile sehen.
Rufen Sie mit diesem Code die ChooseMasterPage.aspx Seite auf. Zunächst ist die Site.master Masterseite ausgewählt (siehe Abbildung 6), aber der Benutzer kann eine andere Masterseite aus der Dropdown-Liste auswählen.
Abbildung 06: Inhaltsseiten werden mithilfe der Site.master Masterseite angezeigt (Bild in voller Größe anzeigen klicken)
Abbildung 07: Inhaltsseiten werden jetzt mithilfe der Gestaltungsvorlage angezeigt (Zum Anzeigen des Alternate.master Bilds mit voller Größe klicken)
Zusammenfassung
Wenn eine Inhaltsseite besucht wird, werden ihre Inhaltssteuerelemente mit den ContentPlaceHolder-Steuerelementen der Gestaltungsvorlage integriert. Die Masterpage der Inhaltsseite wird durch die Eigenschaft der Page-Klasse MasterPageFile identifiziert, die dem Attribut der @Page-Direktive MasterPageFile während der Initialisierungsphase zugewiesen wird. Wie in diesem Lernprogramm gezeigt, können wir der MasterPageFile Eigenschaft einen Wert zuweisen, solange wir dies vor dem Ende der PreInit-Phase tun. Durch die programmgesteuerte Angabe der Master-Seite eröffnet sich die Möglichkeit für erweiterte Szenarien, wie beispielsweise die dynamische Bindung einer Inhaltsseite an eine Master-Seite basierend auf externen Faktoren.
Glückliche Programmierung!
Weitere Lektüre
Weitere Informationen zu den in diesem Lernprogramm erläuterten Themen finden Sie in den folgenden Ressourcen:
- Übersicht über den Seitenlebenszyklus ASP.NET
- übersicht über ASP.NET Designs und Skins
- Masterseiten: Tipps, Tricks und Fallen
- Themen in ASP.NET
Zum Autor
Scott Mitchell, Autor mehrerer ASP/ASP.NET Bücher und Gründer von 4GuysFromRolla.com, arbeitet seit 1998 mit Microsoft Web Technologies zusammen. Scott arbeitet als unabhängiger Berater, Trainer und Schriftsteller. Sein neuestes Buch ist Sams Teach Yourself ASP.NET 3.5 in 24 Stunden. Scott kann unter mitchell@4GuysFromRolla.com erreicht werden oder über seinen Blog unter http://ScottOnWriting.NET.
Besonderer Dank an
Diese Lernprogrammreihe wurde von vielen hilfreichen Prüfern überprüft. Leitender Prüfer für dieses Lernprogramm war Suchi Banerjee. Möchten Sie meine bevorstehenden MSDN-Artikel überprüfen? Wenn das der Fall ist, schreiben Sie mir eine Nachricht an mitchell@4GuysFromRolla.com