Skip to content

11. A aplicação [SimuPaie] – versão 7 – ASP.NET / multi-vista / multi-página


Leitura recomendada: referência [1], Desenvolvimento Web com ASP.NET 1.1, secção: Exemplos


Estamos agora a analisar uma versão que é funcionalmente idêntica à aplicação ASP.NET de três camadas [pam-v4-3tier-nhibernate-multivues-monopage] discutida anteriormente, mas estamos a modificar a sua arquitetura da seguinte forma: enquanto na versão anterior as vistas eram implementadas por uma única página ASPX, aqui serão implementadas por três páginas ASPX.

A arquitetura da aplicação anterior era a seguinte:

Aqui temos uma arquitetura MVC (Modelo–Visão–Controlador):

  • [Default.aspx.cs] contém o código do controlador. A página [Default.aspx] é o único ponto de contacto do cliente. Ela trata de todos os pedidos do cliente.
  • [Saisies, Simulation, Simulations, ...] são as vistas. Estas vistas são implementadas aqui utilizando componentes [View] na página [Default.aspx].

A arquitetura da nova versão será a seguinte:

  • apenas a camada [web] muda
  • as vistas (o que é apresentado ao utilizador) permanecem inalteradas.
  • O código do controlador, que na versão anterior estava inteiramente em [Default.aspx.cs], está agora distribuído por várias páginas:
    • [MasterPage.master]: uma página que encapsula elementos comuns às diferentes visualizações: o banner superior com as suas opções de menu
    • [Formulaire.aspx]: a página que apresenta o formulário de simulação e gere as ações que ocorrem neste formulário
    • [Simulations.aspx]: a página que apresenta a lista de simulações e gere as ações que ocorrem nesta página
    • [Errors.aspx]: a página apresentada quando ocorre um erro de inicialização da aplicação. Não são possíveis quaisquer ações nesta página.

Isto pode ser considerado uma arquitetura MVC com vários controladores, enquanto a arquitetura da versão anterior era uma arquitetura MVC com um único controlador.

O processamento de um pedido do cliente segue estes passos:

  1. O cliente faz uma solicitação à aplicação. A solicitação é direcionada para uma das duas páginas [Formulaire.aspx, Simulations.aspx].
  2. A página solicitada processa esta solicitação. Para tal, pode necessitar da assistência da camada [business], que por sua vez pode necessitar da camada [DAO] caso seja necessário trocar dados com a base de dados. A aplicação recebe uma resposta da camada [business].
  3. Com base nessa resposta, seleciona (3) a vista (= a resposta) a enviar ao cliente, fornecendo-lhe (4) as informações (o modelo) de que necessita.
  4. A resposta é enviada ao cliente (5)

11.1. As vistas da aplicação

As diferentes visualizações apresentadas ao utilizador são as seguintes:

  • - a vista [VueSaisies], que exibe o formulário de simulação

Image

  • - a vista [VueSimulation], utilizada para apresentar os resultados detalhados da simulação:

Image

  • - a vista [SimulationView], que lista as simulações realizadas pelo cliente

Image

  • - a vista [EmptySimulationsView], que indica que o cliente não tem simulações ou já não tem mais simulações:

Image

  • a vista [ErrorView], que indica um erro de inicialização da aplicação:

Image

11.2. Gerar vistas num contexto de controladores múltiplos

Na versão anterior, todas as vistas eram geradas a partir da página única [Default.aspx]. Esta página continha dois componentes [MultiView], e as vistas consistiam numa combinação de um ou dois componentes [View] pertencentes a estes dois componentes [MultiView].

Embora eficaz quando há poucas vistas, esta arquitetura atinge os seus limites assim que o número de componentes que formam as várias vistas se torna elevado: de facto, com cada pedido feito à página única [Default.aspx], todos os seus componentes são instanciados, mesmo que apenas alguns deles sejam utilizados para gerar a resposta ao utilizador. É assim realizado trabalho desnecessário com cada novo pedido, o que se torna um estrangulamento quando o número total de componentes na página é elevado.

Uma solução consiste em distribuir as vistas por diferentes páginas. É isso que estamos a fazer aqui. Vamos examinar dois casos diferentes de geração de vistas:

  1. a solicitação é feita à página P1, e esta gera a resposta
  2. a solicitação é feita à página P1, e esta página pede à página P2 para gerar a resposta

11.2.1. Caso 1: uma página controlador/visualização

No Caso 1, voltamos à arquitetura de controlador único da versão anterior, em que a página [Default.aspx] é a página P1:

  1. o cliente faz uma solicitação à página P1 (1)
  2. A página P1 processa esta solicitação. Para tal, pode necessitar da assistência da camada [business] (2), que por sua vez pode necessitar da camada [DAO] caso seja necessário trocar dados com a base de dados. A aplicação recebe uma resposta da camada [business].
  3. Com base nessa resposta, seleciona (3) a vista (= a resposta) a enviar ao cliente, fornecendo-lhe (4) as informações (o modelo) de que necessita. Isto envolve a seleção dos componentes [Panel] ou [View] a apresentar na página P1 e a inicialização dos componentes que estes contêm.
  4. A resposta é enviada ao cliente (5)

Aqui estão dois exemplos retirados da aplicação em estudo:

[Página Formulaire.aspx]

  • em [1]: após solicitar a página [Formulaire.aspx], o utilizador solicita uma simulação
  • em [2]: a página [Formulaire.aspx] processou este pedido e gerou a resposta exibindo um componente [View] que não tinha sido exibido em [1]

[página Simulations.aspx]

  • em [1]: após solicitar a página [Simulations.aspx], o utilizador pretende remover uma simulação
  • em [2]: a página [Simulations.aspx] processou este pedido e gerou a resposta, exibindo novamente a nova lista de simulações.

11.2.2. Caso 2: uma página com um único controlador, uma página controlador/visualização

O caso 2 pode abranger várias arquiteturas. Escolheremos a seguinte:

  1. o cliente faz uma solicitação à página P1 (1)
  2. A página P1 processa esta solicitação. Para tal, pode necessitar da assistência da camada [business] (2), que por sua vez pode necessitar da camada [DAO] caso seja necessário trocar dados com a base de dados. A aplicação recebe uma resposta da camada [business].
  3. Com base nisso, seleciona (3) a vista (= a resposta) a enviar ao cliente, fornecendo-lhe (4) as informações (o modelo) de que necessita. Neste caso, a vista a gerar deve ser criada por uma página diferente da P1 — especificamente, a página P2. Para realizar as operações (3) e (4), a página P1 tem duas opções:
    • transferir a execução para a página P2 utilizando a operação [Server.Transfer("P2.aspx")]. Neste caso, pode colocar o modelo destinado à página P2 no contexto da solicitação [Context.Items["key"]=value] ou na sessão do utilizador [Session.["key"]=value]. A página P2 será então instanciada e, quando o seu evento Load for processado, por exemplo, poderá recuperar as informações passadas pela página P1 utilizando as operações [value=(Type)Context.Items["key"] ou [value=(Type)Session["key"], conforme apropriado, onde Type é o tipo do valor associado à chave. A transmissão de valores através do Context é mais adequada se não for necessário que os valores do modelo sejam retidos para um futuro pedido do cliente.
    • Peça ao cliente para redirecionar para a página P2 utilizando a operação [Response.Redirect("P2.aspx")]. Neste caso, a página P1 colocará o modelo destinado à página P2 na sessão, uma vez que o contexto da solicitação é limpo no final de cada solicitação. No entanto, aqui, o redirecionamento fará com que a primeira solicitação do cliente para P1 termine e acione uma segunda solicitação do mesmo cliente, desta vez para P2. Há duas solicitações sucessivas. Sabemos que a sessão é uma forma de preservar a "memória" entre as solicitações. Existem outras soluções além da sessão.
  4. Independentemente de como a P2 assume o controlo, voltamos então ao caso 1: a P2 recebeu uma solicitação que irá processar (5) e irá gerar a resposta por si própria (6, 7). Também podemos imaginar que, após processar a solicitação, a página P2 irá passar o controlo para a página P3, e assim por diante.

Eis um exemplo retirado da aplicação em estudo:

  • em [1]: o utilizador que solicitou a página [Formulaire.aspx] pede para ver a lista de simulações
  • em [2]: a página [Formulaire.aspx] processa este pedido e redireciona o cliente para a página [Simulations.aspx]. É esta última que fornece a resposta ao utilizador. Em vez de pedir ao cliente para redirecionar, a página [Formulaire.aspx] poderia ter encaminhado o pedido do cliente para a página [Simulations.aspx]. Neste caso, em [2], teríamos visto o mesmo URL que em [1]. Na verdade, um navegador exibe sempre o último URL solicitado:
    • A ação solicitada em [1] destina-se à página [Formulaire.aspx]. O navegador envia uma solicitação POST para esta página.
    • Se a página [Formulaire.aspx] processar a solicitação e, em seguida, a encaminhar via [Server.Transfer("Simulations.aspx")] para a página [Simulations.aspx], permanecemos na mesma solicitação. O navegador exibirá então em [2] a URL de [Formulaire.aspx] para a qual o POST foi enviado.
    • Se a página [Formulaire.aspx] processar a solicitação e, em seguida, redirecioná-la via [Response.Redirect("Simulations.aspx")] para a página [Simulations.aspx], o navegador fará então uma segunda solicitação, uma solicitação GET para [Simulations.aspx]. O navegador exibirá então em [2] a URL de [Simulations.aspx] para a qual a solicitação GET foi enviada. É isso que a captura de ecrã [2] acima nos mostra.

11.3. O projeto do Visual Web Developer para a camada [web]

O projeto do Visual Web Developer para a camada [web] é o seguinte:

  • Em [1] encontramos:
    • o ficheiro de configuração da aplicação [Web.config] – que é idêntico ao da aplicação [pam-v4-3tier-nhibernate-multivues-monopage].
    • a página [Default.aspx] – redireciona simplesmente o cliente para a página [Formulaire.aspx]
    • a página [Formulaire.aspx], que apresenta o formulário de simulação ao utilizador e gere as ações relacionadas com este formulário
    • a página [Simulations.aspx], que apresenta a lista de simulações do utilizador e gere as ações relacionadas com esta página
    • A página [Errors.aspx], que apresenta ao utilizador uma página indicando um erro encontrado ao iniciar a aplicação web.
  • Em [2], vemos as referências do projeto.

Voltemos à arquitetura do novo projeto:

Em comparação com o projeto [pam-v4-3tier-nhibernate-multivues-monopage], apenas as vistas foram alteradas. É por isso que o novo projeto reutiliza alguns dos ficheiros desse projeto:

  • o ficheiro de configuração [Web.config]
  • as DLLs referenciadas [pam-dao-nhibernate, pam-metier-dao-nhibernate, Spring.Core, NHibernate]
  • a classe de aplicação global [Global.asax]
  • as pastas [images, resources, pam]

Para manter a consistência com o projeto atualmente em desenvolvimento, iremos garantir que o namespace para as vistas e a classe de aplicação global é [pam-v7]:

  

11.4. O código de apresentação da página

11.4.1. A página mestre [MasterPage.master]

As vistas da aplicação apresentadas na Secção 11.1 têm elementos comuns que podem ser agrupados numa Página Mestre, conhecida como Master Page no Visual Studio. Tomemos, por exemplo, as vistas [VueSaisies] e [VueSimulationsVides] abaixo, geradas respetivamente pelas páginas [Formulaire.aspx] e [Simulations.aspx]:

Estas duas vistas partilham o banner superior (Título e Opções de Menu). Isto aplica-se a todas as vistas que serão apresentadas ao utilizador: todas terão o mesmo banner superior. Para permitir que diferentes páginas partilhem o mesmo fragmento de apresentação, existem várias soluções, incluindo as seguintes:

  • Colocar este fragmento comum num controlo de utilizador. Esta era a técnica principal no ASP.NET 1.1
  • Colocar este fragmento comum numa página mestre. Esta técnica foi introduzida com o ASP.NET 2.0. É esta que estamos a utilizar aqui.

Para criar uma página mestre numa aplicação web, siga estes passos:

  • Clique com o botão direito do rato no projeto / Adicionar Novo Item / Página Mestre:

Ao adicionar uma Página Mestre, são adicionados três ficheiros à aplicação web por predefinição:

  • [MasterPage.master]: o código de layout da Página Mestre
  • [MasterPage.master.cs]: o código de controlo da Página Mestre
  • [MasterPage.Master.Designer.cs]: as declarações de componentes para a Página Mestre

O código gerado pelo Visual Studio em [MasterPage.master] é o seguinte:


<%@ Master Language="C#" AutoEventWireup="true" CodeBehind="MasterPage.master.cs" Inherits="pam_v7.MasterPage" %>
 
<!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 runat="server">
    <title>Untitled Page</title>
    <asp:ContentPlaceHolder id="head" runat="server">
    </asp:ContentPlaceHolder>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:ContentPlaceHolder id="ContentPlaceHolder1" runat="server">
 
        </asp:ContentPlaceHolder>
    </div>
    </form>
</body>
</html>
  • Linha 1: A tag <%@ Master ... %> é utilizada para definir a página como uma página mestre. O código de controlo da página estará no ficheiro especificado pelo atributo CodeBehind, e a página herdará da classe especificada pelo atributo Inherits.
  • Linhas 12–18: O formulário da página mestre
  • Linhas 14–16: Um contentor vazio que, na nossa aplicação, irá conter uma das páginas [Form.aspx, Simulations.aspx, Errors.aspx]. O cliente recebe sempre a mesma página em resposta — a página mestre — na qual o contentor [ContentPlaceHolder1] receberá um fluxo HTML fornecido por uma das páginas [Form.aspx, Simulations.aspx, Errors.aspx]. Assim, para alterar a aparência das páginas enviadas aos clientes, basta alterar a aparência da página mestre.
  • Linhas 8–9: um contentor vazio que permite às páginas «filhas» personalizar o cabeçalho <head>...</head>.

A representação visual (separador Design) deste código-fonte é apresentada em (1) abaixo. Além disso, pode adicionar quantos contentores desejar utilizando o componente [ContentPlaceHolder] (2) da barra de ferramentas [Standard].

O código de controlo gerado pelo Visual Studio em [MasterPage.master.cs] é o seguinte:


using System;
 
public partial class MasterPage : System.Web.UI.MasterPage
{
    protected void Page_Load(object sender, EventArgs e)
    {
 
    }
}
  • Linha 3: A classe referenciada pelo atributo [Inherits] da diretiva <%@ Master ... %> na página [MasterPage.master] deriva da classe [System.Web.UI.MasterPage]

Acima, vemos a presença do método Page_Load, que trata do evento Load da página mestre. A página mestre conterá outra página no seu interior. Em que ordem ocorrem os eventos Load das duas páginas? Esta é uma regra geral: o evento Load de um componente ocorre antes do seu contentor. Aqui, o evento Load da página incorporada na página mestre ocorrerá, portanto, antes do da própria página mestre.

Para gerar uma página no que utilize a página anterior [MasterPage.master] como sua página mestre, pode proceder da seguinte forma:

  • em [1]: clique com o botão direito do rato na página mestre e, em seguida, selecione [Adicionar Página de Conteúdo]
  • em [2]: é gerada uma página padrão, neste caso [WebForm1.aspx].

O código de apresentação para [WebForm1.aspx] é o seguinte:


<%@ Page Title="" Language="C#" MasterPageFile="~/MasterPage.Master" AutoEventWireup="true" CodeBehind="WebForm1.aspx.cs" Inherits="pam_v7.WebForm1" %>
<asp:Content ID="Content1" ContentPlaceHolderID="ContentPlaceHolder1" runat="server">
</asp:Content>
  • Linha 1: A diretiva Page e os seus atributos
    • MasterPageFile: especifica o ficheiro da página mestre para a página descrita pela diretiva. O símbolo ~ indica a pasta do projeto.
    • Os outros parâmetros são os padrão para uma página web ASP
  • Linhas 2–3: As tags <asp:Content> são ligadas uma a uma às diretivas <asp:ContentPlaceHolder> na página mestre através do atributo ContentPlaceHolderID. Os componentes colocados entre as linhas 2–3 acima serão, em tempo de execução, colocados no contentor ContentPlaceHolder1 na página mestre.

Ao renomear a página [WebForm1.aspx] gerada desta forma, podemos criar as várias páginas utilizando [MasterPage.master] como página mestre.

Para a nossa aplicação [SimuPaie], a aparência visual da página mestre será a seguinte:

N.º
Tipo
Nome
Função
A
Painel (rosa acima)
cabeçalho
cabeçalho da página
B
Painel (amarelo acima)
conteúdo
conteúdo da página
1
Botão de ligação
LinkButtonRunSimulation
solicita o cálculo da simulação
2
LinkButton
LinkButtonClearSimulation
limpa o formulário de entrada
3
LinkButton
LinkButtonViewSimulations
exibe a lista de simulações já realizadas
4
LinkButton
LinkButtonSimulationForm
volta ao formulário de entrada
5
LinkButton
LinkButtonSaveSimulation
guarda a simulação atual na lista de simulações
6
LinkButton
LinkButtonEndSession
encerra a sessão atual

O código-fonte correspondente é o seguinte:


<%@ Master Language="C#" AutoEventWireup="true" CodeBehind="MasterPage.master.cs" Inherits="pam_v7.MasterPage" %>
 
<!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>Application PAM</title>
</head>
<body background="ressources/standard.jpg">
  <form id="form1" runat="server">
  <asp:ScriptManager ID="ScriptManager1" runat="server" EnablePartialRendering="true" />
  <asp:UpdatePanel runat="server" ID="UpdatePanelPam" UpdateMode="Conditional">
    <ContentTemplate>
      <asp:Panel ID="entete" runat="server" BackColor="#FFE0C0">
        <table>
          <tr>
            <td>
              <h2>
                Simulateur de calcul de paie</h2>
            </td>
            <td>
              <label>
                &nbsp;&nbsp;&nbsp</label>
              <asp:UpdateProgress ID="UpdateProgress1" runat="server">
                <ProgressTemplate>
                  <img alt="" src="images/indicator.gif" />
                  <asp:Label ID="Label5" runat="server" BackColor="#FF8000"
                             EnableViewState="False" Text="Calcul en cours. Patientez ....">
                        </asp:Label>
                </ProgressTemplate>
              </asp:UpdateProgress>
            </td>
            <td>
              <asp:LinkButton ID="LinkButtonFaireSimulation" runat="server"
                         CausesValidation="False">| Faire la simulation<br />
                    </asp:LinkButton>
              <asp:LinkButton ID="LinkButtonEffacerSimulation" runat="server"
                         CausesValidation="False">| Effacer la simulation<br />
                    </asp:LinkButton>
              <asp:LinkButton ID="LinkButtonVoirSimulations" runat="server"
                     CausesValidation="False">| Voir les simulations<br />
                    </asp:LinkButton>
              <asp:LinkButton ID="LinkButtonFormulaireSimulation" runat="server"
                         CausesValidation="False">| Retour au formulaire de simulation<br />
                    </asp:LinkButton>
              <asp:LinkButton ID="LinkButtonEnregistrerSimulation" runat="server"
                         CausesValidation="False">| Enregistrer la simulation<br />
                    </asp:LinkButton>
              <asp:LinkButton ID="LinkButtonTerminerSession" runat="server"
                         CausesValidation="False">| Terminer la session<br />
                    </asp:LinkButton>
            </td>
          </tr>
        </table>
        <hr />
      </asp:Panel>
      <div>
        <asp:Panel ID="contenu" runat="server" BackColor="#FFFFC0">
          <asp:ContentPlaceHolder ID="ContentPlaceHolder1" runat="server">
          </asp:ContentPlaceHolder>
        </asp:Panel>
      </div>
    </ContentTemplate>
  </asp:UpdatePanel>
  </form>
</body>
</html>
  • Linha 1: Repare no nome da classe da página mestre: MasterPage
  • Linha 8: Defina uma imagem de fundo para a página.
  • Linhas 9–64: o formulário
  • Linha 10: O componente ScriptManager necessário para os efeitos Ajax
  • Linhas 11–63: o contentor AJAX
  • Linhas 12–62: o conteúdo com Ajax
  • linhas 13–55: o componente Panel [cabeçalho]
  • Linhas 57–60: o componente Panel [conteúdo]
  • Linhas 58–59: o componente [ContentPlaceHolder1], que irá conter a página encapsulada [Formulaire.aspx, Simulations.aspx, Erreurs.aspx]

Para construir esta página, podemos inserir no painel [header] o código ASPX da vista [HeaderView] da página [Default.aspx] da versão [pam-v4-3tier-nhibernate-multivues-monopage], descrita na secção 8.5.2.

11.4.2. A página [Formulaire.aspx]

Para gerar esta página, siga o método descrito na secção 11.4.1 e renomeie a página [WebForm1.aspx] gerada para [Form.aspx]. A aparência visual da página [Form.aspx] em construção será a seguinte:

A aparência visual da página [Formulaire.aspx] é composta por dois elementos:

  • [1] a página mestre com o seu contentor [ContentPlaceHolder1] (2)
  • [2] os componentes colocados no contentor [ContentPlaceHolder1]. Estes são idênticos aos da aplicação anterior.

O código-fonte desta página é o seguinte:


<%@ Page Language="C#" MasterPageFile="~/MasterPage.master" AutoEventWireup="true"
  CodeBehind="Formulaire.aspx.cs" Inherits="pam_v7.PageFormulaire" Title="Simulation de calcul de paie : formulaire" %>
 
<%@ MasterType VirtualPath="~/MasterPage.master" %>
<asp:Content ID="Content1" ContentPlaceHolderID="ContentPlaceHolder1" runat="Server">
  <div>
    <table>
      <tr>
        <td>
          Employé
        </td>
        <td>
          Heures travaillées
        </td>
        <td>
          Jours travaillés
        </td>
        <td>
        </td>
      </tr>
...
</asp:Content>
  • Linha 1: A diretiva Page com o seu atributo MasterPageFile
  • linha 4: a classe de controlo da página mestre pode expor campos e propriedades públicos. Estes são acessíveis às páginas encapsuladas utilizando a sintaxe Master.[campo] ou Master.[propriedade]. A propriedade Master da página refere-se à página mestre como uma instância do tipo [System.Web.UI.MasterPage]. Portanto, no nosso exemplo, deveríamos escrever (MasterPage)(Master).[campo] ou (MasterPage)(Master).[propriedade]. Esta conversão de tipo pode ser evitada inserindo a diretiva MasterType da linha 4 na página. O atributo VirtualPath desta diretiva especifica o ficheiro da página mestre. O compilador pode então reconhecer os campos públicos, propriedades e métodos expostos pela classe da página mestre, neste caso do tipo [MasterPage].
  • Linhas 5–22: o conteúdo a ser inserido no contentor [ContentPlaceHolder1] da página mestre.

Esta página pode ser criada definindo o seu conteúdo (linhas 6–21) como o da vista [VueSaisies] descrita na Secção 8.5.3 e o da vista [VueSimulation] descrita na Secção 8.5.4.

11.4.3. A página [Simulations.aspx]

Para gerar esta página, siga o método descrito na secção 11.4.1 e renomeie a página [WebForm1.aspx] resultante para [Simulations.aspx]. A aparência visual da página [Simulations.aspx] atualmente em construção é a seguinte:

A aparência visual da página [Simulations.aspx] consiste em dois elementos:

  • [1] a página mestre com o seu contentor [ContentPlaceHolder1]
  • em [2] os componentes colocados no contentor [ContentPlaceHolder1]. Estes são idênticos aos da aplicação anterior.

O código-fonte desta página é o seguinte:


<%@ Page Language="C#" MasterPageFile="~/MasterPage.master" AutoEventWireup="true"
  CodeBehind="Simulations.aspx.cs" Inherits="pam_v7.PageSimulations" Title="Pam : liste des simulations" %>
 
<%@ MasterType VirtualPath="~/MasterPage.master" %>
<asp:Content ID="Content1" ContentPlaceHolderID="ContentPlaceHolder1" runat="Server">
  <asp:MultiView ID="MultiView1" runat="server">
    <asp:View ID="View1" runat="server">
      <h2>
        Liste de vos simulations</h2>
      <p>
        <asp:GridView ID="GridViewSimulations" runat="server" ...>
...
        </asp:GridView>
      </p>
    </asp:View>
    <asp:View ID="View2" runat="server">
      <h2>
        La liste de vos simulations est vide</h2>
    </asp:View>
  </asp:MultiView><br />
</asp:Content>

Podemos criar esta página definindo o seu conteúdo (linhas 5–21) como o da vista [VueSimulations] descrita na secção 8.5.5 e o da vista [VueSimulationsVides] descrita na secção 8.5.6.

11.4.4. A página [Errors.aspx]

Para gerar esta página, siga o método descrito na secção 11.4.1 e renomeie a página [WebForm1.aspx] resultante para [Errors.aspx]. A aparência visual da página [Errors.aspx] atualmente em construção é a seguinte:

A aparência visual da página [Errors.aspx] consiste em dois elementos:

  • [1] a página mestre com o seu contentor [ContentPlaceHolder1]
  • [2] os componentes colocados no contentor [ContentPlaceHolder1]. Estes são idênticos aos da aplicação anterior.

O código-fonte desta página é o seguinte:


<%@ Page Language="C#" MasterPageFile="~/MasterPage.master" AutoEventWireup="true"
  CodeBehind="Erreurs.aspx.cs" Inherits="pam_v7.PageErreurs" Title="Pam : erreurs" %>
 
<%@ MasterType VirtualPath="~/MasterPage.master" %>
<asp:Content ID="Content1" ContentPlaceHolderID="ContentPlaceHolder1" Runat="Server">
        <h3>Les erreurs suivantes se sont produites au démarrage de l'application</h3>
        <ul>
            <asp:Repeater id="rptErreurs" runat="server">
                <ItemTemplate>
                    <li>
                        <%# Container.DataItem %>
                    </li>
                </ItemTemplate>
            </asp:Repeater>
        </ul>
</asp:Content>

11.5. Código de controlo da página

11.5.1. Visão geral

Voltemos à arquitetura da aplicação:

  • [Global] é o objeto [HttpApplication] que inicializa (passo 0) a aplicação. Esta classe é idêntica à da versão anterior.
  • O código do controlador, que na versão anterior estava inteiramente em [Default.aspx.cs], está agora distribuído por várias páginas:
    • [MasterPage.master]: a página mestre para [Form.aspx, Simulations.aspx, Errors.aspx]. Contém o menu.
    • [Formulaire.aspx]: a página que apresenta o formulário de simulação e gere as ações realizadas neste formulário
    • [Simulations.aspx]: a página que apresenta a lista de simulações e gere as ações que ocorrem nesta página
    • [Errors.aspx]: a página apresentada quando ocorre um erro de inicialização da aplicação. Não são possíveis quaisquer ações nesta página.

O processamento de um pedido do cliente segue estes passos:

  1. O cliente faz uma solicitação à aplicação. Normalmente, faz-o numa das duas páginas [Form.aspx, Simulations.aspx], mas nada o impede de solicitar a página [Errors.aspx]. Este cenário deve ser tido em conta.
  2. A página solicitada processa esta solicitação (etapa 1). Para tal, pode necessitar da assistência da camada [business] (etapa 2), que por sua vez pode necessitar da camada [DAO] caso seja necessário trocar dados com a base de dados. A aplicação recebe uma resposta da camada [business].
  3. Com base nisso, seleciona (passo 3) a vista (= a resposta) a enviar ao cliente e fornece-lhe (passo 4) as informações (o modelo) de que necessita. Vimos três possibilidades para gerar esta resposta:
    • a página solicitada (D) é também a página (R) enviada em resposta. A construção do modelo de resposta (R) consiste então em atribuir a determinados componentes da página (D) os valores que devem ter na resposta.
    • A página solicitada (D) não é a página (R) enviada em resposta. A página (D) pode então:
      • Transferir o fluxo de execução para a página (R) utilizando a instrução Server.Transfer(" R "). O modelo pode então ser colocado no contexto utilizando Context.Items("key")=value ou, menos frequentemente, na sessão utilizando Session.Items("key")=value
      • Redirecionar o cliente para a página (R) utilizando a instrução Response.redirect(" R "). O modelo pode então ser colocado na sessão, mas não no contexto.
  4. A resposta é enviada ao cliente (passo 5)

Cada uma das páginas [MasterPage.master, Form.aspx, Simulations.aspx, Errors.aspx] responderá a um ou mais dos seguintes eventos:

  • Init: primeiro evento no ciclo de vida da página
  • Load: ocorre quando a página é carregada
  • Click: um clique num dos links do menu da página mestre

Processamos as páginas uma a seguir à outra, começando pela página mestre.

11.5.2. Código de controlo para a página [MasterPage.master]

11.5.2.1. Estrutura da classe

O código de controlo da página principal tem o seguinte esqueleto:


using System.Web.UI.WebControls;
 
namespace pam_v7
{
  public partial class MasterPage : System.Web.UI.MasterPage
  {
 
    // the menu 
    public LinkButton OptionFaireSimulation
    {
      get { return LinkButtonFaireSimulation; }
    }
...
 
    // set menu 
    public void SetMenu(bool boolFaireSimulation, bool boolEnregistrerSimulation, bool boolEffacerSimulation, bool boolFormulaireSimulation, bool boolVoirSimulations, bool boolTerminerSession)
    {
....
    }
 
    // managing the [End session] option 
    protected void LinkButtonTerminerSession_Click(object sender, System.EventArgs e)
    {
....
    }
 
    // init master page 
    protected void Page_Init(object sender, System.EventArgs e)
    {
....
      }
    }
  }
}
  • linha 5: a classe é denominada [MasterPage] e deriva da classe do sistema [System.Web.UI.MasterPage].
  • linhas 9–14: as 6 opções de menu são expostas como propriedades públicas da classe
  • linhas 16–19: o método público SetMenu permite que as páginas [Formulaire.aspx, Simulations.aspx, Erreurs.aspx] definam o menu da página mestre
  • linhas 22–25: o procedimento que trata do clique no link [LinkButtonTerminerSession]
  • Linhas 28–31: O procedimento que trata do evento Init da página mestre

11.5.2.2. Propriedades públicas da classe


using System.Web.UI.WebControls;
 
namespace pam_v7
{
  public partial class MasterPage : System.Web.UI.MasterPage
  {
 
    // the menu 
    public LinkButton OptionFaireSimulation
    {
      get { return LinkButtonFaireSimulation; }
    }
 
    public LinkButton OptionEffacerSimulation
    {
      get { return LinkButtonEffacerSimulation; }
    }
 
    public LinkButton OptionEnregistrerSimulation
    {
      get { return LinkButtonEnregistrerSimulation; }
    }
 
    public LinkButton OptionVoirSimulations
    {
      get { return LinkButtonVoirSimulations; }
    }
 
    public LinkButton OptionTerminerSession
    {
      get { return LinkButtonTerminerSession; }
    }
 
    public LinkButton OptionFormulaireSimulation
    {
      get { return LinkButtonFormulaireSimulation; }
    }
 
...
  }
}

Para compreender este código, é necessário recordar os componentes que constituem a página mestre:

N.º
Tipo
Nome
Função
A
Painel (rosa acima)
cabeçalho
cabeçalho da página
B
Painel (amarelo acima)
conteúdo
conteúdo da página
1
Botão de ligação
LinkButtonExecutarSimulação
Solicitar cálculo da simulação
2
Botão de ligação
LinkButtonLimparSimulação
limpa o formulário de entrada
3
LinkButton
LinkButtonViewSimulations
exibe a lista de simulações já realizadas
4
LinkButton
LinkButtonSimulationForm
volta ao formulário de entrada
5
LinkButton
LinkButtonSaveSimulation
guarda a simulação atual na lista de simulações
6
LinkButton
LinkButtonEndSession
encerra a sessão atual

Os componentes 1 a 6 não são acessíveis fora da página que os contém. As propriedades nas linhas 9 a 37 destinam-se a torná-los acessíveis a classes externas, neste caso as classes das outras páginas da aplicação.

11.5.2.3. O método SetMenu

O método público SetMenu permite que as páginas [Formulaire.aspx, Simulations.aspx, Erreurs.aspx] definam o menu da página mestre. O seu código é básico:


        // fixer le menu 
        public void SetMenu(bool boolFaireSimulation, bool boolEnregistrerSimulation, bool boolEffacerSimulation, bool boolFormulaireSimulation, bool boolVoirSimulations, bool boolTerminerSession)
        {
            // on fixe les options de menu 
            LinkButtonFaireSimulation.Visible = boolFaireSimulation;
            LinkButtonEnregistrerSimulation.Visible = boolEnregistrerSimulation;
            LinkButtonEffacerSimulation.Visible = boolEffacerSimulation;
            LinkButtonVoirSimulations.Visible = boolVoirSimulations;
            LinkButtonFormulaireSimulation.Visible = boolFormulaireSimulation;
            LinkButtonTerminerSession.Visible = boolTerminerSession;
}

11.5.2.4. Tratamento de eventos na página mestre

A página mestre irá tratar dois eventos:

  • o evento Init, que é o primeiro evento no ciclo de vida da página
  • o evento Click no link [LinkButtonTerminerSession]

A página mestre possui cinco outros links: [LinkButtonRunSimulation, LinkButtonSaveSimulation, LinkButtonClearSimulation, LinkButtonViewSimulations, LinkButtonSimulationForm]. A título de exemplo, vamos examinar o que precisa ser feito quando o link [LinkButtonRunSimulation] é clicado:

  1. verificar os dados introduzidos (horas, dias) na página [Form.aspx]
  2. calcular o salário
  3. exibir os resultados na página [Form.aspx]

Os passos 1 e 3 requerem acesso aos componentes na página [Form.aspx]. Não é esse o caso. Na verdade, a página mestre não tem conhecimento dos componentes nas páginas que podem ser inseridas no seu contentor [ContentPlaceHolder1]. No nosso exemplo, cabe à página [Formulaire.aspx] tratar o clique no link [LinkButtonFaireSimulation], uma vez que é a página que é apresentada quando este evento ocorre. Como pode ser notificada deste evento?

  • Uma vez que o link [LinkButtonFaireSimulation] não faz parte da página [Formulaire.aspx], não podemos escrever o procedimento habitual em [Formulaire.aspx]:

    private void LinkButtonFaireSimulation_Click(object sender, System.EventArgs e)
    {
...
}

Pode contornar o problema com o seguinte código em [Formulaire.aspx]:


using System.Collections.Generic;
...
 
namespace pam_v7
{
    public partial class Formulaire : System.Web.UI.Page
    {
// page loading 
    protected void Page_Load(object sender, System.EventArgs e)
    {
        // event manager
        Master.OptionFaireSimulation.Click += OptFaireSimulation_Click;
        Master.OptionEffacerSimulation.Click += OptEffacerSimulation_Click;
        Master.OptionVoirSimulations.Click += OptVoirSimulations_Click;
        Master.OptionEnregistrerSimulation.Click += OptEnregistrerSimulation_Click;
...
    }
 
    // payroll calculation 
    private void OptFaireSimulation_Click(object sender, System.EventArgs e)
    {
....
    }
 
    // delete simulation 
    private void OptEffacerSimulation_Click(object sender, System.EventArgs e)
    {
...
    }
 
    protected void OptVoirSimulations_Click(object sender, System.EventArgs e)
    {
...
    }
 
    protected void OptEnregistrerSimulation_Click(object sender, System.EventArgs e)
    {
...
    }
 }
}
  • linhas 12–15: Quando ocorre o evento Load da página [Formulaire.aspx], a classe [MasterPage] da página mestre foi instanciada. As suas propriedades públicas Optionxx estão acessíveis e são do tipo LinkButton, um componente que suporta o evento Click. Associamos os seguintes métodos a estes eventos Click:
    • OptFaireSimulation_Click para o evento Click no link LinkButtonFaireSimulation
    • OptEffacerSimulation_Click para o evento Click no link LinkButtonEffacerSimulation
    • OptVoirSimulations_Click para o evento Click no link LinkButtonVoirSimulations
    • OptEnregistrerSimulation_Click para o evento Click no link LinkButtonEnregistrerSimulation

O tratamento dos eventos de clique nos seis links do menu será distribuído da seguinte forma:

  • a página [Formulaire.aspx] irá tratar os links [LinkButtonRunSimulation, LinkButtonSaveSimulation, LinkButtonClearSimulation, LinkButtonViewSimulations]
  • a página [Simulations.aspx] irá tratar do link [LinkButtonSimulationForm]
  • a página mestre [MasterPage.master] irá tratar do link [LinkButtonEndSession]. Para este evento, não é necessário saber qual a página que encapsula.

11.5.2.5. O evento Init da página mestre

As três páginas [Form.aspx, Simulations.aspx, Errors.aspx] da aplicação utilizam [MasterPage.master] como sua página mestre. Vamos chamar a página mestre de M e a página encapsulada de E. Quando a página E é solicitada pelo cliente, ocorrem os seguintes eventos por ordem:

  • E.Init
  • M.Init
  • E.Load
  • M.Load
  • ...

Vamos utilizar o evento Init da página M para executar código que deve ser executado o mais cedo possível, independentemente da página de destino E. Para identificar este código, vamos rever a visão geral da aplicação:

Acima, [Global] é o objeto [HttpApplication] que inicializa a aplicação. Esta classe é a mesma da versão [pam-v4-3tier-nhibernate-multivues-monopage]:


using System;
...
 
namespace pam_v7
{
  public class Global : System.Web.HttpApplication
  {
    // --- static application data ---
    public static Employe[] Employes;
    public static IPamMetier PamMetier = null;
    public static string Msg;
    public static bool Erreur = false;
 
    // application startup
    public void Application_Start(object sender, EventArgs e)
    {
...
    }
 
    public void Session_Start(object sender, EventArgs e)
    {
...
    }
  }
}

Se a classe [Global] não conseguir inicializar a aplicação corretamente, define duas variáveis públicas estáticas:

  • a variável booleana Error na linha 12 é definida como true
  • a variável `Msg` na linha 11 contém uma mensagem com detalhes sobre o erro encontrado

Quando um utilizador solicita uma das páginas [Form.aspx, Simulations.aspx] enquanto a aplicação ainda não foi inicializada corretamente, esse pedido deve ser encaminhado ou redirecionado para a página [Errors.aspx], que exibirá a mensagem de erro da classe [Global]. Existem várias formas de lidar com esta situação:

  • Executar a verificação de erros de inicialização no manipulador de eventos Init ou Load de cada uma das páginas [Formulaire.aspx, Simulations.aspx]
  • Efetuar a verificação de erros de inicialização no manipulador de eventos Init ou Load da página mestre para estas duas páginas. Este método tem a vantagem de colocar a verificação de erros de inicialização num único local.

Optamos por realizar a verificação de erros de inicialização no manipulador de eventos Init da página mestre:


        protected void Page_Init(object sender, System.EventArgs e)
        {
            // event manager 
            LinkButtonTerminerSession.Click += LinkButtonTerminerSession_Click;
            // initialization errors? 
            if (Global.Erreur)
            {
                // is the encapsulated page the error page? 
                bool isPageErreurs =...;
                // if the error page is displayed, leave it alone, otherwise redirect the client to the error page 
                if (!isPageErreurs)
                    Response.Redirect("Erreurs.aspx");
                return;
            }
}

O código acima será executado assim que uma das páginas [Form.aspx, Simulations.aspx, Errors.aspx] for solicitada. Se a página solicitada for [Form.aspx] ou [Simulations.aspx], simplesmente (linha 12) redirecionamos o cliente para a página [Errors.aspx], que exibe a mensagem de erro da classe [Global]. Se a página solicitada for [Errors.aspx], este redirecionamento não deve ocorrer: a página [Errors.aspx] deve ser apresentada. Por isso, precisamos de saber, dentro do método [Page_Init] da página mestre, qual a página que esta encapsula.

Vamos rever a árvore de componentes da página mestre:


...
<body background="ressources/standard.jpg">
    <form id="form1" runat="server">
        <asp:Panel ID="entete" runat="server" BackColor="#FFE0C0" Width="1239px" >
...
        </asp:Panel>
        <div>
            <asp:Panel ID="contenu" runat="server" BackColor="#FFFFC0">
                <asp:ContentPlaceHolder ID="ContentPlaceHolder1" runat="server">
                </asp:ContentPlaceHolder>
            </asp:Panel>
        </div>
    </form>
</body>
</html>
  • linhas 1-13: o contentor com o ID "form1"
  • linhas 4-6: o contentor com o ID "entete", incluído no contentor com o ID "form1"
  • linhas 8-11: o contentor com o id "content", incluído no contentor com o id "form1"
  • linhas 9-10: o contentor com o id "ContentPlaceHolder1", incluído no contentor com o id "content"

Uma página E incorporada na página mestre M está contida no contentor com o id "ContentPlaceHolder1". Para referenciar um componente com o id C nesta página E, escreveríamos:


this.FindControl("form1").FindControl("contenu").FindControl("ContentPlaceHolder1").FindControl("C");

A árvore de componentes da página [Errors.aspx] é a seguinte:


<%@ Page Language="C#" MasterPageFile="~/MasterPage.master" AutoEventWireup="true"
  CodeBehind="Erreurs.aspx.cs" Inherits="pam_v7.PageErreurs" Title="Pam : erreurs" %>
 
<%@ MasterType VirtualPath="~/MasterPage.master" %>
<asp:Content ID="Content1" ContentPlaceHolderID="ContentPlaceHolder1" Runat="Server">
        <h3>Les erreurs suivantes se sont produites au démarrage de l'application</h3>
        <ul>
            <asp:Repeater id="rptErreurs" runat="server">
                <ItemTemplate>
                    <li>
                        <%# Container.DataItem %>
                    </li>
                </ItemTemplate>
            </asp:Repeater>
        </ul>
</asp:Content>

Quando a página [Errors.aspx] é mesclada com a página mestre M, o conteúdo da tag <asp:Content> acima (linhas 5–16) é integrado na tag <asp:ContentPlaceHolder> com o ID "ContentPlaceholder1" na página M, resultando na seguinte árvore de componentes:

...
<body background="ressources/standard.jpg">
    <form id="form1" runat="server">
        <asp:panel ID="entete" runat="server" BackColor="#FFE0C0" Width="1239px" >
...
        </asp:Panel>
        <div>
            <asp:Panel ID="contenu" runat="server" BackColor="#FFFFC0">
                <asp:ContentPlaceHolder ID="ContentPlaceHolder1" runat="server">
              <h3>Les erreurs suivantes se sont produites au démarrage de l'application</h3>
              <ul>
                  <asp:Repeater id="rptErreurs" runat="server">
                      <ItemTemplate>
                          <li>
                              <%# Container.DataItem %>
                          </li>
                      </ItemTemplate>
                  </asp:Repeater>
              </ul>
                </asp:ContentPlaceHolder>
            </asp:Panel>
        </div>
    </form>
</body>
</html>
  • Linha 12: O componente [rptErrors] pode ser utilizado para determinar se a página mestre M contém ou não a página [Errors.aspx]. Este componente existe apenas nesta página.

Estas explicações são suficientes para compreender o código do procedimento [Page_Init] na página mestre:


protected void Page_Init(object sender, System.EventArgs e)
        {
            // event manager 
            LinkButtonTerminerSession.Click += LinkButtonTerminerSession_Click;
            // initialization errors? 
            if (Global.Erreur)
            {
                // is the encapsulated page the error page? 
                bool isPageErreurs = this.FindControl("form1").FindControl("contenu").FindControl("ContentPlaceHolder1").FindControl("rptErreurs") != null;
                // if the error page is displayed, leave it alone, otherwise redirect the client to the error page 
                if (!isPageErreurs)
                    Response.Redirect("Erreurs.aspx");
                return;
            }
        }
  • Linha 4: Associamos um manipulador de eventos ao evento Click do link LinkButtonTerminerSession. Este manipulador encontra-se na classe MasterPage.
  • Linha 6: Verificamos se a classe [Global] definiu o seu booleano Error
  • linha 9: se assim for, o booleano IsPageErrors indica se a página encapsulada na página mestre é a página [Errors.aspx]
  • linha 12: se a página encapsulada na página mestre não for a página [Errors.aspx], o cliente é redirecionado para essa página; caso contrário, nada é feito.

Quando o utilizador clica no link [End Session] na vista (1) acima, o conteúdo da sessão deve ser apagado e um formulário vazio (2) deve ser apresentado.

O código para o manipulador deste evento poderia ser o seguinte:


        protected void LinkButtonTerminerSession_Click(object sender, System.EventArgs e)
        {
            // quit session 
            Session.Abandon();
            // the [form] view is displayed 
            Response.Redirect("Formulaire.aspx");
}
  • Linha 4: A sessão atual é encerrada
  • linha 6: o cliente é redirecionado para a página [Form.aspx]

Podemos ver que este código não envolve nenhum dos componentes das páginas [Form.aspx, Simulations.aspx, Errors.aspx]. O evento pode, portanto, ser tratado pela própria página mestre.

11.5.3. Código de controlo para a página [Errors.aspx]

O código de controlo para a página [Errors.aspx] poderia ser o seguinte:


using System.Collections.Generic;
 
namespace pam_v7
{
  public partial class Erreurs : System.Web.UI.Page
  {
    protected void Page_Load(object sender, System.EventArgs e)
    {
      // initialization errors? 
      if (Global.Erreur)
      {
        // prepare the template for the [errors] page 
        List<string> erreursInitialisation = new List<string>();
        erreursInitialisation.Add(Global.Msg);
        // associate the error list with its component 
        rptErreurs.DataSource = erreursInitialisation;
        rptErreurs.DataBind();
      }
      // set the menu 
      Master.SetMenu(false, false, false, false, false, false);
    }
  }
}

Lembre-se de que a página [Errors.aspx] tem como único objetivo exibir um erro de inicialização da aplicação quando este ocorre:

  • linha 10: verificamos se a inicialização terminou com um erro
  • linhas 13–14: se for o caso, a mensagem de erro (Global.Msg) é colocada numa lista [InitializationErrors]
  • linhas 16–17: o componente [rptErrors] recebe a instrução para exibir esta lista
  • linha 20: em todos os casos (com ou sem erro), as opções do menu da página mestre não são exibidas, pelo que o utilizador não pode iniciar quaisquer novas ações a partir desta página.

O que acontece se o utilizador aceder diretamente à página [Errors.aspx] (o que não deve acontecer durante a utilização normal da aplicação)? Ao analisar o código em [MasterPage.master.cs] e [Errors.aspx.cs], verificamos que:

  • se houve um erro de inicialização, este é apresentado
  • se não houve erro de inicialização, o utilizador recebe uma página contendo apenas o cabeçalho de [MasterPage.master], sem opções de menu exibidas.

11.5.4. Código de controlo para a página [Formulaire.aspx]

11.5.4.1. Estrutura da classe

O esqueleto do código de controlo para a página [Form.aspx] poderia ser o seguinte:


using Pam.Metier.Entites;
...
 
partial class PageFormulaire : System.Web.UI.Page
{
 
    // page loading 
    protected void Page_Load(object sender, System.EventArgs e)
    {
        // event manager
        Master.OptionFaireSimulation.Click += OptFaireSimulation_Click;
        Master.OptionEffacerSimulation.Click += OptEffacerSimulation_Click;
        Master.OptionVoirSimulations.Click += OptVoirSimulations_Click;
        Master.OptionEnregistrerSimulation.Click += OptEnregistrerSimulation_Click;
....
    }
 
    // payroll calculation 
    private void OptFaireSimulation_Click(object sender, System.EventArgs e)
    {
....
    }
 
    // delete simulation 
    private void OptEffacerSimulation_Click(object sender, System.EventArgs e)
    {
...
    }
 
    protected void OptVoirSimulations_Click(object sender, System.EventArgs e)
    {
....
    }

    protected void OptEnregistrerSimulation_Click(object sender, System.EventArgs e)
    {
...
    }
 
}

O código de controlo da página [Formulaire.aspx] gere cinco eventos:

  1. o evento Load da página
  2. o evento Click no link [LinkButtonRunSimulation] na página mestre
  3. o evento Click no link [LinkButtonClearSimulation] na página mestre
  4. o evento Click do link [LinkButtonEnregistrerSimulation] na página mestre
  5. o evento Click no link [LinkButtonViewSimulations] na página mestre

11.5.4.2. Evento Page Load

A estrutura do manipulador do evento de carregamento da página poderia ser a seguinte:


    protected void Page_Load(object sender, System.EventArgs e)
    {
        // event manager
        Master.OptionFaireSimulation.Click += OptFaireSimulation_Click;
        Master.OptionEffacerSimulation.Click += OptEffacerSimulation_Click;
        Master.OptionVoirSimulations.Click += OptVoirSimulations_Click;
        Master.OptionEnregistrerSimulation.Click += OptEnregistrerSimulation_Click;
        // view [entries] display 
        ...
        // menu positioning master page 
        ...
        // query processing GET 
        if (!IsPostBack)
        {
            // loading employee names into the combo 
...
            // init view [entries] with entries stored in the session if they exist 
....
        }
}

Um exemplo para esclarecer o comentário na linha 17 poderia ser este:

  • Em [1], solicitamos a lista de simulações. Foram introduzidos dados em [A, B, C].
  • Em [2], vemos a lista
  • Em [3], pedimos para voltar ao formulário
  • em [4], o formulário é apresentado exatamente como foi deixado. Uma vez que houve dois pedidos, (1,2) e (3,4), isto significa que:
    • ao passar de [1] para [2], as entradas de [1] foram guardadas
    • ao passar de [3] para [4], foram restauradas. É o procedimento [Page_Load] em [Form.aspx] que realiza esta restauração.

Pergunta: Complete o procedimento Page_Load utilizando os comentários e o código da versão [pam-v4-3tier-nhibernate-multivues-monopage]


A estrutura dos manipuladores de eventos de clique para os links na página mestre é a seguinte:


// payroll calculation 
    private void OptFaireSimulation_Click(object sender, System.EventArgs e)
    {
        // ajax effect
        Thread.Sleep(3000);
        // valid page? 
        Page.Validate();
        if (!Page.IsValid)
        {
            // view display [input] 
...
        }
        // the page is validated - inputs are retrieved 
...
        // we calculate the employee's salary 
        FeuilleSalaire feuillesalaire;
        try
        {
            feuillesalaire = ...;
        }
        catch (PamException ex)
        {
            // we encountered a problem 
...
            return;
        }
        // put the result in the session 
        Session["simulation"] = ...;
        // put the entries in the session 
...
        // display 
...
        // views display 
...
        // display menu MasterPage 
...
    }
 
    // delete simulation 
    private void OptEffacerSimulation_Click(object sender, System.EventArgs e)
    {
        // display panel [input] 
...
        // selection 1st employee 
...
    }
 
    protected void OptVoirSimulations_Click(object sender, System.EventArgs e)
    {
        // put the entries in the session 
...
        // the [simulations] view is displayed 
        Response.Redirect("simulations.aspx");
    }
 
    protected void OptEnregistrerSimulation_Click(object sender, System.EventArgs e)
    {
        // save the current simulation in the user's session 
...
        // the [simulations] view is displayed 
        Response.Redirect("simulations.aspx");
}

Pergunta: Complete o código para os procedimentos acima utilizando os comentários e o código da versão [pam-v4-3tier-nhibernate-multivues-monopage]


11.5.5. Código de controlo para a página [Simulations.aspx]

O esboço do código de controlo para a página [Simulations.aspx] poderia ser o seguinte:


using System.Collections.Generic;
using Pam.Web;
using System.Web.UI.WebControls;
 
partial class PageSimulations : System.Web.UI.Page
{
 
    // simulations 
    private List<Simulation> simulations;
 
    // page loading
    protected void Page_Load(object sender, System.EventArgs e)
    {
        // event manager 
        Master.OptionFormulaireSimulation.Click += OptFormulaireSimulation_Click;
        GridViewSimulations.RowDeleting += GridViewSimulations_RowDeleting;
        // simulations are retrieved from the
        simulations = ...;
        // are there any simulations? 
        if (simulations.Count != 0)
        {
            // first view visible 
            ...
            // fill the gridview 
            ...
        }
        else
        {
            // second view 
            ...
        }
        // set the menu 
        ...
    }
 
    protected void GridViewSimulations_RowDeleting(object sender, System.Web.UI.WebControls.GridViewDeleteEventArgs e)
    {
        // simulations are retrieved from the
        List<Simulation> simulations = ...;
        // delete the designated simulation (e.RowIndex represents the number of the deleted line in the gridview)
        ..
        // are there any simulations left? 
        if (simulations.Count != 0)
        {
            // fill the gridview 
            ...
        }
        else
        {
            // view [SimulationsVides] 
            ...
        }
    }
 
    protected void OptFormulaireSimulation_Click(object sender, System.EventArgs e)
    {
        // the [form] view is displayed 
        Response.Redirect("formulaire.aspx");
    }
 
}

Pergunta: Complete o código para os procedimentos acima utilizando os comentários e o código da versão [pam-v4-3tier-nhibernate-multivues-monopage]


11.5.6. Código de controlo para a página [Default.aspx]

Pode incluir uma página [Default.aspx] na aplicação para permitir que o utilizador solicite o URL da aplicação sem especificar uma página, conforme mostrado abaixo:

A solicitação [1] recebeu a página [Formulaire.aspx] (2) como resposta. Sabemos que a solicitação (1) é tratada por padrão pela página [Default.aspx] da aplicação. Para obter (2), a [Default.aspx] precisa simplesmente redirecionar o cliente para a página [Formulaire.aspx]. Isto pode ser feito com o seguinte código:


partial class _Default : System.Web.UI.Page
{
 
    protected void Page_Init(object sender, System.EventArgs e)
    {
        // redirects to the input form 
        Response.Redirect("Formulaire.aspx");
    }
}

A página de apresentação [Default.aspx] contém apenas a diretiva que a vincula a [Default.aspx.cs]:


<%@ Page Language="C#" AutoEventWireup="true"
  CodeBehind="Default.aspx.cs" Inherits="pam_v7._Default" Title="Untitled Page" %>