Partilhar via


Especificar a página mestra programaticamente (C#)

por Scott Mitchell

Analisa a configuração da página de master de conteúdo programaticamente por meio do manipulador de eventos PreInit.

Introdução

Desde o exemplo inaugural em Criando um layout de Site-Wide usando páginas mestras, todas as páginas de conteúdo referenciaram seus master página declarativamente por meio do MasterPageFile atributo na @Page diretiva . Por exemplo, a diretiva a seguir @Page vincula a página de conteúdo à página Site.mastermaster :

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

A Page classe no System.Web.UI namespace inclui uma MasterPageFile propriedade que retorna o caminho para a página master da página de conteúdo; é essa propriedade definida pela @Page diretiva . Essa propriedade também pode ser usada para especificar programaticamente a página master da página de conteúdo. Essa abordagem será útil se você quiser atribuir dinamicamente a página master com base em fatores externos, como o usuário que visita a página.

Neste tutorial, adicionamos uma segunda página master ao nosso site e decidimos dinamicamente qual master página usar em runtime.

Etapa 1: Uma olhada no ciclo de vida da página

Sempre que uma solicitação chega ao servidor Web para uma página de ASP.NET que é uma página de conteúdo, o mecanismo de ASP.NET deve fundir os controles de Conteúdo da página nos controles ContentPlaceHolder correspondentes da página master. Essa fusão cria uma hierarquia de controle único que pode prosseguir pelo ciclo de vida típico da página.

A Figura 1 ilustra essa fusão. A etapa 1 na Figura 1 mostra o conteúdo inicial e master hierarquias de controle de página. No final do estágio PreInit, os controles de conteúdo na página são adicionados ao ContentPlaceHolders correspondente na página master (Etapa 2). Após essa fusão, a página master serve como a raiz da hierarquia de controle fundida. Essa hierarquia de controle fundida é então adicionada à página para produzir a hierarquia de controle finalizada (Etapa 3). O resultado líquido é que a hierarquia de controle da página inclui a hierarquia de controle fundida.

As hierarquias de controle da página mestra e do conteúdo são fundidas durante o estágio pré-inicial

Figura 01: As hierarquias de controle da página mestra e da página de conteúdo são fundidas juntas durante o estágio PreInit (clique para exibir a imagem em tamanho real)

Etapa 2: Definindo a propriedade doMasterPageFilecódigo

O que master página participa dessa fusão depende do valor da Page propriedade do MasterPageFile objeto. Definir o MasterPageFile atributo na @Page diretiva tem o efeito líquido de atribuir a Pagepropriedade durante MasterPageFile o estágio inicialização, que é o primeiro estágio do ciclo de vida da página. Como alternativa, podemos definir essa propriedade programaticamente. No entanto, é imperativo que essa propriedade seja definida antes da fusão na Figura 1 ocorrer.

No início do estágio PreInit, o Page objeto aciona seu PreInit evento e chama seu OnPreInit método. Para definir a página master programaticamente, podemos criar um manipulador de eventos para o PreInit evento ou substituir o OnPreInit método . Vamos examinar as duas abordagens.

Comece abrindo Default.aspx.cs, o arquivo de classe code-behind para a home page do nosso site. Adicione um manipulador de eventos para o evento da PreInit página digitando no seguinte código:

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

A partir daqui, podemos definir a MasterPageFile propriedade . Atualize o código para que ele atribua o valor "~/Site. master" para a MasterPageFile propriedade .

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

Se você definir um ponto de interrupção e começar com a depuração, verá que sempre que a Default.aspx página for visitada ou sempre que houver um postback nessa página, o Page_PreInit manipulador de eventos será executado e a MasterPageFile propriedade será atribuída a "~/Site.master".

Como alternativa, você pode substituir o Page método da OnPreInit classe e definir a MasterPageFile propriedade lá. Para este exemplo, não vamos definir a página master em uma página específica, mas sim de BasePage. Lembre-se de que criamos uma classe de página base personalizada (BasePage) novamente no tutorial Especificando o título, metamaras e outros cabeçalhos HTML na Página Mestra . Atualmente BasePage , substitui o Page método da OnLoadComplete classe, em que define a propriedade da Title página com base nos dados do mapa do site. Vamos atualizar BasePage para também substituir o OnPreInit método para especificar programaticamente a página master.

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

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

E a@Pagediretiva ?

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

O primeiro estágio no ciclo de vida da página é o estágio inicialização. Durante esse estágio, a Page propriedade do MasterPageFile objeto recebe o valor do MasterPageFile atributo na @Page diretiva (se for fornecido). O estágio PreInit segue o estágio inicialização e é aqui que definimos programaticamente a Page propriedade do MasterPageFile objeto, substituindo assim o valor atribuído da @Page diretiva . Como estamos definindo a Page propriedade do MasterPageFile objeto programaticamente, poderíamos remover o MasterPageFile atributo da @Page diretiva sem afetar a experiência do usuário final. Para se convencer disso, vá em frente e remova o MasterPageFile atributo da @Page diretiva em Default.aspx e visite a página por meio de um navegador. Como era de se esperar, a saída é a mesma que antes de o atributo ser removido.

Se a MasterPageFile propriedade é definida por meio da @Page diretiva ou programaticamente é inconsequente à experiência do usuário final. No entanto, o MasterPageFile atributo na @Page diretiva é usado pelo Visual Studio durante o tempo de design para produzir a exibição WYSIWYG no Designer. Se você voltar para Default.aspx o Visual Studio e navegar até o Designer verá a mensagem "Erro da Página Mestra: a página tem controles que exigem uma referência de Página Mestra, mas nenhuma é especificada" (consulte a Figura 2).

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

O Visual Studio usa o atributo MasterPageFile da Directive para renderizar a exibição de design" />

Figura 02: o Visual Studio usa o @Page atributo da MasterPageFile diretiva para renderizar a exibição de design (clique para exibir a imagem em tamanho real)

Etapa 3: Criando uma página mestra alternativa

Como a página master de uma página de conteúdo pode ser definida programaticamente em runtime, é possível carregar dinamicamente uma página de master específica com base em alguns critérios externos. Essa funcionalidade pode ser útil em situações em que o layout do site precisa variar de acordo com o usuário. Por exemplo, um aplicativo Web do mecanismo de blog pode permitir que seus usuários escolham um layout para seu blog, em que cada layout está associado a uma página de master diferente. Em runtime, quando um visitante está exibindo o blog de um usuário, o aplicativo Web precisaria determinar o layout do blog e associar dinamicamente a página de master correspondente à página de conteúdo.

Vamos examinar como carregar dinamicamente uma página de master em runtime com base em alguns critérios externos. Atualmente, nosso site contém apenas uma página de master (Site.master). Precisamos de outra página master para ilustrar a escolha de uma página de master no runtime. Esta etapa se concentra na criação e configuração da nova página de master. A etapa 4 analisa a determinação de qual página master usar no runtime.

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

Adicionar outra página mestra e um arquivo CSS ao site

Figura 03: Adicionar outra página mestra e arquivo CSS ao site (clique para exibir a imagem em tamanho real)

Eu projetei a Alternate.master página master para ter o título exibido na parte superior da página, centralizado e em um plano de fundo da marinha. Dispensei a coluna esquerda e movi esse conteúdo abaixo do MainContent controle ContentPlaceHolder, que agora abrange toda a largura da página. Além disso, nixed the unordered Lessons list and replaced it with a horizontal list above MainContent. Também atualizei as fontes e cores usadas pela página master (e, por extensão, suas páginas de conteúdo). A Figura 4 mostra Default.aspx ao usar a Alternate.master página master.

Observação

ASP.NET inclui a capacidade de definir Temas. Um Tema é uma coleção de imagens, arquivos CSS e configurações de propriedade de controle da Web relacionadas ao estilo que podem ser aplicadas a uma página em runtime. Os temas são o caminho a percorrer se os layouts do seu site diferem apenas nas imagens exibidas e pelas regras do CSS. Se os layouts forem mais substancialmente diferentes, como usar diferentes controles da Web ou ter um layout radicalmente diferente, você precisará usar páginas master separadas. Consulte a seção Leitura Adicional no final deste tutorial para obter mais informações sobre Temas.

Nossas páginas de conteúdo agora podem usar uma nova aparência

Figura 04: nossas páginas de conteúdo agora podem usar uma nova aparência (clique para exibir a imagem em tamanho real)

Quando a marcação das páginas de master e conteúdo é fundida, a MasterPage classe verifica se todos os controles de conteúdo na página de conteúdo fazem referência a um ContentPlaceHolder na página master. Uma exceção será gerada se um controle content que faz referência a um ContentPlaceHolder inexistente for encontrado. Em outras palavras, é imperativo que a página master que está sendo atribuída à página de conteúdo tenha um ContentPlaceHolder para cada controle de conteúdo na página de conteúdo.

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

  • head
  • MainContent
  • QuickLoginUI
  • LeftColumnContent

Algumas das páginas de conteúdo em nosso site incluem apenas um ou dois controles de conteúdo; outros incluem um controle de conteúdo para cada um dos ContentPlaceHolders disponíveis. Se nossa nova página de master (Alternate.master) puder ser atribuída a essas páginas de conteúdo que têm controles de conteúdo para todos os ContentPlaceHolders, Site.master é essencial que Alternate.master também incluam os mesmos controles ContentPlaceHolder que Site.master.

Para que sua Alternate.master página de master fique semelhante à minha (consulte Figura 4), comece definindo os estilos da página master na AlternateStyles.css folha de estilos. Adicione as seguintes regras a 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; 
}

Em seguida, adicione a marcação declarativa a seguir a Alternate.master. Como você pode ver, Alternate.master contém quatro controles ContentPlaceHolder com os mesmos ID valores que os controles ContentPlaceHolder em Site.master. Além disso, ele inclui um controle ScriptManager, que é necessário para as páginas em nosso site que usam o ASP.NET estrutura 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 mestra

Para testar esse novo master página, atualize o BasePage método da OnPreInit classe para que a MasterPageFile propriedade receba o valor "~/Alternate.master" e visite o site. Cada página deve funcionar sem erro, exceto por dois: ~/Admin/AddProduct.aspx e ~/Admin/Products.aspx. Adicionar um produto ao DetailsView resulta em ~/Admin/AddProduct.aspx um NullReferenceException da linha de código que tenta definir a propriedade da GridMessageText página master. Ao visitar ~/Admin/Products.aspx um InvalidCastException é gerado no carregamento da página com a mensagem: "Não é possível converter o objeto do tipo 'ASP.alternate_master' para digitar 'ASP.site_master'."

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

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

Além disso, o manipulador de eventos do ItemInserted DetailsView no ~/Admin/AddProduct.aspx inclui o código que converte a propriedade de tipo Page.Master flexível em um objeto do tipo Site. A @MasterType diretiva (usada dessa forma) e a conversão no ItemInserted manipulador de eventos associam firmemente as ~/Admin/AddProduct.aspx páginas e ~/Admin/Products.aspx à Site.master página master.

Para interromper esse acoplamento apertado, podemos ter Site.master e Alternate.master derivar de uma classe base comum que contém definições para os membros públicos. Depois disso, podemos atualizar a @MasterType diretiva para fazer referência a esse tipo base comum.

Criando uma classe de página mestra base personalizada

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

O que precisamos fazer é configurar BaseMasterPage de forma que esses membros sejam definidos lá, mas, na verdade, são implementados pelas BaseMasterPageclasses derivadas de (Site.master e Alternate.master). Esse tipo de herança é possível marcando a classe e seus membros como abstract. Em suma, adicionar o abstract palavra-chave a esses dois membros anuncia que BaseMasterPage não implementou RefreshRecentProductsGrid e GridMessageText, mas que suas classes derivadas irão.

Também precisamos definir o PricesDoubled evento em BaseMasterPage e fornecer um meio pelas classes derivadas para acionar o evento. O padrão usado no .NET Framework para facilitar esse comportamento é criar um evento público na classe base e adicionar um método protegido virtual chamado OnEventName. As classes derivadas podem chamar esse método para acionar o evento ou podem substituí-lo para executar o código imediatamente antes ou depois que o evento é acionado.

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

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

Em seguida, vá para a Site.master classe code-behind e faça com que ela derive de BaseMasterPage. Porque BaseMasterPage precisamos abstract substituir esses abstract membros aqui no Site.master. Adicione o override palavra-chave às definições de método e propriedade. Atualize também o código que aciona o PricesDoubled evento no DoublePrice manipulador de eventos do Click Botão com uma chamada para o método da OnPricesDoubled classe base.

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

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);
    } 
}

Também precisamos atualizar Alternate.mastera classe code-behind para derivar BaseMasterPage e substituir os dois abstract membros. Mas como Alternate.master não contém um GridView que lista os produtos mais recentes nem um Label que exibe uma mensagem depois que um novo produto é adicionado ao banco de dados, esses métodos não precisam fazer nada.

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

Referenciando a classe de página mestra base

Agora que concluímos a BaseMasterPage classe e temos nossas duas páginas master estendendo-a, nossa etapa final é atualizar as ~/Admin/AddProduct.aspx páginas e ~/Admin/Products.aspx para fazer referência a esse tipo comum. Comece alterando a @MasterType diretiva em ambas as páginas de:

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

Para:

<%@ MasterType TypeName="BaseMasterPage" %>

Em vez de referenciar um caminho de arquivo, a @MasterType propriedade agora faz referência ao tipo base (BaseMasterPage). Consequentemente, a propriedade fortemente tipada Master usada nas classes code-behind de ambas as páginas agora é do tipo BaseMasterPage (em vez do tipo Site). Com essa alteração em vigor, reveja ~/Admin/Products.aspx. Anteriormente, isso resultava em um erro de conversão porque a página estava configurada para usar a Alternate.master página master, mas a @MasterType diretiva fazia referência ao Site.master arquivo. Mas agora a página é renderizada sem erros. Isso ocorre porque a Alternate.master página master pode ser convertida em um objeto do tipo BaseMasterPage (já que a estende).

Há uma pequena alteração que precisa ser feita em ~/Admin/AddProduct.aspx. O manipulador de eventos do ItemInserted controle DetailsView usa a propriedade fortemente tipada Master e a propriedade de tipo Page.Master flexível. Corrigimos a referência fortemente tipada quando atualizamos a @MasterType diretiva , mas ainda precisamos atualizar a referência de tipo flexível. Substitua a seguinte linha de código:

Site myMasterPage = Page.Master as Site;

Com o seguinte, que é convertido Page.Master no tipo base:

BaseMasterPage myMasterPage = Page.Master as BaseMasterPage;

Etapa 4: Determinando qual página mestra associar às páginas de conteúdo

Atualmente, nossa BasePage classe define todas as propriedades de MasterPageFile páginas de conteúdo como um valor embutido em código no estágio PreInit do ciclo de vida da página. Podemos atualizar esse código para basear a página master em algum fator externo. Talvez a página master a ser carregada dependa das preferências do usuário conectado no momento. Nesse caso, precisamos escrever código no OnPreInit método em BasePage que pesquisa as preferências de página de master do usuário que está visitando no momento.

Vamos criar uma página da Web que permita que o usuário escolha qual master página usar - Site.master ou Alternate.master - e salvar essa opção em uma variável de sessão. Comece criando uma nova página da Web no diretório raiz chamado ChooseMasterPage.aspx. Ao criar essa página (ou outras páginas de conteúdo a partir de agora), você não precisa associá-la a uma página master porque a página master é definida programaticamente em BasePage. No entanto, se você não associar a nova página a uma página master, a marcação declarativa padrão da nova página conterá um Web Form e outro conteúdo fornecido pela página master. Você precisará substituir manualmente essa marcação pelos controles de Conteúdo apropriados. Por esse motivo, acho mais fácil associar a nova página de ASP.NET a uma página master.

Observação

Como Site.master e Alternate.master têm o mesmo conjunto de controles ContentPlaceHolder, não importa qual master página você escolher ao criar a nova página de conteúdo. Para consistência, sugiro 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 exibir a imagem em tamanho real)

Atualize o Web.sitemap arquivo para incluir uma entrada para esta lição. Adicione a seguinte marcação abaixo de <siteMapNode> para a lição Páginas Mestras e 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 ela seja derivada de (em vez System.Web.UI.Pagede BasePage ). Em seguida, adicione um controle DropDownList à página, defina sua ID propriedade MasterPageChoicecomo e adicione dois ListItems com os Text valores de "~/Site.master" e "~/Alternate.master".

Adicione um controle web de botão à página e defina suas ID propriedades e Text como SaveLayout e "Salvar Escolha de Layout", respectivamente. Neste ponto, a marcação declarativa da 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 exibir a opção de página master do usuário selecionada no momento. Crie um Page_Load manipulador de eventos e adicione o seguinte código:

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

O código acima é executado somente na primeira visita à página (e não em postbacks subsequentes). Primeiro, ele verifica se a variável MyMasterPage Session existe. Se isso acontecer, ele tentará encontrar o ListItem correspondente no MasterPageChoice DropDownList. Se um ListItem correspondente for encontrado, sua Selected propriedade será definida truecomo .

Também precisamos de código que salve a escolha do usuário na MyMasterPage variável De sessão. Crie um manipulador de eventos para o SaveLayout evento do Click Botão e adicione o seguinte código:

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

Observação

No momento em que o Click manipulador de eventos é executado no postback, a página master já foi selecionada. Portanto, a seleção de lista suspensa do usuário não estará em vigor até a próxima visita à página. O Response.Redirect força o navegador a solicitar ChooseMasterPage.aspxnovamente .

Com a ChooseMasterPage.aspx página concluída, nossa tarefa final é atribuir BasePage a MasterPageFile propriedade com base no valor da MyMasterPage variável Session. Se a variável Session não estiver definida, o padrão Site.masterserá BasePage .

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(); 
}

Observação

Movai o código que atribui a Page propriedade do MasterPageFile objeto para fora do OnPreInit manipulador de eventos e para dois métodos separados. Esse primeiro método, SetMasterPageFile, atribui a MasterPageFile propriedade ao valor retornado pelo segundo método, GetMasterPageFileFromSession. Fiz o SetMasterPageFile método virtual para que classes futuras que se estendem BasePage possam, opcionalmente, substituí-lo para implementar a lógica personalizada, se necessário. Veremos um exemplo de substituição BasePageda propriedade de SetMasterPageFile no próximo tutorial.

Com esse código em vigor, visite a ChooseMasterPage.aspx página. Inicialmente, a Site.master página master está selecionada (consulte a Figura 6), mas o usuário pode escolher uma página de master diferente na lista suspensa.

As Páginas de Conteúdo são exibidas usando o site. Página Mestra do master

Figura 06: As páginas de conteúdo são exibidas usando a Site.master página mestra (clique para exibir a imagem em tamanho real)

As páginas de conteúdo agora são exibidas usando o alternativo. Página Mestra do master

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

Resumo

Quando uma página de conteúdo é visitada, seus controles de conteúdo são fundidos com os controles ContentPlaceHolder da página master. A página master da página de conteúdo é indicada pela Page propriedade da MasterPageFile classe , que é atribuída ao @Page atributo da MasterPageFile diretiva durante o estágio inicialização. Como este tutorial mostrou, podemos atribuir um valor à MasterPageFile propriedade desde que façamos isso antes do final do estágio PreInit. Ser capaz de especificar programaticamente a página master abre a porta para cenários mais avançados, como associar dinamicamente uma página de conteúdo a uma página master com base em fatores externos.

Programação feliz!

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 do ASP/ASP.NET e fundador da 4GuysFromRolla.com, trabalha com tecnologias da Microsoft Web desde 1998. Scott trabalha como consultor independente, treinador e escritor. Seu último livro é Sams Teach Yourself ASP.NET 3.5 em 24 Horas. Scott pode ser contatado em mitchell@4GuysFromRolla.com ou através de seu blog em http://ScottOnWriting.NET.

Agradecimentos Especiais

Esta série de tutoriais foi revisada por muitos revisores úteis. O revisor principal deste tutorial foi Suchi Banerjee. Interessado em revisar meus próximos artigos do MSDN? Nesse caso, deixe-me uma linha em mitchell@4GuysFromRolla.com