Partilhar via


Especificação Programática da Página Mestre (VB)

por Scott Mitchell

Analisa como definir programaticamente a página mestre da página de conteúdo através do manipulador de eventos PreInit.

Introduction

Desde o exemplo inaugural em Criar um Layout Site-Wide Usando Páginas Mestres, todas as páginas de conteúdo referenciaram a sua página mestra de forma declarativa através do MasterPageFile atributo na @Page diretiva. Por exemplo, a seguinte @Page diretiva liga a página de conteúdo à página Site.mastermestra :

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

A Page classe no System.Web.UI namespace inclui uma MasterPageFile propriedade que devolve o caminho para a página mestra da página de conteúdo; é esta propriedade que é definida pela @Page diretiva. Esta propriedade também pode ser usada para especificar programaticamente a página mestra da página de conteúdo. Esta abordagem é útil se quiser atribuir dinamicamente a página-mestre com base em fatores externos, como o utilizador que visita a página.

Neste tutorial, adicionamos uma segunda página-mestre ao nosso site e decidimos dinamicamente qual a página-mestre a usar em tempo de execução.

Passo 1: Uma Análise do Ciclo de Vida da Página

Sempre que um pedido chega ao servidor web para uma página ASP.NET que é uma página de conteúdo, o motor de ASP.NET deve fundir os controlos de Conteúdo da página nos respetivos controlos ContentPlaceHolder da página mestre. Esta fusão cria uma única hierarquia de controlo que pode depois avançar ao longo do ciclo de vida típico da página.

A Figura 1 ilustra esta fusão. O Passo 1 da Figura 1 mostra as hierarquias de conteúdo inicial e de controlo da página principal. No final da fase PreInit, os controlos de Conteúdo na página são adicionados aos ContentPlaceHolders correspondentes na página mestra (Passo 2). Após esta fusão, a página mestra serve como raiz da hierarquia de controlo fundida. Esta hierarquia de controlo fundido é então adicionada à página para produzir a hierarquia de controlo finalizada (Passo 3). O resultado líquido é que a hierarquia de controle da página inclui a hierarquia de controle integrada.

As hierarquias de controlo da Página Mestra e da Página de Conteúdo são fundidas durante a fase PreInit

Figura 01: As hierarquias de controlo da Página Mestra e da Página de Conteúdo são fundidas durante a fase PreInit (Clique para ver a imagem em tamanho real)

Passo 2: Definir aMasterPageFilePropriedade a partir do Código

A página mestra que participa nesta fusão depende do valor da Page propriedade do MasterPageFile objeto. A definição do atributo MasterPageFile na diretiva @Page resulta na atribuição da propriedade MasterPageFile de Page durante a fase de inicialização, que é a primeira fase do ciclo de vida da página. Podemos alternativamente definir esta propriedade programaticamente. No entanto, é imperativo que esta propriedade seja definida antes da fusão na Figura 1 ocorrer.

No início da fase PreInit, o Page objeto eleva o seu PreInit evento e chama o seu OnPreInit método. Para definir a página mestre programaticamente, podemos criar um gestor de eventos para o PreInit evento ou sobrescrever o OnPreInit método. Vamos analisar ambas as abordagens.

Comece por abrir Default.aspx.vb, o ficheiro de classe code-behind para a página inicial do nosso site. Adicione um gestor de eventos para o evento da PreInit página digitando o seguinte código:

Protected Sub Page_PreInit(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.PreInit 
End Sub

Daqui podemos definir a MasterPageFile propriedade. Atualize o código para que atribua o valor "~/Site.master" à MasterPageFile propriedade.

Protected Sub Page_PreInit(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.PreInit 
 Me.MasterPageFile = "~/Site.master"
End Sub

Se definires um ponto de interrupção e começares a depurar, vais ver que sempre que a Default.aspx página é visitada ou há um retorno de postback para essa página, o Page_PreInit gestor de eventos é executado e a MasterPageFile propriedade é atribuída a "~/Site.master".

Alternativamente, podes sobrepor o Page método da OnPreInit classe e definir a MasterPageFile propriedade aí. Para este exemplo, não vamos definir a página mestra numa página particular, mas sim a partir de BasePage. Lembre-se que criámos uma classe de página base personalizada (BasePage) no tutorial Especificando o Título, Meta Tags e Outros Cabeçalhos HTML na Página Mestre . Atualmente BasePage sobrepõe-se ao Page método da OnLoadComplete classe, onde define a propriedade da Title página com base nos dados do mapa do site. Vamos atualizar BasePage para também sobrescrever o OnPreInit método e especificar programaticamente a página mestre.

Protected Overrides Sub OnPreInit(ByVal e As System.EventArgs)
 Me.MasterPageFile = "~/Site.master" 
 MyBase.OnPreInit(e)
End Sub

Como todas as nossas páginas de conteúdo derivam de BasePage, todas elas têm agora a sua página mestra programaticamente atribuída. Neste ponto, o PreInit manipulador de eventos em Default.aspx.vb é supérfluo; pode removê-lo.

E quanto à@PageDiretiva?

O que pode ser um pouco confuso é que as propriedades das MasterPageFile páginas de conteúdo estão agora a ser especificadas em dois locais: programaticamente no BasePage método da OnPreInit classe, bem como através do MasterPageFile atributo na diretiva de @Page cada página de conteúdo.

A primeira etapa do ciclo de vida da página é a fase de Inicialização. Durante esta fase, a Page propriedade do MasterPageFile objeto recebe o valor do MasterPageFile atributo na @Page diretiva (se for fornecido). A etapa PreInit segue a etapa de Inicialização, e é aqui que definimos programaticamente a Page propriedade do MasterPageFile objeto, sobrescrevendo assim o valor atribuído pela @Page diretiva. Como estamos a definir a Page propriedade do MasterPageFile objeto programaticamente, poderíamos remover o MasterPageFile atributo da @Page diretiva sem afetar a experiência do utilizador final. Para te convenceres disto, remove o MasterPageFile atributo da @Page diretiva em Default.aspx e depois visita a página através de um navegador. Como seria de esperar, a saída é a mesma de antes do atributo ter sido removido.

Se a MasterPageFile propriedade é definida pela @Page diretiva ou programaticamente é irrelevante para a experiência do utilizador final. No entanto, o MasterPageFile atributo na @Page diretiva é usado pelo Visual Studio durante o tempo de concepção para produzir a vista WYSIWYG no Designer. Se regressar ao Default.aspx no Visual Studio e navegar até ao Designer, verá a mensagem: "Erro de Página Mestra: A página tem controlos que requerem uma referência de Página Mestra, mas nenhuma está especificada" (ver Figura 2).

Em suma, deve deixar o atributo MasterPageFile na diretiva @Page para desfrutar de uma experiência rica de design no Visual Studio.

O Visual Studio utiliza o atributo MasterPageFile da diretiva <span class= @Page para renderizar a vista de design" />

Figura 02: O Visual Studio utiliza o @Page atributo da MasterPageFile diretiva para renderizar a vista de design (clique para ver a imagem em tamanho real)

Passo 3: Criação de uma Página Mestra Alternativa

Como a página mestra de uma página de conteúdo pode ser definida programaticamente em tempo de execução, é possível carregar dinamicamente uma página mestra específica com base em critérios externos. Esta funcionalidade pode ser útil em situações em que o layout do site precisa de variar consoante o utilizador. Por exemplo, uma aplicação web de motor de blogs pode permitir que os seus utilizadores escolham um layout para o seu blog, onde cada layout está associado a uma página mestra diferente. Em tempo de execução, quando um visitante está a visualizar o blog de um utilizador, a aplicação web teria de determinar o layout do blogue e associar dinamicamente a página mestra correspondente à página de conteúdo.

Vamos analisar como carregar dinamicamente uma página mestra em tempo de execução com base em alguns critérios externos. O nosso site contém atualmente apenas uma página mestra (Site.master). Precisamos de outra página-mestre para ilustrar a escolha de uma página-mestre em tempo de execução. Esta etapa foca-se na criação e configuração da nova página mestre. O Passo 4 trata de determinar que página mestre usar em tempo de execução.

Crie uma nova página mestra na pasta raiz chamada Alternate.master. Adicione também uma nova folha de estilo ao site chamada AlternateStyles.css.

Adicione outra página mestra e ficheiro CSS ao site

Figura 03: Adicionar outra página mestre e ficheiro CSS ao site (Clique para ver a imagem em tamanho real)

Desenhei a Alternate.master página principal para que o título apareça no topo da página, centrado e com fundo azul-marinho. Eliminei a coluna da esquerda e movi esse conteúdo sob o controlo MainContent ContentPlaceHolder, que agora se estende por toda a largura da página. Além disso, eliminei a lista de Lições não ordenada e substituí-a por uma lista horizontal acima de MainContent. Também atualizei as fontes e cores usadas pela página mestra (e, por extensão, pelas suas páginas de conteúdo). A Figura 4 mostra Default.aspx quando se usa a Alternate.master página mestre.

Observação

ASP.NET inclui a capacidade de definir Temas. Um Tema é uma coleção de imagens, ficheiros CSS e definições de propriedades de controlo Web relacionadas com o estilo que podem ser aplicadas a uma página em tempo de execução. Os temas são a melhor opção se os layouts do seu site diferem apenas nas imagens apresentadas e pelas suas regras de CSS. Se os layouts diferem mais substancialmente, como usar controlos Web diferentes ou ter um layout radicalmente diferente, então terá de usar páginas-mestre separadas. Consulte a secção de Leituras Adicionais no final deste tutorial para mais informações sobre Temas.

As nossas páginas de conteúdo podem agora beneficiar de um novo aspeto e ambiente

Figura 04: As nossas páginas de conteúdo podem agora beneficiar de um novo visual (Clique para ver a imagem em tamanho real)

Quando a marcação das páginas mestra e de conteúdo está combinada, a classe MasterPage verifica se todos os controlos de conteúdo nas páginas de conteúdo fazem referência a um ContentPlaceHolder na página mestra. Uma exceção é lançada se for encontrado um controlo de Conteúdo que faça referência a um ContentPlaceHolder inexistente. Por outras palavras, é imperativo que a página-mestre atribuída à página de conteúdo tenha um ContentPlaceHolder para cada controlo de conteúdo na página de conteúdo.

A Site.master página principal inclui quatro controles ContentPlaceHolder:

  • head
  • MainContent
  • QuickLoginUI
  • LeftColumnContent

Algumas das páginas de conteúdo do nosso site incluem apenas um ou dois controlos de conteúdo; outros incluem um controlo de Conteúdo para cada um dos ContentPlaceHolders disponíveis. Se a nossa nova página mestra (Alternate.master) alguma vez for atribuída àquelas páginas de conteúdo que tenham controlos de Conteúdo para todos os ContentPlaceHolders em Site.master, então é essencial que Alternate.master inclua também os mesmos controlos de ContentPlaceHolder de Site.master.

Para que a sua Alternate.master página mestre se assemelhe à minha (ver Figura 4), comece por definir os estilos da página mestra na AlternateStyles.css folha de estilos. Adicione as seguintes regras em: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;
}

De seguida, adicione a seguinte marcação declarativa a Alternate.master. Como pode ver, Alternate.master contém quatro controlos ContentPlaceHolder com os mesmos ID valores que os controlos ContentPlaceHolder em Site.master. Além disso, inclui um controlo ScriptManager, necessário para as páginas do nosso site que utilizam o framework ASP.NET AJAX.

<!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>

Testando a Nova Página Mestre

Para testar esta nova página-mestre, atualize o BasePage método da OnPreInit classe para que a MasterPageFile propriedade seja atribuída ao valor "~/Alternate.maser" e depois visite o site. Todas as páginas devem funcionar sem erro, exceto duas: ~/Admin/AddProduct.aspx e ~/Admin/Products.aspx. Adicionar um produto à DetailsView em ~/Admin/AddProduct.aspx resulta num NullReferenceException na linha de código que tenta definir a propriedade da página mestre GridMessageText. Ao visitar ~/Admin/Products.aspx uma InvalidCastException é gerada no carregamento da página com a mensagem: "Não é possível converter o objeto do tipo 'ASP.alternate_master' para o tipo 'ASP.site_master'."

Estes erros ocorrem porque a Site.master classe code-behind inclui eventos públicos, propriedades e métodos que não estão definidos em Alternate.master. A parte de marcação destas duas páginas tem uma @MasterType diretiva que faz referência à Site.master página mestre.

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

Além disso, o manipulador de eventos do ItemInserted DetailsView em ~/Admin/AddProduct.aspx inclui código que lança a propriedade de tipagem fraca Page.Master para um objeto do tipo Site. A diretiva @MasterType (usada desta forma) e a conversão de tipo no manipulador de eventos ItemInserted acoplam estreitamente as páginas ~/Admin/AddProduct.aspx e ~/Admin/Products.aspx à página mestre Site.master.

Para quebrar este acoplamento estreito, podemos ter Site.master e Alternate.master derivar de uma classe base comum que contenha definições para os membros públicos. Depois disso, podemos atualizar a @MasterType diretiva para referenciar este tipo de base comum.

Criação de uma Classe de Master Page Base Personalizada

Adicione um novo ficheiro de classe à App_Code pasta nomeada BaseMasterPage.vb e faça com que derive de System.Web.UI.MasterPage. Precisamos de definir o método RefreshRecentProductsGrid e a propriedade GridMessageText em BaseMasterPage, mas não podemos simplesmente movê-los para lá, uma vez que estes membros, em Site.master, trabalham com controlos Web específicos da página-mestre Site.master (o GridView RecentProducts e o Label GridMessage).

O que precisamos de fazer é configurar BaseMasterPage de forma a que estes membros sejam definidos ali, mas sejam efetivamente implementados pelas classes derivadas de BaseMasterPage (Site.master e Alternate.master). Este tipo de herança é possível marcando a classe como MustInherit e os seus membros como MustOverride. Resumindo, adicionar estas palavras-chave à classe e aos seus dois membros anuncia que BaseMasterPage não implementou RefreshRecentProductsGrid e GridMessageText, mas que as classes derivadas o farão.

Também precisamos de definir o PricesDoubled evento em BaseMasterPage e fornecer um meio, pelas classes derivadas, de elevar o evento. O padrão usado no .NET Framework para facilitar este comportamento é criar um evento público na classe base e adicionar um método protegido e sobrescrito chamado OnEventName. As classes derivadas podem então chamar este método para levantar o evento ou podem sobrepê-lo para executar código imediatamente antes ou depois do evento ser ativado.

Atualize a sua BaseMasterPage classe para que contenha o seguinte código:

Public MustInherit Class BaseMasterPage 
 Inherits System.Web.UI.MasterPage 
 Public Event PricesDoubled As EventHandler
 Protected Overridable Sub OnPricesDoubled(ByVal e As EventArgs)
 RaiseEvent PricesDoubled(Me, e)
 End Sub
 Public MustOverride Sub RefreshRecentProductsGrid() 
 Public MustOverride Property GridMessageText() As String 
End Class

De seguida, vá à classe de código subjacente Site.master para derivar de BaseMasterPage. Como BaseMasterPage contém membros marcados MustOverride , precisamos de sobrepor esses membros aqui em Site.master. Adicione a Overrides palavra-chave às definições de método e propriedade. Também atualize o código que dispara o evento PricesDoubled no manipulador de eventos do Botão DoublePrice com uma chamada para o método da classe base OnPricesDoubled.

Após estas modificações, a Site.master classe code-behind deve conter o seguinte código:

Partial Class Site 
 Inherits BaseMasterPage
 Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load 
 DateDisplay.Text = DateTime.Now.ToString("dddd, MMMM dd")
 End Sub
 Public Overrides Sub RefreshRecentProductsGrid() 
 RecentProducts.DataBind()
 End Sub 
 Public Overrides Property GridMessageText() As String 
 Get
 Return GridMessage.Text
 End Get 
 Set(ByVal Value As String) 
 GridMessage.Text = Value 
 End Set
 End Property 
 Protected Sub DoublePrice_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles DoublePrice.Click 
 ' Double the prices 
 DoublePricesDataSource.Update()
 ' Refresh RecentProducts 
 RecentProducts.DataBind()
 ' Raise the PricesDoubled event
 MyBase.OnPricesDoubled(EventArgs.Empty)
 End Sub 
End Class

Também precisamos de atualizar a classe code-behind de Alternate.master para derivar de BaseMasterPage e substituir os dois membros de MustOverride. Mas, como Alternate.master não contém um GridView que liste os produtos mais recentes nem uma Etiqueta que mostre uma mensagem após a adição de um novo produto à base de dados, estes métodos não precisam de fazer nada.

Partial Class Alternate 
 Inherits BaseMasterPage
 Public Overrides Property GridMessageText() As String 
 Get
 Return String.Empty
 End Get
 Set(ByVal value As String) 
 ' Do nothing 
 End Set 
 End Property 
 Public Overrides Sub RefreshRecentProductsGrid()
 ' Do nothing 
 End Sub 
End Class

Referência à Classe Base da Página Master

Agora que concluímos a BaseMasterPage classe e temos as nossas duas páginas-mestra a estendê-la, o nosso passo final é atualizar as páginas ~/Admin/AddProduct.aspx e ~/Admin/Products.aspx para fazer referência a este tipo comum. Comece por alterar a diretiva @MasterType em ambas as páginas de:

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

To:

<%@ MasterType TypeName="BaseMasterPage" %>

Em vez de referenciar um caminho de ficheiro, a @MasterType propriedade agora faz referência ao tipo base (BaseMasterPage). Consequentemente, a propriedade fortemente tipada Master, usada nas classes de código subjacente de ambas as páginas, é agora do tipo BaseMasterPage (em vez de do tipo Site). Com esta mudança em vigor, revisite ~/Admin/Products.aspx. Anteriormente, isto resultava num erro de casting porque a página estava configurada para usar a Alternate.master página mestre, mas a @MasterType diretiva referenciava o Site.master ficheiro. Mas agora a página é renderizada sem erro. Isto porque a Alternate.master página mestre pode ser convertida num objeto do tipo BaseMasterPage (uma vez que o estende).

Há uma pequena alteração que precisa de ser feita em ~/Admin/AddProduct.aspx. O manipulador de eventos do controlo ItemInserted DetailsView utiliza tanto a propriedade fortemente tipada Master como a propriedade fracamente tipada Page.Master. Corrigimos a referência fortemente tipada quando atualizámos a @MasterType diretiva, mas ainda precisamos de atualizar a referência fracamente tipada. Substitua a seguinte linha de código:

Dim myMasterPage As Site = CType(Page.Master, Site)

Com o seguinte, que converte Page.Master para o tipo base:

Dim myMasterPage As BaseMasterPage = CType(Page.Master, BaseMasterPage)

Passo 4: Determinar que Página-Mestre Atribuir às Páginas de Conteúdo

A nossa BasePage classe define atualmente todas as propriedades das MasterPageFile páginas de conteúdo para um valor codificado fixamente na fase PreInit do ciclo de vida da página. Podemos atualizar este código para basear a página mestre num fator externo. Talvez a página mestra a ser carregada dependa das preferências do utilizador atualmente autenticado. Nesse caso, teríamos de escrever código no método OnPreInit em BasePage que procura as preferências da página principal do utilizador atualmente a visitar.

Vamos criar uma página web que permita ao utilizador escolher qual a página-mestre a usar – Site.master ou Alternate.master – e guardar essa escolha numa variável de Sessão. Comece por criar uma nova página web no diretório raiz chamada ChooseMasterPage.aspx. Ao criar esta página (ou quaisquer outras páginas de conteúdo daqui para a frente) não precisa de a vincular a uma página-mestre porque a página-mestre está definida programaticamente em BasePage. No entanto, se não vincular a nova página a uma página mestre, então a marcação declarativa padrão da nova página contém um Formulário Web e outro conteúdo fornecido pela página mestre. Terá de substituir manualmente esta marcação pelos controlos de Conteúdo apropriados. Por essa razão, acho mais fácil associar a nova página ASP.NET a uma página mestre.

Observação

Porque Site.master e Alternate.master têm o mesmo conjunto de controlos ContentPlaceHolder, não importa qual a página-mestre que escolhas ao criar a nova página de conteúdo. Para maior consistência, sugeria usar Site.master.

Adicionar uma nova página de conteúdo ao site

Figura 05: Adicionar uma nova página de conteúdo ao site (Clique para ver a imagem em tamanho real)

Atualize o Web.sitemap ficheiro para incluir uma entrada para esta lição. Adicione a seguinte marcação abaixo de <siteMapNode> para as Páginas Mestras e a lição de ASP.NET AJAX.

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

Antes de adicionar qualquer conteúdo à ChooseMasterPage.aspx página, reserve um momento para atualizar a classe code-behind da página para que derive de BasePage (em vez de System.Web.UI.Page). De seguida, adicione um controlo DropDownList à página, defina a sua ID propriedade para MasterPageChoice, e adicione dois ListItems com os Text valores "~/Site.master" e "~/Alternate.master".

Adicione um controlo Web de Botão à página e defina as propriedades ID e Text para SaveLayout e "Guardar Escolha de Layout", respetivamente. Neste ponto, a marcação declarativa da sua página deve ser semelhante à seguinte:

<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>

Quando a página é visitada pela primeira vez, precisamos de mostrar a escolha de página mestra selecionada pelo utilizador. Crie um Page_Load gestor de eventos e adicione o seguinte código:

Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load 
 If Not Page.IsPostBack Then 
 If Session("MyMasterPage") IsNot Nothing Then 
 Dim li As ListItem = MasterPageChoice.Items.FindByText(Session("MyMasterPage").ToString())
 If li IsNot Nothing Then 
 li.Selected = True
 End If 
 End If 
 End If 
End Sub

O código acima é executado apenas na primeira visita à página (e não em postbacks subsequentes). Primeiro verifica se a variável MyMasterPage Session existe. Se o fizer, tenta encontrar o Item da Lista correspondente na MasterPageChoice Lista Dropdown. Se for encontrado um ItemDeLista correspondente, a sua Selected propriedade é definida como True.

Também precisamos de código que guarde a escolha do utilizador na MyMasterPage variável Session. Crie um gestor de eventos para o SaveLayout evento do Click Botão e adicione o seguinte código:

Protected Sub SaveLayout_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles SaveLayout.Click 
 Session("MyMasterPage") = MasterPageChoice.SelectedValue 
 Response.Redirect("ChooseMasterPage.aspx")
End Sub

Observação

Quando o Click manipulador de eventos é executado durante o postback, a página mestre já foi selecionada. Assim, a seleção da lista suspensa do utilizador só estará ativa na próxima visita à página. Isto Response.Redirect obriga o navegador a re-solicitar ChooseMasterPage.aspx.

Com a ChooseMasterPage.aspx página concluída, a nossa tarefa final é que BasePage atribua a propriedade MasterPageFile com base no valor da variável de sessão MyMasterPage. Se a variável Session não estiver definida, defina BasePage por defeito para Site.master.

Protected Overrides Sub OnPreInit(ByVal e As System.EventArgs)
 SetMasterPageFile() 
 MyBase.OnPreInit(e)
End Sub 
Protected Overridable Sub SetMasterPageFile() 
 Me.MasterPageFile = GetMasterPageFileFromSession() 
End Sub 
Protected Function GetMasterPageFileFromSession() As String 
 If Session("MyMasterPage") Is Nothing Then
 Return "~/Site.master"
 Else 
 Return Session("MyMasterPage").ToString() 
 End If 
End Function

Observação

Mudei o código que atribui a Page propriedade do MasterPageFile objeto para fora do OnPreInit gestor de eventos e para dois métodos separados. Este primeiro método, SetMasterPageFile, atribui a MasterPageFile propriedade ao valor devolvido pelo segundo método, GetMasterPageFileFromSession. Marquei o método SetMasterPageFileOverridable para que as futuras classes que estendam BasePage possam opcionalmente sobrescrevê-lo para implementar lógica personalizada, se necessário. Veremos um exemplo de substituição da propriedade SetMasterPageFile de BasePage no próximo tutorial.

Com este código implementado, visite a página ChooseMasterPage.aspx. Inicialmente, a Site.master página mestra é selecionada (ver Figura 6), mas o utilizador pode selecionar uma página mestra diferente na lista suspensa.

As páginas de conteúdo são exibidas usando a página-mestre site.master

Figura 06: As Páginas de Conteúdo são Exibidas Usando a Site.master Página Mestre (Clique para ver a imagem em tamanho real)

As páginas de conteúdo são agora exibidas usando a página-mestre Alternate.master

Figura 07: As páginas de conteúdo são agora exibidas usando a Alternate.master página principal (Clique para ver a imagem em tamanho real)

Resumo

Quando uma página de conteúdo é visitada, os seus controlos de Conteúdo são fundidos com os controlos ContentPlaceHolder da página mestra. A página mestra da página de conteúdo é indicada pela Page propriedade da MasterPageFile classe, que é atribuída ao @Page atributo da MasterPageFile diretiva durante a fase de Inicialização. Como este tutorial mostrou, podemos atribuir um valor à MasterPageFile propriedade desde que o façamos antes do final da fase PreInit. Poder especificar programaticamente a página-mestre abre a porta a cenários mais avançados, como vincular dinamicamente uma página de conteúdo a uma página-mestre com base em fatores externos.

Feliz Programação!

Leitura adicional

Para obter mais informações sobre os tópicos discutidos neste tutorial, consulte os seguintes recursos:

Sobre o Autor

Scott Mitchell, autor de vários livros sobre ASP/ASP.NET e fundador da 4GuysFromRolla.com, trabalha com tecnologias Web da Microsoft desde 1998. Scott trabalha como consultor, formador e escritor independente. O seu livro mais recente é Sams Teach Yourself ASP.NET 3.5 in 24 Hours. Scott pode ser contatado em mitchell@4GuysFromRolla.com ou através de seu blog em http://ScottOnWriting.NET.

Um agradecimento especial a

Esta série de tutoriais foi revisada por muitos revisores úteis. A revisora principal deste tutorial foi Suchi Banerjee. Interessado em rever meus próximos artigos do MSDN? Se sim, envia-me uma mensagem para mitchell@4GuysFromRolla.com