Compartilhar via


Reutilizar a interface do usuário usando páginas mestras e parciais

pela Microsoft

Baixar PDF

Esta é a etapa 7 de um tutorial gratuito de aplicativo "NerdDinner" que explica como criar um aplicativo Web pequeno, mas completo, usando ASP.NET MVC 1.

A etapa 7 analisa como podemos aplicar o "Princípio DRY" em nossos modelos de exibição para eliminar a duplicação de código, usando modelos de exibição parciais e páginas de master.

Se você estiver usando ASP.NET MVC 3, recomendamos que siga os tutoriais Introdução With MVC 3 ou MVC Music Store.

NerdDinner Etapa 7: Parciais e Páginas Mestras

Uma das filosofias de design ASP.NET o MVC abraça é o princípio "Não Se Repita" (comumente chamado de "DRY"). Um design DRY ajuda a eliminar a duplicação de código e lógica, o que, em última análise, torna os aplicativos mais rápidos de compilar e mais fáceis de manter.

Já vimos o princípio DRY aplicado em vários de nossos cenários NerdDinner. Alguns exemplos: nossa lógica de validação é implementada em nossa camada de modelo, o que permite que ela seja imposta em cenários de edição e criação em nosso controlador; estamos usando novamente o modelo de exibição "NotFound" nos métodos de ação Editar, Detalhes e Excluir; estamos usando um padrão de nomenclatura de convenção com nossos modelos de exibição, o que elimina a necessidade de especificar explicitamente o nome quando chamamos o método auxiliar View() ; e estamos reutilizar a classe DinnerFormViewModel para cenários de ação Editar e Criar.

Agora vamos examinar como podemos aplicar o "Princípio DRY" em nossos modelos de exibição para eliminar também a duplicação de código.

Visitando novamente nossos modelos editar e criar exibição

Atualmente, estamos usando dois modelos de exibição diferentes – "Edit.aspx" e "Create.aspx" – para exibir nossa interface do usuário do formulário dinner. Uma comparação visual rápida deles destaca como eles são semelhantes. Veja abaixo a aparência do formulário de criação:

Captura de tela da página Meu Aplicativo M V C. O formulário Hospedar um Jantar é mostrado.

E aqui está a aparência do nosso formulário "Editar":

Captura de tela da paage Meu Aplicativo M V C é mostrada. O formulário Editar é mostrado.

Não há muita diferença? Além do título e do texto do cabeçalho, o layout do formulário e os controles de entrada são idênticos.

Se abrirmos os modelos de exibição "Edit.aspx" e "Create.aspx", descobriremos que eles contêm layout de formulário idêntico e código de controle de entrada. Essa duplicação significa que acabamos tendo que fazer alterações duas vezes sempre que introduzimos ou alteramos uma nova propriedade Dinner - o que não é bom.

Usando modelos de exibição parcial

ASP.NET MVC dá suporte à capacidade de definir modelos de "exibição parcial" que podem ser usados para encapsular a lógica de renderização de exibição para uma sub-parte de uma página. As "parciais" fornecem uma maneira útil de definir a lógica de renderização de exibição uma vez e, em seguida, reutilizá-la em vários locais em um aplicativo.

Para ajudar a "DRY-up" nossa duplicação de modelo de exibição Edit.aspx e Create.aspx, podemos criar um modelo de exibição parcial chamado "DinnerForm.ascx" que encapsula o layout do formulário e os elementos de entrada comuns a ambos. Faremos isso clicando com o botão direito do mouse em nosso diretório /Views/Dinners e escolhendo o comando de menu "Add-View>":

Captura de tela da árvore de navegação Gerenciador de Soluções. O jantar está realçado. Adicionar e Exibir estão selecionados. A exibição está realçada.

Isso exibirá a caixa de diálogo "Adicionar Exibição". Nomearemos o novo modo de exibição que desejamos criar "DinnerForm", marque a caixa de seleção "Criar uma exibição parcial" na caixa de diálogo e indique que passaremos uma classe DinnerFormViewModel:

Captura de tela da caixa de diálogo Adicionar Exibição. Criar uma exibição parcial é selecionado e realçado.

Quando clicarmos no botão "Adicionar", o Visual Studio criará um novo modelo de exibição "DinnerForm.ascx" para nós no diretório "\Views\Dinners".

Em seguida, podemos copiar/colar o layout de formulário duplicado/código de controle de entrada de nossos modelos de exibição Edit.aspx/ Create.aspx em nosso novo modelo de exibição parcial "DinnerForm.ascx":

<%= Html.ValidationSummary("Please correct the errors and try again.") %>

<% using (Html.BeginForm()) { %>

    <fieldset>
        <p>
            <label for="Title">Dinner Title:</label>
            <%= Html.TextBox("Title", Model.Dinner.Title) %>
            <%=Html.ValidationMessage("Title", "*") %>
        </p>
        <p>
            <label for="EventDate">Event Date:</label>
            <%= Html.TextBox("EventDate", Model.Dinner.EventDate) %>
            <%= Html.ValidationMessage("EventDate", "*") %>
        </p>
        <p>
            <label for="Description">Description:</label>
            <%= Html.TextArea("Description", Model.Dinner.Description) %>
            <%= Html.ValidationMessage("Description", "*") %>
        </p>
        <p>
            <label for="Address">Address:</label>
            <%= Html.TextBox("Address", Model.Dinner.Address) %>
            <%= Html.ValidationMessage("Address", "*") %>
        </p>
        <p>
            <label for="Country">Country:</label>
            <%= Html.DropDownList("Country", Model.Countries) %>                
            <%= Html.ValidationMessage("Country", "*") %>
        </p>
        <p>
            <label for="ContactPhone">Contact Phone #:</label>
            <%= Html.TextBox("ContactPhone", Model.Dinner.ContactPhone) %>
            <%= Html.ValidationMessage("ContactPhone", "*") %>
        </p>
            
        <p>
            <input type="submit" value="Save"/>
        </p>
    </fieldset>
    
<% } %>

Em seguida, podemos atualizar nossos modelos de exibição Editar e Criar para chamar o modelo parcial DinnerForm e eliminar a duplicação do formulário. Podemos fazer isso chamando Html.RenderPartial("DinnerForm") em nossos modelos de exibição:

Create.aspx
<asp:Content ID="Title" ContentPlaceHolderID="TitleContent" runat="server">
    Host a Dinner
</asp:Content>

<asp:Content ID="Create" ContentPlaceHolderID="MainContent" runat="server">

    <h2>Host a Dinner</h2>

    <% Html.RenderPartial("DinnerForm"); %>
    
</asp:Content>
Edit.aspx
<asp:Content ID="Title" ContentPlaceHolderID="TitleContent" runat="server">
    Edit: <%=Html.Encode(Model.Dinner.Title) %>
</asp:Content>

<asp:Content ID="Edit" ContentPlaceHolderID="MainContent" runat="server">

    <h2>Edit Dinner</h2>

    <% Html.RenderPartial("DinnerForm"); %>

</asp:Content>

Você pode qualificar explicitamente o caminho do modelo parcial desejado ao chamar Html.RenderPartial (por exemplo: ~Views/Dinners/DinnerForm.ascx"). Em nosso código acima, porém, estamos aproveitando o padrão de nomenclatura baseado em convenção em ASP.NET MVC e apenas especificando "DinnerForm" como o nome da parcial a ser renderizada. Quando fizermos isso ASP.NET o MVC ficará em primeiro lugar no diretório de exibições baseado em convenção (para DinnersController, isso seria /Views/Dinners). Se ele não encontrar o modelo parcial lá, ele o procurará no diretório /Views/Shared.

Quando Html.RenderPartial() for chamado apenas com o nome da exibição parcial, ASP.NET MVC passará para a exibição parcial os mesmos objetos de dicionário Model e ViewData usados pelo modelo de exibição de chamada. Como alternativa, há versões sobrecarregadas de Html.RenderPartial() que permitem que você passe um objeto Modelo alternativo e/ou dicionário ViewData para a exibição parcial a ser usada. Isso é útil para cenários em que você só deseja passar um subconjunto do Model/ViewModel completo.

Tópico Lateral: Por que <% %> em vez de <%= %>?
Uma das coisas sutis que você pode ter notado com o código acima é que estamos usando um <bloco % %> em vez de um <bloco %= %> ao chamar Html.RenderPartial(). <%= %> de blocos no ASP.NET indicam que um desenvolvedor deseja renderizar um valor especificado (por exemplo: <%= "Olá" %> renderizaria "Olá"). <% de> blocos, em vez disso, indicam que o desenvolvedor deseja executar o código e que qualquer saída renderizada dentro deles deve ser feita explicitamente (por exemplo: <% Response.Write("Hello") %>. O motivo pelo qual estamos usando um <bloco % %> com nosso código Html.RenderPartial acima é porque o método Html.RenderPartial() não retorna uma cadeia de caracteres e, em vez disso, gera o conteúdo diretamente para o fluxo de saída do modelo de exibição de chamada. Ele faz isso por motivos de eficiência de desempenho e, ao fazê-lo, evita a necessidade de criar um objeto de cadeia de caracteres temporário (potencialmente muito grande). Isso reduz o uso de memória e melhora a taxa de transferência geral do aplicativo. Um erro comum ao usar Html.RenderPartial() é esquecer de adicionar um ponto e vírgula no final da chamada quando ele estiver dentro de um <bloco %> . Por exemplo, esse código causará um erro do compilador: <% Html.RenderPartial("DinnerForm") %> Em vez disso, você precisará escrever: <% Html.RenderPartial("DinnerForm"); %> Isso ocorre porque <% dos> blocos são instruções de código autossuficientes e, ao usar instruções de código C#, é necessário terminar com dois-pontos.

Usando modelos de exibição parcial para esclarecer código

Criamos o modelo de exibição parcial "DinnerForm" para evitar a duplicação da lógica de renderização de exibição em vários locais. Esse é o motivo mais comum para criar modelos de exibição parcial.

Às vezes, ainda faz sentido criar exibições parciais mesmo quando elas estão sendo chamadas apenas em um único lugar. Modelos de exibição muito complicados geralmente podem se tornar muito mais fáceis de ler quando sua lógica de renderização de exibição é extraída e particionada em um ou mais modelos parciais bem nomeados.

Por exemplo, considere o snippet de código abaixo do Site. master arquivo em nosso projeto (que veremos em breve). O código é relativamente direto para leitura – em parte porque a lógica para exibir um link de logoff/logoff no canto superior direito da tela é encapsulada dentro da parcial "LogOnUserControl":

<div id="header">
    <div id="title">
        <h1>My MVC Application</h1>
    </div>
      
    <div id="logindisplay">
        <% Html.RenderPartial("LogOnUserControl"); %>
    </div> 
    
    <div id="menucontainer">
    
        <ul id="menu">              
            <li><%=Html.ActionLink("Home", "Index", "Home")%></li>
            <li><%=Html.ActionLink("About", "About", "Home")%></li>
        </ul>
    </div>
</div>

Sempre que você se encontrar confuso tentando entender a marcação html/código em um modelo de exibição, considere se não seria mais claro se algumas delas fossem extraídas e refatoradas em exibições parciais bem nomeadas.

Páginas mestras

Além de dar suporte a exibições parciais, ASP.NET MVC também dá suporte à capacidade de criar modelos de "página master" que podem ser usados para definir o layout comum e html de nível superior de um site. Os controles de espaço reservado de conteúdo podem ser adicionados à página master para identificar regiões substituíveis que podem ser substituídas ou "preenchidas" por exibições. Isso fornece uma maneira muito eficaz (e DRY) de aplicar um layout comum em um aplicativo.

Por padrão, novos projetos de ASP.NET MVC têm um modelo de página master adicionado automaticamente a eles. Esta página master é chamada de "Site.master" e reside na pasta \Views\Shared\:

Captura de tela da árvore de navegação Nerd Dinner. O Site Mestre está realçado e selecionado.

O Site padrão. master arquivo se parece com o seguinte. Ele define o html externo do site, juntamente com um menu para navegação na parte superior. Ele contém dois controles de espaço reservado de conteúdo substituíveis: um para o título e outro para onde o conteúdo primário de uma página deve ser substituído:

<%@ Master Language="C#" Inherits="System.Web.Mvc.ViewMasterPage"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">

<head runat="server">
    <title>
       <asp:ContentPlaceHolder ID="TitleContent" runat="server" />
    </title>
   <link href="../../Content/Site.css" rel="stylesheet" type="text/css" />
</head>

<body>
    <div class="page">

        <div id="header">
            <div id="title">
                <h1>My MVC Application</h1>
            </div>
              
            <div id="logindisplay">
                <% Html.RenderPartial("LogOnUserControl"); %>
            </div> 
            
            <div id="menucontainer">

                <ul id="menu">              
                    <li><%=Html.ActionLink("Home", "Index", "Home")%></li>
                    <li><%=Html.ActionLink("About", "About", "Home")%></li>
                </ul>
            
            </div>
        </div>

        <div id="main">
            <asp:ContentPlaceHolder ID="MainContent" runat="server" />
        </div>
    </div>
</body>
</html>

Todos os modelos de exibição que criamos para nosso aplicativo NerdDinner ("List", "Details", "Edit", "Create", "NotFound", etc) foram baseados neste Site. master modelo. Isso é indicado por meio do atributo "MasterPageFile" que foi adicionado por padrão à diretiva % superior <@ Page %> quando criamos nossas exibições usando a caixa de diálogo "Adicionar Exibição":

<%@ Page Inherits="System.Web.Mvc.ViewPage<NerdDinner.Controllers.DinnerViewModel>" MasterPageFile="~/Views/Shared/Site.Master" %>

O que isso significa é que podemos alterar o Site. master conteúdo e as alterações serão aplicadas e usadas automaticamente quando renderizarmos qualquer um dos nossos modelos de exibição.

Vamos atualizar nosso Site. master seção de cabeçalho para que o cabeçalho do nosso aplicativo seja "NerdDinner" em vez de "Meu Aplicativo MVC". Vamos também atualizar nosso menu de navegação para que a primeira guia seja "Localizar um Jantar" (manipulada pelo método de ação Índice() do HomeController) e vamos adicionar uma nova guia chamada "Hospedar um Jantar" (manipulada pelo método de ação Create() do DinnersController):

<div id="header">

    <div id="title">
        <h1>NerdDinner</h1>
    </div>

    <div id="logindisplay">
        <% Html.RenderPartial("LoginStatus"); %>
    </div> 
    
    <div id="menucontainer">
        <ul id="menu">      
           <li><%=Html.ActionLink("Find Dinner", "Index", "Home")%></li>
           <li><%=Html.ActionLink("Host Dinner", "Create", "Dinners")%></li>
           <li><%=Html.ActionLink("About", "About", "Home")%></li>   
        </ul>
    </div>
</div>

Quando salvamos o Site. master arquivo e atualizar nosso navegador, veremos nossas alterações de cabeçalho aparecerem em todos os modos de exibição em nosso aplicativo. Por exemplo:

Captura de tela da página da lista Jantares Futuros do Nerd.

E com a URL /Dinners/Edit/[id] :

Captura de tela da página do formulário Editar Jantar Nerd é mostrada.

Próxima etapa

As parciais e master páginas fornecem opções muito flexíveis que permitem organizar as exibições de maneira limpa. Você descobrirá que eles ajudam você a evitar a duplicação de conteúdo/código de exibição e facilitar a leitura e a manutenção dos modelos de exibição.

Agora vamos revisitar o cenário de listagem que criamos anteriormente e habilitar o suporte escalonável à paginação.