Simple PIM – Exemplo Nova Classe de Conexão – Parte 3: Web User Interface
Olá! E aí, após modelarmos o banco de dados, construir a biblioteca de classes e uma “quebra de gelo” com a Americanas anunciando GeForce 2 à 1500 Reais em pleno 2009 (Nem Radeon HD 4870 custa isso!), vamos à penúltima parte (na verdade, a última no que se refere a códigos hehe) da construção do nosso Simple PIM (Personal Information Manager), onde iremos construir sua interface web.
A Interface Web será construída em apenas uma página (Single Page Application), sendo TODOS os cadastros implementados através de janelas modais, utilizando mais uma vez a ótima biblioteca jQuery e seu plugin jqModal.
Vamos ver com mais carinho aquele screenshot da solution da segunda parte agora? (após o break ;-) )
Separamos, em diretórios, os arquivos conforme o seu tipo:
Bin: Arquivos compilados, bibliotecas de classe.
css: Folhas de estilo, para a formatação dos elementos da UI.
javascript: Arquivos de script em JavaScript.
imagens: Imagens que farão parte do sistema (neste, particularmente, não coloquei imagens).
Na raíz, encontram-se o web.config, a master page (sim, embora tenha apenas uma página, preferi utilizar master pages neste projeto) e o index.aspx, que é onde tudo acontece.
Vamos primeiro olhar a parte de design:
1: <%@ Page Language="C#" MasterPageFile="~/principal.master" AutoEventWireup="true"
2: CodeFile="index.aspx.cs" Inherits="index" Title="Simple PIM by NeoMatrix Tech" %>
3:
4: <asp:Content ID="Content1" ContentPlaceHolderID="ContentPlaceHolder1" runat="Server">
5: <div>
6: <asp:UpdatePanel runat="server" ID="updGeral">
7: <ContentTemplate>
8: <div style="width:100%;text-align:center">
9: <span class="fonte-peq">Escolha o módulo desejado:</span>
10: <asp:DropDownList runat="server" ID="ddlEscolheMod" CssClass="tbx-normal" AutoPostBack="true"
11: OnSelectedIndexChanged="ddlEscolheMod_SelectedIndexChange">
12: <asp:ListItem Value="1" Text="Cadastro de Contatos"></asp:ListItem>
13: <asp:ListItem Value="2" Text="Cadastro de Formas de Contato"></asp:ListItem>
14: </asp:DropDownList>
15: </div>
16: <hr />
17: <asp:Panel runat="server" ID="pnlCadContato">
18: <div style="text-align:center;width:100%;">
19: <asp:Button runat="server" ID="btnFiltrarContato" Text="Filtrar" OnClick="btnFiltrarContato_Click" CssClass="botoes" />
20: <asp:Button runat="server" ID="btnNovoContato" Text="Novo Contato" OnClick="btnNovo_Click" CssClass="botoes" CommandArgument="TContato,0,dvDetContato" /><br />
21: </div>
22: <br />
23: <asp:GridView runat="server" ID="grdContatos" AutoGenerateColumns="false" DataKeyNames="Id" Width="100%">
24: <RowStyle CssClass="grid-normalitem" />
25: <HeaderStyle CssClass="grid-header" />
26: <Columns>
27: <asp:BoundField HeaderText="Nome" DataField="Nome" />
28: <asp:BoundField HeaderText="Sobrenome" DataField="Sobrenome" />
29: <asp:BoundField HeaderText="Dt. Nascimento" DataField="DtNascimento" DataFormatString="{0:dd/MM/yyyy}" />
30: <asp:BoundField HeaderText="Sexo" DataField="Sexo" />
31: <asp:BoundField HeaderText="Profissão" DataField="Profissao" />
32: <asp:TemplateField>
33: <ItemTemplate>
34: <asp:Button runat="server" ID="btnEditarContato" Text="Editar" CommandArgument='<%#Bind("Id","TContato,{0},dvDetContato")%>'
35: OnClick="btnEditar_Click" CssClass="botoes-grid" />
36: <asp:Button runat="server" ID="btnExcluirContato" Text="Excluir" CommandArgument='<%#Bind("Id","TContato,{0},dvDetContato")%>' CssClass="botoes-grid" OnClick="btnExcluir_Click" />
37: </ItemTemplate>
38: </asp:TemplateField>
39: </Columns>
40: </asp:GridView>
41: </asp:Panel>
42: <asp:Panel runat="server" ID="pnlCadFC" Visible="false">
43: <div style="text-align:center;width:100%;">
44: <asp:Button runat="server" ID="btnFiltrarTFC" Text="Filtrar" OnClick="btnFiltrarTFC_Click" CssClass="botoes" />
45: <asp:Button runat="server" ID="btnNovoTFC" Text="Novo Tipo de Forma de Contato" OnClick="btnNovo_Click" CssClass="botoes" CommandArgument="TTpFormaContato,0,dvDetTpFormaContato" /><br />
46: </div>
47: <br />
48: <asp:GridView runat="server" ID="grdTipoFC" AutoGenerateColumns="false" DataKeyNames="Id" Width="100%">
49: <RowStyle CssClass="grid-normalitem" />
50: <HeaderStyle CssClass="grid-header" />
51: <Columns>
52: <asp:BoundField HeaderText="Descrição" DataField="Descricao" />
53: <asp:TemplateField>
54: <ItemTemplate>
55: <asp:Button runat="server" ID="btnEditarTFC" Text="Editar" CommandArgument='<%#Bind("Id","TTpFormaContato,{0},dvDetTpFormaContato")%>'
56: OnClick="btnEditar_Click" CssClass="botoes-grid" />
57: <asp:Button runat="server" ID="btnExcluirTFC" Text="Excluir" CommandArgument='<%#Bind("Id","TTpFormaContato,{0},dvDetTpFormaContato")%>' CssClass="botoes-grid" OnClick="btnExcluir_Click" />
58: </ItemTemplate>
59: </asp:TemplateField>
60: </Columns>
61: </asp:GridView>
62: </asp:Panel>
63: </ContentTemplate>
64: </asp:UpdatePanel>
65: </div>
66: <div id="dvDetContato" class="jqmWindow" style="overflow: auto; width: 700px; height: 500px;">
67: <asp:UpdatePanel runat="server" ID="updContatos">
68: <ContentTemplate>
69: <div class="titulos-secao">
70: <span>Detalhes do Contato</span>
71: </div>
72: <div style="width: 80px; float: left">
73: <span class="fonte-peq">Código</span><br />
74: <asp:TextBox ID="tbxTContatoId" runat="server" CssClass="tbx-ro" Width="70px" ReadOnly="true"></asp:TextBox>
75: </div>
76: <div style="width: 250px; float: left">
77: <span class="fonte-peq">Nome</span><br />
78: <asp:TextBox ID="tbxTContatoNome" runat="server" CssClass="tbx-normal" Width="240px"></asp:TextBox>
79: </div>
80: <div style="width: 250px; float: none;">
81: <span class="fonte-peq">Sobrenome</span><br />
82: <asp:TextBox ID="tbxTContatoSobrenome" runat="server" CssClass="tbx-normal" Width="240px"></asp:TextBox>
83: </div>
84: <div style="width: 150px; float: left;">
85: <span class="fonte-peq">Data de Nascimento</span><br />
86: <asp:TextBox ID="tbxTContatoDtNascimento" runat="server" CssClass="tbx-normal" Width="90px"></asp:TextBox>
87: </div>
88: <div style="width: 160px; float: left;">
89: <span class="fonte-peq">SEXO</span><br />
90: <asp:DropDownList ID="ddlTContatoSexo" runat="server" CssClass="tbx-normal" Width="150px">
91: <asp:ListItem Value="M" Text="MASC."></asp:ListItem>
92: <asp:ListItem Value="F" Text="FEM."></asp:ListItem>
93: <asp:ListItem Value="G" Text="GAY"></asp:ListItem>
94: <asp:ListItem Value="L" Text="LÉSBICA"></asp:ListItem>
95: <asp:ListItem Value="B" Text="BISSEXUAL"></asp:ListItem>
96: <asp:ListItem Value="T" Text="TRANSSEXUAL"></asp:ListItem>
97: <asp:ListItem Value="E" Text="METROSSEXUAL"></asp:ListItem>
98: </asp:DropDownList>
99: </div>
100: <div style="width: 160px; float: left;">
101: <span class="fonte-peq">RG</span><br />
102: <asp:TextBox ID="tbxTContatoRg" runat="server" CssClass="tbx-normal" Width="150px"></asp:TextBox>
103: </div>
104: <div style="width: 160px; float: none">
105: <span class="fonte-peq">CPF</span><br />
106: <asp:TextBox ID="tbxTContatoCpf" runat="server" CssClass="tbx-normal" Width="150px"></asp:TextBox>
107: </div>
108: <div style="width: 160px; float: left;">
109: <span class="fonte-peq">CNH</span><br />
110: <asp:TextBox ID="tbxTContatoCnh" runat="server" CssClass="tbx-normal" Width="150px"></asp:TextBox>
111: </div>
112: <div style="width: 250px; float: none">
113: <span class="fonte-peq">PROFISSAO</span><br />
114: <asp:TextBox ID="tbxTContatoProfissao" runat="server" CssClass="tbx-normal" Width="240px"></asp:TextBox>
115: </div>
116: <br />
117: <div style="text-align:center;background-color:Black;width:100%;">
118: <asp:Button runat="server" ID="btnSalvarDetContato" Text="Salvar Contato" OnClick="btnSalvarDetContato_Click" CssClass="botoes" />
119: <asp:Button runat="server" ID="btnFecharDetContato" Text="Fechar" OnClientClick="$dvDetContato.jqmHide(); return false;" CssClass="botoes" />
120: </div>
121: <br />
122: <div style="border: solid 1px black; height: 200px; width: 100%; overflow: auto;">
123: <div class="titulos-secao">
124: <span>Endereços</span>
125: </div>
126: <div style="width:100%;text-align:center;">
127: <asp:Button runat="server" ID="btnNovoEndereco" Text="Novo Endereço" OnClick="btnNovo_Click" CssClass="botoes" CommandArgument="TEndereco,0,dvDetEndereco" />
128: </div>
129: <br />
130: <asp:GridView runat="server" ID="grdTContatoListaEnderecos" AutoGenerateColumns="false"
131: DataKeyNames="Id" Width="100%">
132: <RowStyle CssClass="grid-normalitem" />
133: <HeaderStyle CssClass="grid-header" />
134: <Columns>
135: <asp:BoundField HeaderText="Logradouro" DataField="Logradouro" />
136: <asp:BoundField HeaderText="Numero" DataField="Numero" />
137: <asp:BoundField HeaderText="Cidade" DataField="Cidade" />
138: <asp:BoundField HeaderText="Estado" DataField="Estado" />
139: <asp:TemplateField>
140: <ItemTemplate>
141: <asp:Button runat="server" ID="btnEditarEndereco" Text="Editar" CommandArgument='<%#Bind("Id","TEndereco,{0},dvDetEndereco")%>'
142: OnClick="btnEditar_Click" CssClass="botoes-grid" />
143: <asp:Button runat="server" ID="btnExcluirEndereco" Text="Excluir" CommandArgument='<%#Bind("Id","TEndereco,{0},dvDetEndereco")%>' CssClass="botoes-grid" OnClick="btnExcluir_Click"/>
144: </ItemTemplate>
145: </asp:TemplateField>
146: </Columns>
147: </asp:GridView>
148: </div>
149: <br />
150: <div style="border: solid 1px black; height: 200px; width: 100%; overflow: auto;">
151: <div class="titulos-secao">
152: <span>Formas de Contato</span>
153: </div>
154: <div style="text-align:center;width:100%;">
155: <asp:Button runat="server" ID="btnNovoFormaContato" Text="Nova Forma de Contato"
156: OnClick="btnNovo_Click" CssClass="botoes" CommandArgument="TFormaContato,0,dvDetFormaContato" />
157: </div>
158: <asp:GridView runat="server" ID="grdTContatoListaFormaContato" AutoGenerateColumns="false"
159: DataKeyNames="Id" Width="100%">
160: <RowStyle CssClass="grid-normalitem" />
161: <HeaderStyle CssClass="grid-header" />
162: <Columns>
163: <asp:BoundField HeaderText="Forma de Contato" DataField="DescricaoFormaContato" />
164: <asp:BoundField HeaderText="Valor" DataField="Valor" />
165: <asp:TemplateField>
166: <ItemTemplate>
167: <asp:Button runat="server" ID="btnEditarFC" Text="Editar" CommandArgument='<%#Bind("Id","TFormaContato,{0},dvDetFormaContato")%>'
168: OnClick="btnEditar_Click" CssClass="botoes-grid" />
169: <asp:Button runat="server" ID="btnExcluirFC" Text="Excluir" CommandArgument='<%#Bind("Id","TFormaContato,{0},dvFormaDetContato")%>' CssClass="botoes-grid" OnClick="btnExcluir_Click"/>
170: </ItemTemplate>
171: </asp:TemplateField>
172: </Columns>
173: </asp:GridView>
174: </div>
175: </ContentTemplate>
176: </asp:UpdatePanel>
177: </div>
178: <div id="dvDetEndereco" class="jqmWindow" style="z-index: 3001;">
179: <asp:UpdatePanel runat="server" ID="updDetEndereco">
180: <ContentTemplate>
181: <div class="titulos-secao">
182: <span>Detalhes do Endereço</span>
183: </div>
184: <!-- A classe TContato é a que irá setar este campo, a PK da tabela de Endereços aponta para ele -->
185: <input type="hidden" id="hdfTContatoId" runat="server" />
186: <div style="width: 160px;">
187: <span class="fonte-peq">ID</span><br />
188: <asp:TextBox ID="tbxTEnderecoId" runat="server" CssClass="tbx-ro" Width="150px" ReadOnly="true"></asp:TextBox>
189: </div>
190: <div style="width: 160px;">
191: <span class="fonte-peq">Tipo de Logradouro</span><br />
192: <asp:DropDownList ID="ddlTEnderecoTipoLogradouro" runat="server" CssClass="tbx-normal"
193: Width="150px">
194: <asp:ListItem Text="Rua" Value="R"></asp:ListItem>
195: <asp:ListItem Text="Avenida" Value="AV"></asp:ListItem>
196: <asp:ListItem Text="Alameda" Value="AL"></asp:ListItem>
197: <asp:ListItem Text="Travessa" Value="TV"></asp:ListItem>
198: <asp:ListItem Text="Beco" Value="B"></asp:ListItem>
199: <asp:ListItem Text="Praça" Value="PC"></asp:ListItem>
200: <asp:ListItem Text="Rodovia" Value="ROD"></asp:ListItem>
201: </asp:DropDownList>
202: </div>
203: <div style="width: 210px; float: left;">
204: <span class="fonte-peq">Logradouro</span><br />
205: <asp:TextBox ID="tbxTEnderecoLogradouro" runat="server" CssClass="tbx-normal" Width="200px"></asp:TextBox>
206: </div>
207: <div style="width: 160px; float: left;">
208: <span class="fonte-peq">Número</span><br />
209: <asp:TextBox ID="tbxTEnderecoNumero" runat="server" CssClass="tbx-normal" Width="150px"></asp:TextBox>
210: </div>
211: <div style="width: 160px; float: none;">
212: <span class="fonte-peq">Complemento</span><br />
213: <asp:TextBox ID="tbxTEnderecoComplemento" runat="server" CssClass="tbx-normal" Width="150px"></asp:TextBox>
214: </div>
215: <div style="width: 160px; float: left;">
216: <span class="fonte-peq">Cep</span><br />
217: <asp:TextBox ID="tbxTEnderecoCep" runat="server" CssClass="tbx-normal" Width="150px"></asp:TextBox>
218: </div>
219: <div style="width: 300px; float: none;">
220: <span class="fonte-peq">Bairro</span><br />
221: <asp:TextBox ID="tbxTEnderecoBairro" runat="server" CssClass="tbx-normal" Width="290px"></asp:TextBox>
222: </div>
223: <div style="width: 260px; float: left;">
224: <span class="fonte-peq">Cidade</span><br />
225: <asp:TextBox ID="tbxTEnderecoCidade" runat="server" CssClass="tbx-normal" Width="250px"></asp:TextBox>
226: </div>
227: <div style="width: 40px; float: none;">
228: <span class="fonte-peq">UF</span><br />
229: <asp:TextBox ID="tbxTEnderecoEstado" runat="server" CssClass="tbx-normal" Width="30px"
230: MaxLength="2"></asp:TextBox>
231: </div>
232: <div style="text-align:center;width:100%;">
233: <asp:Button runat="server" ID="btnSalvaEndereco" Text="Salvar" OnClick="btnSalvaEndereco_Click" CssClass="botoes" />
234: <asp:Button runat="server" ID="btnFecharEndereco" Text="Fechar" OnClientClick="$dvDetEndereco.jqmHide();return false;" CssClass="botoes" />
235: </div>
236: </ContentTemplate>
237: </asp:UpdatePanel>
238: </div>
239: <div id="dvDetFormaContato" class="jqmWindow" style="z-index: 3001;">
240: <asp:UpdatePanel runat="server" ID="updDetFC">
241: <ContentTemplate>
242: <div class="titulos-secao">
243: <span>Detalhes da Forma de Contato</span>
244: </div>
245: <input type="hidden" id="hdfTFormaContatoContatoId" runat="server" />
246: <div style="width: 80px; float: left;">
247: <span class="fonte-peq">ID</span><br />
248: <asp:TextBox ID="tbxTFormaContatoId" runat="server" CssClass="tbx-normal" Width="70px"></asp:TextBox>
249: </div>
250: <div style="width: 210px; float: none;">
251: <span class="fonte-peq">Forma de Contato:</span><br />
252: <asp:DropDownList ID="ddlTFormaContatoTpFormaContatoId" runat="server" CssClass="tbx-normal"
253: Width="200px" DataTextField="Descricao" DataValueField="Id">
254: </asp:DropDownList>
255: </div>
256: <div style="width: 250px;">
257: <span class="fonte-peq">Valor:</span><br />
258: <asp:TextBox ID="tbxTFormaContatoValor" runat="server" CssClass="tbx-normal" Width="240px"></asp:TextBox>
259: </div>
260: <div style="width:100%;text-align:center;">
261: <asp:Button runat="server" ID="btnSalvaFC" Text="Salvar" OnClick="btnSalvaFC_Click" CssClass="botoes" />
262: <asp:Button runat="server" ID="btnFechaFC" Text="Fechar" OnClientClick="$dvDetFormaContato.jqmHide(); return false;" CssClass="botoes" />
263: </div>
264: </ContentTemplate>
265: </asp:UpdatePanel>
266: </div>
267: <div id="dvDetTpFormaContato" class="jqmWindow">
268: <asp:UpdatePanel runat="server" ID="updDetTpFC">
269: <ContentTemplate>
270: <div class="titulos-secao">
271: <span>Detalhes do Tipo de Forma de Contato</span>
272: </div>
273: <div style="width: 90px; float: left;">
274: <span class="fonte-peq">Cód.</span><br />
275: <asp:TextBox ID="tbxTTpFormaContatoId" runat="server" CssClass="tbx-normal" Width="80px"
276: ReadOnly="true"></asp:TextBox>
277: </div>
278: <div style="width: 210px; float: none;">
279: <span class="fonte-peq">Descrição</span><br />
280: <asp:TextBox ID="tbxTTpFormaContatoDescricao" runat="server" CssClass="tbx-normal"
281: Width="200px"></asp:TextBox>
282: </div>
283: <div style="text-align:center;width:100%;">
284: <asp:Button runat="server" ID="btnSalvaTFC" Text="Salvar"
285: OnClick="btnSalvaTFC_Click" CssClass="botoes" />
286: <asp:Button runat="server" ID="Button1" Text="Fechar" OnClientClick="$dvDetTpFormaContato.jqmHide(); return false;" CssClass="botoes" />
287: </div>
288: </ContentTemplate>
289: </asp:UpdatePanel>
290: </div>
291:
292: <script type="text/javascript">1:
2: //Inicializa os Modais3: var $dvDetContato = $('#dvDetContato').jqm({modal:true,toTop:true,trigger:false});4: var $dvDetEndereco = $('#dvDetEndereco').jqm({modal:true,toTop:true,trigger:false});5: var $dvDetFormaContato = $('#dvDetFormaContato').jqm({modal:true,toTop:true,trigger:false});6: var $dvDetTpFormaContato = $('#dvDetTpFormaContato').jqm({modal:true,toTop:true,trigger:false});7:
</script>
293:
294: </asp:Content>
Ele pode assustar por ser gigante, mas lembre-se: a aplicação toda está contida apenas nesta página.
Temos no final um bloco de JavaScript que faz a inicialização das janelas modais do nosso sistema, usando o jQuery.
A página é composta de cinco (5) div’s principais, que representam o cadastro. O primeiro, sem um ID, é o div que corresponde à grade de pesquisa e é a primeira coisa que é mostrada para o usuário quando o site é acessado.
Nesta página, fizemos o mesmo esquema que foi feito no Cadastro de Usuários em ASP.NET (lembra?), ou seja, a página principal corresponde a 2 cadastros: Cadastro de Contatos e Tipos de Forma de Contato, sendo alternados via combo-box.
As telas de visualização, inserção e alteração de dados são janelas modais, sendo o Cadastro de Contatos e o de Tipo de Forma de Contato pertencentes à página principal: são superpostas diretamente a esta.
Já o Cadastro de Endereços e Formas de Contato, pertencem ao Cadastro de Contatos, ou seja, cada endereço e forma de contato pertencem a um contato. Portanto, estas janelas são superpostas ao Cadastro de Contato.
Por causa disto, temos a maior particularidade do design desta página em relação ao Controle de Usuários: janela modal sobre outra janela modal.
Note que nos div’s dvDetEndereco e dvDetFormaContato temos explicitamente declarado o atributo z-index com o valor 3001.
Os div’s contendo o valor jqmWindow no atributo class são janelas modais. Esta classe CSS é utilizada pelo jqModal exatamente para isso: definir os atributos das janelas modais.
O jqmWindow é definido dentro do arquivo jqModal.css, e nele, o atributo z-index padrão de cada modal é 3000.
Para obtermos a superposição de janelas modais, devemos declarar esta janela com um z-index MAIOR do que a modal que estará atrás dela. Como não dá para criar uma classe CSS para cada nível de modal, devemos sobreescrever o atributo z-index colocando-o diretamente na declaração do div a ser colocado em uma camada acima de outra.
Fazendo isso, o jqModal irá atribuir o z-index que declaramos explicitamente ao invés do z-index configurado na classe jqmWindow.
Hum… notaram mais alguma coisa de diferente aí? “O que é que você está passando no CommandArgument de cada botão Novo e nos Editar e Excluir dos grids? Antes você só passava a chave do registro…”.
Vamos ver isso analisando o code-behind:
1: using System;
2: using System.Data;
3: using System.Configuration;
4: using System.Collections;
5: using System.Web;
6: using System.Web.Security;
7: using System.Web.UI;
8: using System.Web.UI.WebControls;
9: using System.Web.UI.WebControls.WebParts;
10: using System.Web.UI.HtmlControls;
11: using System.Runtime.Remoting;
12: using System.Reflection;
13: using SPIMCore;
14:
15: public partial class index : System.Web.UI.Page
16: {
17: protected void Page_Load(object sender, EventArgs e)
18: {
19: if (!IsPostBack)
20: {
21: ddlTFormaContatoTpFormaContatoId.DataSource = TTpFormaContato.ListarTodos();
22: ddlTFormaContatoTpFormaContatoId.DataBind();
23: }
24: }
25:
26: protected void ddlEscolheMod_SelectedIndexChange(object sender, EventArgs e)
27: {
28: pnlCadContato.Visible = (sender as DropDownList).SelectedValue.Equals("1");
29: pnlCadFC.Visible = (sender as DropDownList).SelectedValue.Equals("2");
30: }
31:
32: protected void RefreshGrids()
33: {
34: grdContatos.DataSource = TContato.ListarTodos();
35: grdContatos.DataBind();
36:
37: if (!tbxTContatoId.Text.Equals(""))
38: {
39: grdTContatoListaEnderecos.DataSource = TEndereco.ListarPorContato(Int32.Parse(tbxTContatoId.Text));
40: grdTContatoListaEnderecos.DataBind();
41:
42: grdTContatoListaFormaContato.DataSource = TFormaContato.ListarPorContato(Int32.Parse(tbxTContatoId.Text));
43: grdTContatoListaFormaContato.DataBind();
44: }
45:
46: grdTipoFC.DataSource = TTpFormaContato.ListarTodos();
47: grdTipoFC.DataBind();
48: }
49:
50: #region Rotnias Comuns a todos os botões dos Modais
51: /// <summary>
52: /// Botão Editar dos gridviews
53: /// </summary>
54: /// <param name="sender"></param>
55: /// <param name="e"></param>
56: protected void btnEditar_Click(object sender, EventArgs e)
57: {
58: string[] args = (sender as Button).CommandArgument.Split(new char[1] { ',' });
59: ObjectHandle clsCad = Activator.CreateInstance("SPIMCore", String.Format("SPIMCore.{0}", args[0]));
60: Type t = clsCad.Unwrap().GetType();
61: t.InvokeMember("SetByID", BindingFlags.InvokeMethod, null, clsCad.Unwrap(), new object[] { new object[1] { Int32.Parse(args[1]) } });
62: t.InvokeMember("BindToUI", BindingFlags.InvokeMethod, null, clsCad.Unwrap(), new object[] { this, this.GetType(), new ArrayList() });
63: string script = String.Format("${0}.jqmShow();", args[2]);
64: ScriptManager.RegisterStartupScript(this, this.GetType(), "abremodal", script, true);
65: }
66:
67: /// <summary>
68: /// Botão Novo
69: /// </summary>
70: /// <param name="sender"></param>
71: /// <param name="e"></param>
72: protected void btnNovo_Click(object sender, EventArgs e)
73: {
74: //Não permite o Bind de combo-boxes (PK's)
75: ArrayList notbind = new ArrayList();
76: notbind.Add("ddlTFormaContatoTpFormaContatoId");
77:
78:
79: string[] args = (sender as Button).CommandArgument.Split(new char[1] { ',' });
80: ObjectHandle clsCad = Activator.CreateInstance("SPIMCore", String.Format("SPIMCore.{0}", args[0]));
81: Type t = clsCad.Unwrap().GetType();
82: t.InvokeMember("BindToUI", BindingFlags.InvokeMethod, null, clsCad.Unwrap(), new object[] { this, this.GetType(), notbind });
83: string script = String.Format("${0}.jqmShow();", args[2]);
84: ScriptManager.RegisterStartupScript(this, this.GetType(), "abremodal", script, true);
85: }
86:
87: /// <summary>
88: /// Botão de Exclusão dos gridviews
89: /// </summary>
90: /// <param name="sender"></param>
91: /// <param name="e"></param>
92: protected void btnExcluir_Click(object sender, EventArgs e)
93: {
94: string[] args = (sender as Button).CommandArgument.Split(new char[1] { ',' });
95: ObjectHandle clsCad = Activator.CreateInstance("SPIMCore", String.Format("SPIMCore.{0}", args[0]));
96: Type t = clsCad.Unwrap().GetType();
97: t.InvokeMember("SetByID", BindingFlags.InvokeMethod, null, clsCad.Unwrap(), new object[] { new object[1] { Int32.Parse(args[1]) } });
98: t.InvokeMember("Delete", BindingFlags.InvokeMethod, null, clsCad.Unwrap(), null);
99:
100: PropertyInfo pi = t.GetProperty("MsgInfo");
101:
102: string script = Consts.JavaScript.Alert(Consts.Funcoes.Replacer4js(pi.GetValue(clsCad.Unwrap(), null).ToString()), false);
103: ScriptManager.RegisterStartupScript(this, this.GetType(), "abremodal", script, true);
104:
105: RefreshGrids();
106: }
107:
108: #endregion
109:
110: #region Detalhes do Contato
111: protected void btnSalvarDetContato_Click(object sender, EventArgs e)
112: {
113: TContato contato = new TContato();
114: string script = "";
115:
116: contato.BindFromUI(this, this.GetType(), new ArrayList());
117: bool ok = (tbxTContatoId.Text.Equals("") || tbxTContatoId.Text.Equals("0")) ? contato.Insert() : contato.Update();
118:
119: script += Consts.JavaScript.Alert(Consts.Funcoes.Replacer4js(contato.MsgInfo), false);
120: script += ok ? "$dvDetContato.jqmHide();" : "";
121: if (ok)
122: {
123: grdContatos.DataSource = TContato.ListarTodos();
124: grdContatos.DataBind();
125: }
126:
127: ScriptManager.RegisterStartupScript(this, this.GetType(), "salvacontato", script, true);
128: }
129:
130: protected void btnFiltrarContato_Click(object sender, EventArgs e)
131: {
132: grdContatos.DataSource = TContato.ListarTodos();
133: grdContatos.DataBind();
134: }
135: #endregion
136:
137: #region Modal de Endereços
138: protected void btnSalvaEndereco_Click(object sender, EventArgs e)
139: {
140: TEndereco endereco = new TEndereco();
141: string script = "";
142:
143: endereco.BindFromUI(this, this.GetType(), new ArrayList());
144: endereco.ContatoId = Int32.Parse(hdfTContatoId.Value); //o único que deve ser setado manualmente
145: bool ok = (tbxTEnderecoId.Text.Equals("") || tbxTEnderecoId.Text.Equals("0")) ? endereco.Insert() : endereco.Update();
146:
147: script += Consts.JavaScript.Alert(Consts.Funcoes.Replacer4js(endereco.MsgInfo), false);
148: script += ok ? "$dvDetEndereco.jqmHide();" : "";
149: if (ok)
150: {
151: grdTContatoListaEnderecos.DataSource = TEndereco.ListarPorContato(Int32.Parse(tbxTContatoId.Text));
152: grdTContatoListaEnderecos.DataBind();
153: }
154:
155: ScriptManager.RegisterStartupScript(this, this.GetType(), "salvacontato", script, true);
156: }
157: #endregion
158:
159: #region Modal de Formas de Contato
160:
161: protected void btnSalvaFC_Click(object sender, EventArgs e)
162: {
163: TFormaContato fc = new TFormaContato();
164: string script = "";
165:
166: fc.BindFromUI(this, this.GetType(), new ArrayList());
167: fc.ContatoId = Int32.Parse(tbxTContatoId.Text); //o único que deve ser setado manualmente
168: bool ok = (tbxTFormaContatoId.Text.Equals("") || tbxTFormaContatoId.Text.Equals("0")) ? fc.Insert() : fc.Update();
169:
170: script += Consts.JavaScript.Alert(Consts.Funcoes.Replacer4js(fc.MsgInfo), false);
171: script += ok ? "$dvDetFormaContato.jqmHide();" : "";
172: if (ok)
173: {
174: grdTContatoListaFormaContato.DataSource = TFormaContato.ListarPorContato(Int32.Parse(tbxTContatoId.Text));
175: grdTContatoListaFormaContato.DataBind();
176: }
177:
178: ScriptManager.RegisterStartupScript(this, this.GetType(), "salvafc", script, true);
179: }
180:
181: #endregion
182:
183: #region Modal de Tipos de Formas de Contato
184: protected void btnFiltrarTFC_Click(object sender, EventArgs e)
185: {
186: grdTipoFC.DataSource = TTpFormaContato.ListarTodos();
187: grdTipoFC.DataBind();
188: }
189:
190: protected void btnSalvaTFC_Click(object sender, EventArgs e)
191: {
192: TTpFormaContato tfc = new TTpFormaContato();
193: string script = "";
194:
195: tfc.BindFromUI(this, this.GetType(), new ArrayList());
196: bool ok = (tbxTTpFormaContatoId.Text.Equals("") || tbxTTpFormaContatoId.Text.Equals("0")) ? tfc.Insert() : tfc.Update();
197:
198: script += Consts.JavaScript.Alert(Consts.Funcoes.Replacer4js(tfc.MsgInfo), false);
199: script += ok ? "$dvDetTpFormaContato.jqmHide();" : "";
200: if (ok)
201: {
202: grdTipoFC.DataSource = TTpFormaContato.ListarTodos();
203: grdTipoFC.DataBind();
204: ddlTFormaContatoTpFormaContatoId.DataSource = TTpFormaContato.ListarTodos();
205: ddlTFormaContatoTpFormaContatoId.DataBind();
206: }
207:
208: ScriptManager.RegisterStartupScript(this, this.GetType(), "salvatfc", script, true);
209: }
210:
211: #endregion
212: }
Vamos direto no que você reparou de diferente ;-)
No nosso código, temos um region chamado “Rotinas comuns a todos os botões de modais”. É isso mesmo! o código contido nela é comum a todos os modais! E olha só, são exatamente os botões Novo, Editar e Excluir de cada cadastro :-)
No CommandArgument da cada botão, eu passo o seguinte, através do #Bind: Nome da Classe, Chave do Registro (que é passado no primeiro parâmetro do #Bind) e o Nome do Modal que esta janela abre. Isto é feito formatando-se o resultado do comando #Bind, sendo que onde está o “{0}” será substituído pelo valor do primeiro parâmetro do comando #Bind, no nosso caso, o campo Id da tabela.
Notaram que todos estes botões apontam para UMA única rotina em seu evento OnClick (uma para cada ação: novo, editar e excluir)? Porém eles manipulam classes diferentes!
Pois é, classes diferentes, porém concebidas da mesma maneira!
Estudando o evento OnClick do botão Editar, vemos que ele separa cada argumento (que separei por vírgula) em um array de string, a nossa variável args.
Temos depois disso a primeira novidade: instanciamos um objeto em tempo de execução!
Para isso, faremos uso do namespace System.Runtime.Remoting e das classes ObjectHandle e Activator.
A primeira é uma classe que armazena referências de objetos, e a segunda cria-os, basicamente.
Em uma instância de ObjectHandle (variável clsCad), criamos em tempo de execução uma instância da classe que passamos no CommandArgument do botão Novo. Para isso, utilizamos o método estático CreateInstance da classe Activator, que na sobrecarga que utilizei pede como parâmetros o nome do assembly onde esta classe se encontra e o nome completo da classe (o namespace e o nome da classe) e retorna uma instância de ObjectHandle, que contém a referência deste objeto que criamos. No índice zero da variável args, gravamos o nome da classe que pegamos no CommandArgument e utilizamos neste método.
Em seguida, pegamos as informações de tipo da classe criada em uma instância de uma classe Type. Note que não usei o método GetType() da classe clsCad diretamente: Se eu fizesse isso, o método GetType() iria me retornar as informações da classe ObjectHandle, e não da classe de cadastro que instanciei, e que está encapsulada neste objeto.
Para pegar as informações do objeto encapsulado em si, chamo o método Unwrap() do objeto clsCad, que aí sim, temos o nosso objeto de cadastro à disposição, e a partir dele chamo o GetType().
Com isso, chamaremos os métodos de exibição e atribução dos valores na UI através do método InvokeMember do nosso objeto Type.
O método InvokeMember pede como parâmetros o nome do método em questão, os BindingFlags, que no nosso caso utilizamos BindingFlags.InvokeMethod, o Binder padrão, que no nosso caso utilizamos null, o objeto em que o método será chamado, onde utilizamos a nossa variável clsCad com o método Unwrap(), e um array de object contendo os parâmetros para o método a ser chamado.
No método SetByID(), passamos como parâmetro um array de object contendo as chaves primárias do registro a ser mostrado. Ele é obtido através do índice 1 da variável args.
O método BindToUI() pede como parâmetros a página em que estão os controles a ser atribuídos, as informações de seu tipo e um arraylist indicando quais controles não serão atribuídos.
Para usar o BindToUI, necessitamos nomear cada componente seguindo a convenção: Prefixo de 3 letras, Nome da Classe e Nome da Propriedade.
Feito tudo isso, registramos um JavaScript com o comando para abrir a janela modal referente ao cadastro; janela esta que é passado no terceiro item da variável args.
Notem que TODAS as classes trabalham da mesma forma. Esta maneira de trabalhar e as convenções adotadas foi o que permitiu que escrevessemos um só trecho de código para quatro classes distintas.
Os botões Novo e Excluir trabalham da mesma maneira. A difereça entre eles é:
No botão Novo, criamos um ArrayList para não atribuirmos valor no combo-box de tipos de forma de contato do Cadastro de Formas de Contato de cada contato, pois como é inicializado um objeto SEM DADOS, o valor inicializado na propriedade correspondente possui algo que não existe no combo-box, e isso ocasiona um erro de execução.
No botão Excluir, após executarmos o método Delete() (dinamicamente!), pegamos o valor da propriedade MsgInfo através de um objeto PropertyInfo (que vimos anteriormente) e disparamos para o usuário.
Nos botões de Salvar temos as particularidades de cada classe, como o “refresh” dos grids e alguns campos de chave estrangeira que são atribuídos manualmente, sendo os outros atribuídos via método BindFromUI.
E por fim, terminamos a interface Web e fechamos a exemplificação dos métodos novos mais importantes da nova Classe de Conexão, e no próximo post tecerei algumas conclusões sobre o assunto.
Projeto de Exemplo da Classe de Conexão – Simple PIM (263 kB)
Um abraço!
0 comentários:
Postar um comentário