Skip to content

11. O aplicativo [SimuPaie] – versão 7 – ASP.NET / múltiplas visualizações / múltiplas páginas


Leituras recomendadas: referência [1], Desenvolvimento WEB com ASP.NET 1.1 parágrafo: Exemplos


Analisaremos agora uma versão funcionalmente idêntica ao aplicativo ASP.NET de três camadas [pam-v4-3tier-nhibernate-multivues-monopage] estudado anteriormente, mas modificaremos a arquitetura deste último da seguinte maneira: enquanto na versão anterior as visualizações eram implementadas por uma única página ASPX, aqui elas serão implementadas por três páginas ASPX.

A arquitetura do aplicativo 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 contato com o cliente. Ela recebe todas as solicitações do cliente.
  • [Saisies, Simulation, Simulations, ...] são as visualizações. Essas visualizações são implementadas aqui por meio dos componentes [View] da página [Default.aspx].

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

  • apenas a camada [web] sofre alterações
  • as visualizações (o que é exibido ao usuário) não mudam.
  • O código do controlador, que na versão anterior estava inteiramente no [Default.aspx.cs], agora está distribuído por várias páginas:
    • [MasterPage.master]: uma página que agrupa o que é comum às diferentes visualizações: a barra superior com suas opções de menu
    • [Formulaire.aspx]: a página que apresenta o formulário de simulação e gerencia as ações que ocorrem nesse formulário
    • [Simulations.aspx]: a página que apresenta a lista de simulações e gerencia as ações realizadas nessa mesma página
    • [Erreurs.aspx]: a página exibida quando ocorre um erro de inicialização do aplicativo. Não há ações possíveis nessa página.

Pode-se considerar que temos aqui uma arquitetura MVC com múltiplos controladores, enquanto a arquitetura da versão anterior era uma arquitetura MVC com um único controlador.

O processamento de uma solicitação de um cliente ocorre de acordo com as seguintes etapas:

  1. o cliente faz uma solicitação à aplicação. Ele a faz em uma das duas páginas [Formulaire.aspx, Simulations.aspx].
  2. a página solicitada processa essa solicitação. Para isso, ela pode precisar da ajuda da camada [métier], que, por sua vez, pode precisar da camada [dao] caso seja necessário trocar dados com o banco de dados. O aplicativo recebe uma resposta da camada [métier].
  3. Com base nela, ela seleciona (3) a visualização (= a resposta) a ser enviada ao cliente, fornecendo-lhe (4) as informações (o modelo) de que necessita.
  4. A resposta é enviada ao cliente (5)

11.1. As visualizações do aplicativo

As diferentes visualizações apresentadas ao usuário são as seguintes:

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

Image

  • - a visualização [VueSimulation], utilizada para exibir o resultado detalhado da simulação:

Image

  • - a visualização [VueSimulations], que exibe a lista das simulações realizadas pelo cliente

Image

  • - a visualização [VueSimulationsVides], que indica que o cliente não possui ou não possui mais simulações:

Image

  • a visualização [VueErreurs], que indica um erro de inicialização do aplicativo:

Image

11.2. Geração de visualizações em um contexto com vários controladores

Na versão anterior, todas as visualizações eram geradas a partir da única página [Default.aspx]. Essa página continha dois componentes [MultiView], e as visualizações eram compostas pela combinação de um ou dois componentes [View] pertencentes a esses dois componentes [MultiView].

Eficaz quando há poucas visualizações, essa arquitetura atinge seus limites assim que o número de componentes que formam as diferentes visualizações se torna significativo: de fato, a cada solicitação feita à única página [Default.aspx], todos os componentes dessa página são instanciados, embora apenas alguns deles sejam utilizados para gerar a resposta ao usuário. Assim, um trabalho desnecessário é realizado a cada nova solicitação, o que se torna oneroso quando o número total de componentes da página é elevado.

Uma solução é, portanto, distribuir as visualizações por diferentes páginas. É isso que fazemos aqui. Vamos analisar dois casos diferentes de geração de visualizações:

  1. a solicitação é feita a uma página P1, e esta gera a resposta
  2. a solicitação é feita a uma página P1 e esta solicita que uma página P2 gere a resposta

11.2.1. Caso 1: uma página controladora/visã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 essa solicitação. Para isso, ela pode precisar da ajuda da camada [métier] (2), que, por sua vez, pode precisar da camada [dao] caso seja necessário trocar dados com o banco de dados. A aplicação recebe uma resposta da camada [métier].
  3. Com base nela, ela seleciona (3) a visualização (= a resposta) a ser enviada ao cliente, fornecendo-lhe (4) as informações (o modelo) de que necessita. Trata-se, neste caso, de selecionar na página P1 os componentes [Panel] ou [View] a serem exibidos e de inicializar os componentes que eles contêm.
  4. A resposta é enviada ao cliente (5)

Aqui estão dois exemplos retirados do aplicativo em análise:

[page Formulaire.aspx]

  • em [1]: o usuário, após ter solicitado a página [Formulaire.aspx], solicita uma simulação
  • em [2]: a página [Formulaire.aspx] processou essa solicitação e gerou ela mesma a resposta, exibindo um componente [View] que não havia sido exibido em [1]

[page Simulations.aspx]

  • em [1]: o usuário, após ter solicitado a página [Simulations.aspx], deseja remover uma simulação
  • em [2]: a página [Simulations.aspx] processou essa solicitação e gerou ela mesma a resposta, exibindo novamente a nova lista de simulações.
2

11.2.2. Caso 2: uma página 1 controladora, uma página 2 controladora/visualização

O caso 2 pode abranger diversas arquiteturas. Escolheremos a seguinte:

  1. o cliente faz uma solicitação à página P1 (1)
  2. a página P1 processa essa solicitação. Para isso, ela pode precisar da ajuda da camada [métier] (2), que, por sua vez, pode precisar da camada [dao] caso seja necessário trocar dados com o banco de dados. A aplicação recebe uma resposta da camada [métier].
  3. Com base nela, ela seleciona (3) a visualização (= a resposta) a ser enviada ao cliente, fornecendo-lhe (4) as informações (o modelo) de que necessita. Acontece que, neste caso, a visualização a ser gerada deve ser feita por outra página que não a P1, a página P2. Para realizar as operações (3) e (4), a página P1 tem duas possibilidades:
    • fazer uma transferência de execução para a página P2 por meio da operação [Server.Transfer(" P2.aspx ")]. Nesse caso, ela pode inserir o modelo destinado à página P2 no contexto da solicitação [Context.Items[" clé "]=valeur] ou na sessão do usuário [Session.[" clé "]=valeur]. A página P2 será então instanciada e, durante o processamento de seu evento Load, por exemplo, ela poderá recuperar as informações transmitidas pela página P1 por meio das operações [valeur=(Type)Context.Items[" clé "]] ou [valeur=(Type)Session[" clé "]], conforme o caso, em que Type é o tipo do valor associado à chave. A transmissão de valores pelo contexto Context é a mais adequada caso não haja necessidade de que os valores do modelo sejam mantidos para uma futura solicitação do cliente.
    • solicitar ao cliente que seja redirecionado para a página P2 por meio da operação [Response.Redirect(" P2.aspx ")]. Nesse caso, a página P1 colocará o modelo destinado à página P2 na sessão, pois o contexto de solicitação Context é removido ao final de cada solicitação. No entanto, neste caso, o redirecionamento provocará o término da primeira solicitação do cliente para P1 e o envio de uma segunda solicitação desse mesmo cliente, desta vez para P2. Há duas solicitações sucessivas. Sabemos que a sessão é um dos meios de preservar a “memória” entre as solicitações. Existem outras soluções além da sessão.
  4. Independentemente da forma como P2 assume o controle, voltamos então ao caso 1: P2 recebeu uma solicitação que irá processar (5) e irá gerar ela mesma a resposta (6, 7). Também é possível imaginar que a página P2, após processar a solicitação, passe o controle para uma página P3, e assim por diante.

Aqui está um exemplo retirado do aplicativo em análise:

  • para [1]: o usuário que solicitou a página [Formulaire.aspx] pede para ver a lista de simulações
  • em [2]: a página [Formulaire.aspx] processa essa solicitação e redireciona o cliente para a página [Simulations.aspx]. É esta última que fornece a resposta ao usuário. Em vez de solicitar que o cliente seja redirecionado, a página [Formulaire.aspx] poderia ter encaminhado a solicitação do cliente para a página [Simulations.aspx]. Nesse caso, na página [2], veríamos a mesma URL que na página [1]. De fato, um navegador sempre exibe a última URL solicitada:
    • a ação solicitada na página [1] destina-se à página [Formulaire.aspx]. O navegador realiza uma solicitação para essa página.
    • Se a página [Formulaire.aspx] processar a solicitação e, em seguida, a transferir por meio de [Server.Transfer(" Simulations.aspx ")] para a página [Simulations.aspx], permanecemos na mesma solicitação. O navegador exibirá então, em [2], o URL de [Formulaire.aspx], para o qual ocorreu o POST.
    • Se a página [Formulaire.aspx] processar a solicitação e, em seguida, redirecioná-la por meio de [Response.Redirect(" Simulations.aspx ")] para a página [Simulations.aspx], o navegador faz então uma segunda solicitação, um GET para [Simulations.aspx]. O navegador exibirá então, em [2], o URL de [Simulations.aspx], para o qual ocorreu o GET. É isso que a captura de tela [2] acima nos mostra.

11.3. O projeto Visual Web Developer da camada [web]

O projeto Visual Web Developer da camada [web] é o seguinte:

  • em [1], encontramos:
    • o arquivo de configuração [Web.config] do aplicativo – é idêntico ao do aplicativo [pam-v4-3tier-nhibernate-multivues-monopage].
    • a página [Default.aspx] – limita-se a redirecionar o cliente para a página [Formulaire.aspx]
    • a página [Formulaire.aspx], que apresenta ao usuário o formulário de simulação e processa as ações relacionadas a esse formulário
    • a página [Simulations.aspx], que apresenta ao usuário a lista de suas simulações e processa as ações relacionadas a essa página
    • a página [Erreurs.aspx], que apresenta ao usuário uma página informando sobre um erro ocorrido ao iniciar o aplicativo web.
  • Na página [2], são exibidas as referências do projeto.

Voltemos à arquitetura do novo projeto:

Em relação ao projeto [pam-v4-3tier-nhibernate-multivues-monopage], apenas as visualizações foram alteradas. Assim, o novo projeto herda alguns dos arquivos desse projeto:

  • o arquivo de configuração [Web.config]
  • os arquivos DLL referenciados por [pam-dao-nhibernate, pam-metier-dao-nhibernate, Spring.Core, NHibernate]
  • a classe global de aplicação [Global.asax]
  • as pastas [images, ressources, pam]

Para manter a coerência com o projeto em desenvolvimento, faremos com que o espaço de nomes das visualizações e da classe global de aplicação seja [pam-v7]:

  

11.4. O código de apresentação das páginas

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

As visualizações da aplicação apresentadas no parágrafo 11.1 possuem partes comuns que podem ser agrupadas em uma página mestre, chamada de Master Page no Visual Studio. Tomemos, por exemplo, as visualizações [VueSaisies] e [VueSimulationsVides] abaixo, geradas respectivamente pelas páginas [Formulaire.aspx] e [Simulations.aspx]:

Essas duas visualizações têm em comum a barra superior (Título e Opções de menu). O mesmo se aplica a todas as visualizações que serão apresentadas ao usuário: todas terão a mesma barra superior. Para que diferentes páginas compartilhem um mesmo fragmento de apresentação, existem diversas soluções, entre as quais as seguintes:

  • colocar esse fragmento comum em um componente de usuário. Essa era a principal técnica utilizada no ASP.NET 1.1
  • colocar esse fragmento comum em uma página mestre. Essa técnica surgiu com o ASP.NET 2.0. É a que estamos utilizando aqui.

Para criar uma página mestre em um aplicativo web, pode-se proceder da seguinte forma:

  • clique com o botão direito do mouse no projeto / Adicionar um novo elemento / Página mestre:

A adição de uma página mestre insere, por padrão, três arquivos na aplicação web:

  • [MasterPage.master]: o código de apresentação da página mestre
  • [MasterPage.master.cs]: o código de controle da página mestre
  • [Masterpage.Master.designer.cs]: a declaração dos componentes da página mestre

O código gerado pelo Visual Studio no arquivo [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 ... %> serve para definir a página como uma página mestre. O código de controle da página estará no arquivo definido pelo atributo CodeBehind, e a página herdará a classe definida pelo atributo Inherits.
  • linhas 12-18: o formulário da página mestre
  • linhas 14-16: um contêiner vazio que, em nossa aplicação, conterá uma das páginas [Formulaire.aspx, Simulations.aspx, Erreurs.aspx]. O cliente recebe como resposta, sempre a mesma página, a página mestre, na qual o contêiner [ContentPlaceHolder1] receberá um fluxo HTML fornecido por uma das páginas [Formulaire.aspx, Simulations.aspx, Erreurs.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 contêiner vazio com o qual as páginas “filhas” poderão personalizar o cabeçalho <head>...</head>.

A representação visual (aba Design) desse código-fonte é apresentada em (1) abaixo. Além disso, é possível adicionar quantos contêineres forem desejados, graças ao componente [ContentPlaceHolder] (2) da barra de ferramentas [Standard].

O código de controle gerado pelo Visual Studio no [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 ... %> da página [MasterPage.master] deriva da classe [System.Web.UI.MasterPage]

Acima, vemos a presença do método Page_Load, que gerencia o evento Load da página mestre. A página mestre conterá, em seu interior, outra página. Em que ordem ocorrem os eventos Load das duas páginas? Trata-se de uma regra geral: o evento Load de um componente ocorre antes do evento de seu contêiner. Nesse caso, o evento Load da página inserida na página mestre ocorrerá, portanto, antes do evento da própria página mestre.

Para que gere uma página cuja página-mestre seja a página [MasterPage.master] anterior, pode-se proceder da seguinte forma:

  • em [1]: clique com o botão direito do mouse na página mestre e selecione a opção [Ajouter une page de contenu]
  • em [2]: é gerada uma página padrão, neste caso [WebForm1.aspx].

O código de apresentação [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 seus atributos
    • MasterPageFile: indica o arquivo da página-mestre da página descrita pela diretiva. O sinal ~ indica a pasta do projeto.
    • os demais parâmetros são os habituais de uma página da web ASP
  • linhas 2-3: as tags <asp:Content> são vinculadas, uma a uma, às diretivas <asp:ContentPlaceHolder> da página mestre por meio do atributo ContentPlaceHolderID. Os componentes colocados entre as linhas 2 e 3 acima serão, na execução, inseridos no contêiner de ID ContentPlaceHolder1 da página mestre.

Ao renomear a página [WebForm1.aspx] assim gerada, é possível criar as diferentes páginas tendo [MasterPage.master] como página mestre.

Para nossa aplicação [SimuPaie], a aparência 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
LinkButton
LinkButtonFaireSimulation
solicita o cálculo da simulação
2
LinkButton
LinkButtonEffacerSimulation
apaga o formulário de preenchimento
3
LinkButton
LinkButtonVoirSimulations
exibe a lista das simulações já realizadas
4
LinkButton
LinkButtonFormulaireSimulation
retorna ao formulário de preenchimento
5
LinkButton
LinkButtonEnregistrerSimulation
grava a simulação atual na lista de simulações
6
LinkButton
LinkButtonTerminerSession
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: observe o nome da classe da página mestre: MasterPage
  • linha 8: define-se 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 contêiner AJax
  • linhas 12-62: o conteúdo com Ajax
  • linhas 13-55: o componente Panel [entete]
  • linhas 57-60: o componente Panel [contenu]
  • linhas 58-59: o componente ID [ContentPlaceHolder1], que conterá a página encapsulada [Formulaire.aspx, Simulations.aspx, Erreurs.aspx]

Para construir essa página, será possível inserir no painel [entete], o código ASPX da visualização [VueEntete] da página [Default.aspx] da versão [pam-v4-3tier-nhibernate-multivues-monopage], descrita no parágrafo 8.5.2.

11.4.2. A página [Formulaire.aspx]

Para gerar esta página, seguirá-se o método exposto no parágrafo 11.4.1 e renomear-se-á a página [WebForm1.aspx], assim gerada, para [Formulaire.aspx]. A aparência visual da página [Formulaire.aspx] em fase de construção será a seguinte:

A aparência da página [Formulaire.aspx] possui dois elementos:

  • em [1], a página mestre com seu contêiner [ContentPlaceHolder1] (2)
  • em [2], os componentes colocados no contêiner [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 seu atributo MasterPageFile
  • linha 4: a classe de controle da página mestre pode expor campos e propriedades públicos. Estes são acessíveis às páginas encapsuladas com a sintaxe Master.[champ] ou Master.[propriété]. A propriedade Master da página designa a página mestre na forma de uma instância do tipo [System.Web.UI.MasterPage]. Portanto, em nosso exemplo, seria necessário escrever, na verdade, (MasterPage)(Master).[champ] ou (MasterPage)(Master).[propriété]. É possível evitar essa conversão de tipo inserindo na página a diretiva MasterType da linha 4. O atributo VirtualPath dessa diretiva indica o arquivo da página mestre. O compilador pode, então, identificar os campos, propriedades e métodos públicos expostos pela classe da página mestre, neste caso do tipo [MasterPage].
  • linhas 5-22: o conteúdo que será inserido no contêiner [ContentPlaceHolder1] da página mestre.

É possível construir essa página inserindo como conteúdo (linhas 6-21) o da visualização [VueSaisies] descrita no parágrafo 8.5.3 e o da visualização [VueSimulation] descrita no parágrafo 8.5.4.

11.4.3. A página [Simulations.aspx]

Para gerar esta página, seguirá-se o método exposto no parágrafo 11.4.1 e renomeará-se a página [WebForm1.aspx], assim gerada, para [Simulations.aspx]. A aparência visual da página [Simulations.aspx] em fase de construção é a seguinte:

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

  • em [1], a página mestre com seu contêiner [ContentPlaceHolder1]
  • em [2], os componentes colocados no contêiner [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>

É possível construir essa página inserindo como conteúdo (linhas 5-21) o da visualização [VueSimulations] descrita no parágrafo 8.5.5 e o da visualização [VueSimulationsVides] descrita no parágrafo 8.5.6.

11.4.4. A página [Erreurs.aspx]

Para gerar esta página, seguirá-se o método exposto no parágrafo 11.4.1 e renomeará-se a página [WebForm1.aspx], assim gerada, para [Erreurs.aspx]. A aparência visual da página [Erreurs.aspx] em fase de construção é a seguinte:

A aparência visual da página [Erreurs.aspx] possui dois elementos:

  • em [1], a página mestre com seu contêiner [ContentPlaceHolder1]
  • em [2], os componentes colocados no contêiner [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. O código de controle das páginas

11.5.1. Visão geral

Voltemos à arquitetura do aplicativo:

  • [Global] é o objeto do tipo [HttpApplication] que inicializa (etapa 0) o aplicativo. Essa classe é idêntica à da versão anterior.
  • O código do controlador, que na versão anterior estava inteiramente em [Default.aspx.cs], agora está distribuído por várias páginas:
    • [MasterPage.master]: a página mestre das páginas [Formulaire.aspx, Simulations.aspx, Erreurs.aspx]. Ela contém o menu.
    • [Formulaire.aspx]: a página que apresenta o formulário de simulação e gerencia as ações realizadas nesse formulário
    • [Simulations.aspx]: a página que exibe a lista de simulações e gerencia as ações realizadas nessa mesma página
    • [Erreurs.aspx]: a página exibida quando ocorre um erro de inicialização do aplicativo. Não há ações possíveis nessa página.

O processamento de uma solicitação de um cliente ocorre de acordo com as seguintes etapas:

  1. o cliente faz uma solicitação ao aplicativo. Normalmente, ele a faz em uma das duas páginas [Formulaire.aspx, Simulations.aspx], mas nada o impede de solicitar a página [Erreurs.aspx]. É preciso prever esse caso.
  2. a página solicitada processa essa solicitação (etapa 1). Para isso, ela pode precisar da ajuda da camada [métier] (etapa 2), que, por sua vez, pode precisar da camada [dao] caso seja necessário trocar dados com o banco de dados. A aplicação recebe uma resposta da camada [métier].
  3. Com base nela, ela escolhe (etapa 3) a visualização (= a resposta) a ser enviada ao cliente e fornece a ele (etapa 4) as informações (o modelo) de que precisa. Vimos três possibilidades para gerar essa resposta:
    • a página (D) solicitada é também a página (R) enviada como resposta. Construir o modelo da resposta (R) consiste, então, em atribuir a alguns dos componentes da página (D) o valor que eles devem ter na resposta.
    • a página (D) solicitada não é a página (R) enviada como resposta. A página (D) pode então:
      • transferir o fluxo de execução para a página (R) por meio da instrução Server.Transfer(" R "). O modelo pode então ser inserido no contexto por meio da instrução Context.Items("chave")=valor ou, mais raramente, na sessão por meio da instrução Session.Items("chave")=valor
      • redirecionar o cliente para a página (R) por meio da instrução Response.redirect(" R "). O modelo pode então ser inserido na sessão, mas não no contexto.
  4. A resposta é enviada ao cliente (etapa 5)

Cada uma das páginas [MasterPage.master, Formulaire.aspx, Simulations.aspx, Erreurs.aspx] responderá a um ou mais dos eventos abaixo:

  • Init: primeiro evento no ciclo de vida da página
  • Load: ocorre ao carregar a página
  • Click: o clique em um dos links do menu da página mestre

Processamos as páginas uma após a outra, começando pela página principal.

11.5.2. Código de controle da página [MasterPage.master]

11.5.2.1. Estrutura da classe

O código de controle da página mestre tem a seguinte estrutura:


using System.Web.UI.WebControls;

namespace pam_v7
{
  public partial class MasterPage : System.Web.UI.MasterPage
  {

    // o menu 
    public LinkButton OptionFaireSimulation
    {
      get { return LinkButtonFaireSimulation; }
    }
...

    // fixar o menu 
    public void SetMenu(bool boolFaireSimulation, bool boolEnregistrerSimulation, bool boolEffacerSimulation, bool boolFormulaireSimulation, bool boolVoirSimulations, bool boolTerminerSession)
    {
....
    }

    // gerenciamento da opção [Terminer la session] 
    protected void LinkButtonTerminerSession_Click(object sender, System.EventArgs e)
    {
....
    }

    // inicializar a página mestre 
    protected void Page_Init(object sender, System.EventArgs e)
    {
....
      }
    }
  }
}
  • linha 5: a classe se chama [MasterPage] e deriva da classe do sistema [System.Web.UI.MasterPage].
  • linhas 9-14: as seis opções do menu são definidas como propriedades públicas da classe
  • linhas 16-19: o método público SetMenu permitirá que as páginas [Formulaire.aspx, Simulations.aspx, Erreurs.aspx] definam o menu da página mestre
  • linhas 22-25: o procedimento que irá gerenciar o clique no link [LinkButtonTerminerSession]
  • linhas 28-31: o procedimento de gerenciamento 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
  {

    // o 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 entender esse código, é preciso lembrar os componentes que formam 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
LinkButton
LinkButtonFaireSimulation
solicita o cálculo da simulação
2
LinkButton
LinkButtonEffacerSimulation
apaga o formulário de preenchimento
3
LinkButton
LinkButtonVoirSimulations
exibe a lista das simulações já realizadas
4
LinkButton
LinkButtonFormulaireSimulation
retorna ao formulário de preenchimento
5
LinkButton
LinkButtonEnregistrerSimulation
grava a simulação atual na lista de simulações
6
LinkButton
LinkButtonTerminerSession
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 das linhas 9 a 37 têm como objetivo torná-los acessíveis a classes externas, neste caso, as classes das outras páginas do aplicativo.

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. Seu código é básico:


        // fixar o menu 
        public void SetMenu(bool boolFaireSimulation, bool boolEnregistrerSimulation, bool boolEffacerSimulation, bool boolFormulaireSimulation, bool boolVoirSimulations, bool boolTerminerSession)
        {
            // definindo as opções do menu 
            LinkButtonFaireSimulation.Visible = boolFaireSimulation;
            LinkButtonEnregistrerSimulation.Visible = boolEnregistrerSimulation;
            LinkButtonEffacerSimulation.Visible = boolEffacerSimulation;
            LinkButtonVoirSimulations.Visible = boolVoirSimulations;
            LinkButtonFormulaireSimulation.Visible = boolFormulaireSimulation;
            LinkButtonTerminerSession.Visible = boolTerminerSession;
}

11.5.2.4. Gerenciamento de eventos da página mestre

A página mestre irá gerenciar dois eventos:

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

A página mestre possui outros cinco links: [LinkButtonFaireSimulation, LinkButtonEnregistrerSimulation, LinkButtonEffacerSimulation, LinkButtonVoirSimulations, LinkButtonFormulaireSimulation]. A título de exemplo, vamos examinar o que seria necessário fazer ao clicar no link [LinkButtonFaireSimulation]:

  1. verificar os dados inseridos (horas, dias) na página [Formulaire.aspx]
  2. fazer o cálculo do salário
  3. exibir os resultados na página [Formulaire.aspx]

As operações 1 e 3 exigem acesso aos componentes da página [Formulaire.aspx]. Esse não é o caso. De fato, a página mestre não tem conhecimento dos componentes das páginas que podem ser inseridas em seu contêiner [ContentPlaceHolder1]. No nosso exemplo, cabe à página [Formulaire.aspx] gerenciar o clique no link [LinkButtonFaireSimulation], pois é ela que está sendo exibida quando esse evento ocorre. Como ela pode ser notificada sobre esse evento?

  • Como o link [LinkButtonFaireSimulation] não faz parte da página [Formulaire.aspx], não é possível escrever na página [Formulaire.aspx] o procedimento habitual:

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

É possível 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
    {
// carregamento da página 
    protected void Page_Load(object sender, System.EventArgs e)
    {
        // gerenciador de eventos
        Master.OptionFaireSimulation.Click += OptFaireSimulation_Click;
        Master.OptionEffacerSimulation.Click += OptEffacerSimulation_Click;
        Master.OptionVoirSimulations.Click += OptVoirSimulations_Click;
        Master.OptionEnregistrerSimulation.Click += OptEnregistrerSimulation_Click;
...
    }

    // cálculo da folha de pagamento 
    private void OptFaireSimulation_Click(object sender, System.EventArgs e)
    {
....
    }

    // apagar a simulação 
    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 já foi instanciada. Suas propriedades públicas Optionxx estão acessíveis e são do tipo LinkButton, um componente que suporta o evento Click. Associamos a esses eventos Click os métodos:
    • 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 gerenciamento dos eventos Click nos seis links do menu será distribuído da seguinte forma:

  • a página [Formulaire.aspx] gerenciará os links [LinkButtonFaireSimulation, LinkButtonEnregistrerSimulation, LinkButtonEffacerSimulation, LinkButtonVoirSimulations]
  • a página [Simulations.aspx] gerenciará o link [LinkButtonFormulaireSimulation]
  • a página mestre [MasterPage.master] administrará o link [LinkButtonTerminerSession]. Para esse evento, ela não precisa saber qual é a página que está encapsulando.

11.5.2.5. O evento Init da página mestre

As três páginas [Formulaire.aspx, Simulations.aspx, Erreurs.aspx] do aplicativo têm [MasterPage.master] como página mestre. Chamemos de M a página mestre e de E a página encapsulada. Quando a página E é solicitada pelo cliente, os seguintes eventos ocorrem na seguinte ordem:

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

Vamos utilizar o evento Init da página M para executar um código que seria interessante executar o mais cedo possível, independentemente da página de destino E. Para identificar esse código, vamos revisar a visão geral do aplicativo:

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


using System;
...

namespace pam_v7
{
  public class Global : System.Web.HttpApplication
  {
    // --- dados estáticos do aplicativo ---
    public static Employe[] Employes;
    public static IPamMetier PamMetier = null;
    public static string Msg;
    public static bool Erreur = false;

    // inicialização do aplicativo
    public void Application_Start(object sender, EventArgs e)
    {
...
    }

    public void Session_Start(object sender, EventArgs e)
    {
...
    }
  }
}

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

  • a variável booleana Erro, na linha 12, é definida como vrai
  • a variável `Msg` da linha 11 contém uma mensagem com detalhes sobre o erro ocorrido

Quando o usuário solicita uma das páginas [Formulaire.aspx, Simulations.aspx], mas o aplicativo não foi inicializado corretamente, essa solicitação deve ser transferida ou redirecionada para a página [Erreurs.aspx], que exibirá a mensagem de erro da classe [Global]. É possível lidar com esse caso de várias maneiras:

  • realizar o teste de erro de inicialização no gerenciador de eventos Init ou Load de cada uma das páginas [Formulaire.aspx, Simulations.aspx]
  • executar o teste de erro de inicialização no gerenciador de eventos Init ou Load da página mestre dessas duas páginas. Esse método tem a vantagem de centralizar o teste de erro de inicialização em um único local.

Optamos por realizar o teste de erro de inicialização no gerenciador de eventos Init da página mestre:


        protected void Page_Init(object sender, System.EventArgs e)
        {
            // gerenciador de eventos 
            LinkButtonTerminerSession.Click += LinkButtonTerminerSession_Click;
            // erros de inicialização? 
            if (Global.Erreur)
            {
                // a página encapsulada é a página de erros? 
                bool isPageErreurs =...;
                // se for a página de erros que estiver sendo exibida, deixamos como está; caso contrário, redirecionamos o cliente para a página de erros 
                if (!isPageErreurs)
                    Response.Redirect("Erreurs.aspx");
                return;
            }
}

O código acima será executado assim que uma das páginas [Formulaire.aspx, Simulations.aspx, Erreurs.aspx] for solicitada. Caso a página solicitada seja [Formulaire.aspx, Simulations.aspx], basta (linha 12) redirecionar o cliente para a página [Erreurs.aspx], que se encarregará de exibir a mensagem de erro da classe [Global]. Caso a página solicitada seja [Erreurs.aspx], esse redirecionamento não deve ocorrer: é preciso permitir que a página [Erreurs.aspx] seja exibida. Portanto, precisamos saber, no método [Page_Init] da página mestre, qual é a página que ela encapsula.

Voltemos à á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 contêiner com id “form1”
  • linhas 4-6: o contêiner com o id “entete”, incluído no contêiner com o id “form1”
  • linhas 8-11: o contêiner com o id “contenu”, incluído no contêiner com o id “form1”
  • linhas 9-10: o contêiner com o id “ContentPlaceHolder1”, incluído no contêiner com o id “contenu”

Uma página E encapsulada na página mestre M está contida no contêiner com o ID “ContentPlaceHolder1”. Para referenciar um componente com o ID C dessa página E, escrever-se-á:


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

A árvore de componentes da página [Erreurs.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 [Erreurs.aspx] é mesclada com a página mestre M, o conteúdo da tag <asp:Content> acima (linhas 5-16) é integrado à tag <asp:ContentPlaceHolder> com id “ContentPlaceholder1” da página M, ficando sua árvore de componentes da seguinte forma:

...
<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 [rptErreurs] pode ser usado para verificar se a página mestre M contém ou não a página [Erreurs.aspx]. De fato, esse componente existe apenas nessa página.

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


protected void Page_Init(object sender, System.EventArgs e)
        {
            // gerenciador de eventos 
            LinkButtonTerminerSession.Click += LinkButtonTerminerSession_Click;
            // erros de inicialização? 
            if (Global.Erreur)
            {
                // a página encapsulada é a página de erros? 
                bool isPageErreurs = this.FindControl("form1").FindControl("contenu").FindControl("ContentPlaceHolder1").FindControl("rptErreurs") != null;
                // se for a página de erros que estiver sendo exibida, deixamos como está; caso contrário, redirecionamos o cliente para a página de erros 
                if (!isPageErreurs)
                    Response.Redirect("Erreurs.aspx");
                return;
            }
        }
  • linha 4: associa-se um manipulador de evento ao evento Click no link LinkButtonTerminerSession. Esse manipulador está na classe MasterPage.
  • linha 6: verifica-se se a classe [Global] definiu seu valor booleano Erreur
  • linha 9: se sim, o booleano IsPageErreurs indica se a página encapsulada na página mestre é a página [Erreurs.aspx]
  • linha 12: se a página encapsulada na página mestre não for a página [Erreurs.aspx], então o cliente é redirecionado para essa página; caso contrário, nada é feito.

Quando o usuário clica no link [Terminer la session] na visualização (1) acima, é necessário esvaziar o conteúdo da sessão e apresentar um formulário vazio (2).

O código do manipulador desse evento poderia ser o seguinte:


        protected void LinkButtonTerminerSession_Click(object sender, System.EventArgs e)
        {
            // a sessão é encerrada 
            Session.Abandon();
            // exibe-se a visualização [formulaire] 
            Response.Redirect("Formulaire.aspx");
}
  • linha 4: a sessão atual é encerrada
  • linha 6: o cliente é redirecionado para a página [Formulaire.aspx]

Percebe-se que esse código não envolve nenhum dos componentes das páginas [Formulaire.aspx, Simulations.aspx, Erreurs.aspx]. O evento pode, portanto, ser gerenciado pela própria página mestre.

11.5.3. Código de controle da página [Erreurs.aspx]

O código de controle da página [Erreurs.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)
    {
      // erros de inicialização? 
      if (Global.Erreur)
      {
        // prepara-se o modelo da página [erreurs] 
        List<string> erreursInitialisation = new List<string>();
        erreursInitialisation.Add(Global.Msg);
        // associa-se a lista de erros ao respectivo componente 
        rptErreurs.DataSource = erreursInitialisation;
        rptErreurs.DataBind();
      }
      // definindo o menu 
      Master.SetMenu(false, false, false, false, false, false);
    }
  }
}

Vale lembrar que a página [Erreurs.aspx] tem como única função exibir um erro de inicialização do aplicativo quando este ocorre:

  • linha 10: verifica-se se a inicialização terminou com um erro
  • linhas 13-14: se sim, a mensagem de erro (Global.Msg) é inserida em uma lista [ErreursInitialisation]
  • linhas 16-17: solicita-se ao componente [rptErreurs] que exiba essa 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, de modo que o usuário não pode iniciar nenhuma nova ação a partir dessa página.

O que acontece se o usuário acessar diretamente a página [Erreurs.aspx] (o que não deve ocorrer no uso normal do aplicativo)? Ao analisar o código das páginas [MasterPage.master.cs] e [Erreurs.aspx.cs], percebe-se que:

  • se houver um erro de inicialização, ele é exibido
  • se não houver erro de inicialização, o usuário recebe uma página contendo apenas o cabeçalho de [MasterPage.master], sem nenhuma opção de menu exibida.

11.5.4. Código de controle da página [Formulaire.aspx]

11.5.4.1. Estrutura da classe

A estrutura do código de controle da página [Formulaire.aspx] poderia ser a seguinte:


using Pam.Metier.Entites;
...

partial class PageFormulaire : System.Web.UI.Page
{

    // carregamento da página 
    protected void Page_Load(object sender, System.EventArgs e)
    {
        // gerenciador de eventos
        Master.OptionFaireSimulation.Click += OptFaireSimulation_Click;
        Master.OptionEffacerSimulation.Click += OptEffacerSimulation_Click;
        Master.OptionVoirSimulations.Click += OptVoirSimulations_Click;
        Master.OptionEnregistrerSimulation.Click += OptEnregistrerSimulation_Click;
....
    }

    // cálculo da folha de pagamento 
    private void OptFaireSimulation_Click(object sender, System.EventArgs e)
    {
....
    }

    // apagar a simulação 
    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 controle da página [Formulaire.aspx] gerencia cinco eventos:

  1. o evento Load da página
  2. o evento Click no link [LinkButtonFaireSimulation] da página mestre
  3. o evento Click no link [LinkButtonEffacerSimulation] da página mestre
  4. o evento Click no link [LinkButtonEnregistrerSimulation] da página mestre
  5. o evento Click no link [LinkButtonVoirSimulations] da página mestre

11.5.4.2. Evento de carregamento da página

O esboço do gerenciador do evento Load da página poderia ser o seguinte:


    protected void Page_Load(object sender, System.EventArgs e)
    {
        // gerenciador de eventos
        Master.OptionFaireSimulation.Click += OptFaireSimulation_Click;
        Master.OptionEffacerSimulation.Click += OptEffacerSimulation_Click;
        Master.OptionVoirSimulations.Click += OptVoirSimulations_Click;
        Master.OptionEnregistrerSimulation.Click += OptEnregistrerSimulation_Click;
        // exibição da visualização [saisies] 
        ...
        // posicionamento do menu da página mestre 
        ...
        // processamento de consulta GET 
        if (!IsPostBack)
        {
            // carregamento dos nomes dos funcionários na lista suspensa 
...
            // inicialização da visualização [saisies] com os dados inseridos armazenados na sessão, caso existam 
....
        }
}

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

  • em [1], solicita-se a exibição da lista de simulações. Foram feitas entradas em [A, B, C].
  • em [2], é exibida a lista
  • em [3], solicita-se o retorno ao formulário
  • em [4], o formulário é exibido exatamente como foi deixado. Como houve duas solicitações, (1,2) e (3,4), isso significa que:
    • ao passar de [1] para [2], os dados inseridos em [1] foram armazenados
    • ao passar de [3] para [4], elas foram restauradas. É o procedimento [Page_Load] de [Formulaire.aspx] que realiza essa restauração.

Pergunta: complete o procedimento Page_Load com a ajuda dos comentários e do código da versão [pam-v4-3tier-nhibernate-multivues-monopage]


A estrutura dos gerenciadores de eventos Click para os links da página principal é a seguinte:


// cálculo da folha de pagamento 
    private void OptFaireSimulation_Click(object sender, System.EventArgs e)
    {
        // efeito Ajax
        Thread.Sleep(3000);
        // página válida? 
        Page.Validate();
        if (!Page.IsValid)
        {
            // exibição da visualização [saisie] 
...
        }
        // a página é válida — recuperamos os dados inseridos 
...
        // calcula-se o salário do funcionário 
        FeuilleSalaire feuillesalaire;
        try
        {
            feuillesalaire = ...;
        }
        catch (PamException ex)
        {
            // ocorreu um problema 
...
            return;
        }
        // o resultado é armazenado na sessão 
        Session["simulation"] = ...;
        // as entradas são armazenadas na sessão 
...
        // exibição 
...
        // exibição de visualizações 
...
        // exibição do menu MasterPage 
...
    }

    // apagar a simulação 
    private void OptEffacerSimulation_Click(object sender, System.EventArgs e)
    {
        // exibição do painel [saisie] 
...
        // seleção do primeiro funcionário 
...
    }

    protected void OptVoirSimulations_Click(object sender, System.EventArgs e)
    {
        // insere-se as entradas na sessão 
...
        // exibe-se a visualização [simulations] 
        Response.Redirect("simulations.aspx");
    }

    protected void OptEnregistrerSimulation_Click(object sender, System.EventArgs e)
    {
        // salva-se a simulação atual na sessão do usuário 
...
        // exibe-se a visualização [simulations] 
        Response.Redirect("simulations.aspx");
}

Pergunta: complete o código dos procedimentos acima com a ajuda dos comentários e do código da versão [pam-v4-3tier-nhibernate-multivues-monopage]


11.5.5. Código de controle da página [Simulations.aspx]

A estrutura do código de controle da página [Simulations.aspx] poderia ser a seguinte:


using System.Collections.Generic;
using Pam.Web;
using System.Web.UI.WebControls;

partial class PageSimulations : System.Web.UI.Page
{

    // as simulações 
    private List<Simulation> simulations;

    // carregamento da página
    protected void Page_Load(object sender, System.EventArgs e)
    {
        // gerenciador de eventos 
        Master.OptionFormulaireSimulation.Click += OptFormulaireSimulation_Click;
        GridViewSimulations.RowDeleting += GridViewSimulations_RowDeleting;
        // recuperando as simulações da sessão
        simulations = ...;
        // há simulações? 
        if (simulations.Count != 0)
        {
            // primeira visualização exibida 
            ...
            // preenchimento do GridView 
            ...
        }
        else
        {
            // segunda visualização 
            ...
        }
        // definindo o menu 
        ...
    }

    protected void GridViewSimulations_RowDeleting(object sender, System.Web.UI.WebControls.GridViewDeleteEventArgs e)
    {
        // recuperando as simulações na sessão
        List<Simulation> simulations = ...;
        // exclui-se a simulação indicada (e.RowIndex representa o número da linha excluída no GridView)
        ..
        // Ainda há simulações? 
        if (simulations.Count != 0)
        {
            // preenche-se a visualização em grade 
            ...
        }
        else
        {
            // visualização [SimulationsVides] 
            ...
        }
    }

    protected void OptFormulaireSimulation_Click(object sender, System.EventArgs e)
    {
        // exibe-se a visualização [formulaire] 
        Response.Redirect("formulaire.aspx");
    }

}

Pergunta: complete o código dos procedimentos acima com a ajuda dos comentários e do código da versão [pam-v4-3tier-nhibernate-multivues-monopage]


11.5.6. Código de controle da página [Default.aspx]

É possível prever uma página [Default.aspx] no aplicativo, a fim de permitir que o usuário solicite o URL do aplicativo sem especificar uma página, conforme mostrado abaixo:

A solicitação [1] recebeu como resposta a página [Formulaire.aspx] (2). Sabe-se que a solicitação (1) é processada, por padrão, pela página [Default.aspx] do aplicativo. Para obter (2), basta que [Default.aspx] redirecione o cliente para a página [Formulaire.aspx]. Isso pode ser feito com o seguinte código:


partial class _Default : System.Web.UI.Page
{

    protected void Page_Init(object sender, System.EventArgs e)
    {
        // redireciona para o formulário de preenchimento 
        Response.Redirect("Formulaire.aspx");
    }
}

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


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