dezembro 2013 dezembro 2013 04 05 TvisualPlanit incrementado como base para turbinar um novo aplicativo – parte 1 Editorial Autor: Hamden Voguel Gerenciamento e Manipulação de Dados com Delphi 09 Autor: Jeferson Silva de Lima 18 ASP.NET MVC – Parte I Índice Autor: Luciano Pimenta 26 30 Dicas Delphi Desafio The Club dezembro 2013 03 Editorial Caro Leitor, Chegamos ao final de mais um ano e nossa equipe agradece cada associado por mais um ano de parceria com nosso clube. Cada ano que passa o The Club se torna mais forte e tudo isto devemos a vocês. Procuramos redigir uma revista com assuntos relevantes e sempre estando abertos a sugestões. Este mês, nosso colaborador Luciano Pimenta discute um assunto cada vez mais comum em nosso ramo, como devemos trabalhar com Asp.Net envolvendo conceitos de MVC (Model View Controller) . Para quem não sabe, MVC é um modelo de arquitetura de software que separa a representação da informação da interação do usuário com o mesmo. Esta primeira parte do artigo irá nos dar uma boa base para o aprendizado desta tecnologia. Hamden Vogel nos apresenta uma melhoria na palheta de componentes “TVisualPlanit”, nos componentes “TVpDayView”, “TVpMonthView”, “TVpContactGrid”. Artigo recomendado para quem deseja programar novos recursos em seus softwares. Nosso consultor técnico Jeferson Silva de Lima, com o artigo “Gerenciamento e Manipulação de Dados com Delphi”, nos ensina a manipular os dados dinamicamente tanto no contexto do desenvolvedor como de usuário utilizando o Delphi XE 2, indispensável para implementações alternativas ao decorrer do desenvolvimento de uma aplicação. Depois de um tempo, estamos voltando com a seção de dicas e truques de nossa revista. Neste mês possuímos dicas referentes ao Delphi e ao Sistema Android. Vou finalizando este editorial desejando a todos um Feliz Natal e que no próximo ano nossa parceria continue firme e forte como sempre. Av. Profº Celso Ferreira da Silva, 190 Jd. Europa - Avaré - SP - CEP 18.707-150 Informações e Suporte: (14) 3732-1529 Internet http://www.theclub.com.br Cadastro: [email protected] Suporte: [email protected] Informações: [email protected] Skype Cadastro: theclub_cadastro Skype Suporte: theclub_linha1 theclub_linha2 theclub_linha3 www.twitter.com/theclubbr Copyright The Club 2013 Diretor Técnico Marcos César Silva Diagramação Vitor M. Rodrigues Design Vitor M. Rodrigues Revisão Drielly Cristini Patrinhani Colunistas Hamden Vogel Jeferson Silva de Lima Luciano Pimenta Thiago Cavalheiro Montebugnoli Juninho Jeferson Silva de Lima Impressão e acabamento: GRIL - Gráfica e Editora Taquarituba-SP - Tel. (14) 3762-1345 Abraços Reprodução Thiago Montebugnoli - Editor Chefe [email protected] 04 dezembro 2013 A utilização, reprodução, apropriação, armazenamento em banco de dados, sob qualquer forma ou meio, de textos, fotos e outras criações intelectuais em cada publicação da revista “The Club Megazine” são terminantemente proibidos sem autorização escrita dos titulares dos direitos autorais. Delphi é marca registrada da Borland International, as demais marcas citadas são registradas pelos seus respectivos proprietários. TvisualPlanit incrementado como base para turbinar um novo aplicativo – parte 1 Q ue o Delphi contém componentes para mostrar e formatar dados do tipo data/hora, todo mundo sabe. Mas um grid associado a estas informações, exibindo no formato de uma agenda, com um look customizável e dinâmico (visual parecido com o MsOutlook) e com um gerenciamento completo de “dados por data” - imagine um calendário mensal junto com um outro diário, administrando seus eventos, contatos e lista de tarefas - pouca gente sabe. E ainda com mais incrementações, como exibição de feriados no calendário do componente, ativação de suas funções com um único clique do mouse (muito mais eficiente - porque por padrão a maioria das funções tem que dar um clique duplo), geração de calendário programado também dentro do componente (exemplo: um paciente quer ser atendido todas as terças-feiras no mesmo horário, a partir da semana que vem, durante um período de 6 meses) - aí creio que dessa forma automatizada não se tem registro para este componente ou então um outro similar com estas características. Aí vem a pergunta: porque não fazer? No caso, eu apresento o interessante pacote de componentes em object Pascal chamado VisualPlanit desenvolvido pela empresa TurboPower, concebido originariamente como produto comercial e hoje mantido como projeto opensource. Uma suíte de componentes realmente atrativa que automatiza procedimentos de data e hora com persistência de dados. E para ilustrar, que tal desenvolver uma aplicação que faz uso desta eficiente e conhecida tecnologia e com algumas alterações de minha parte, para melhorar ainda mais os processos internos do componente, somado ainda com algumas peculiaridades desta aplicação, como automatização da criação de seu banco de dados, novas técnicas para geração de relatórios e gráficos, registro da aplicação de trial para definitiva através de encriptação de uma senha armazenada no Regedit do Windows, e muito mais? Pois tudo isso será possível através da criação desta nossa nova aplicação de exemplo real, chamada ProAgendus - Uma Agenda para uma Clínica Psicológica. E aqui começamos o nosso trabalho - então mãos a obra! A nossa aplicação conterá algumas características fundamentais: Ela se “auto-conectará” com o nosso banco de dados através de um algoritmo próprio; Ela realizará procedimentos básicos e operacionais comuns a um processo de agendamento de uma clínica psicológica fictícia (aqui é utilizado o TVisualPlanit); Ela validará o seu registro, funcionando em modo experimental até que uma senha seja fornecida para sua liberação definitiva; Ela gerará relatórios e gráficos, com opções de exportação; Ela terá telas de cadastros necessários às realizações das atividades do processo. Entendendo a Aplicação: Primeiros Passos Para a criação da nossa aplicação serão necessários alguns componentes, listados abaixo: TVisualPlanit - OpenSource; DBISAM - Comercial; XPMenu - Freeware; TMaskeditHV - Freeware - Desenvolvido por mim; XPMenu - Freeware. O único que não é free nesta lista é o pacote DBISAM; trata-se de um banco de dados desenvolvido pela empresa ElevateSoft e que para utilizá-lo deve ser comprado por eles; entretanto pode-se baixar uma versão trial do mesmo. Ele é necessário porque será o responsável pelo armazenamento das informações (persistência) gerados pelo TVisualPlanit. Nós poderíamos utilizar outros bancos disponibilizados pelo componente, como o Paradox usando juntamente a BDE, mas para nossa melhor performance esse banco foi eleito por mim devido a sua eficiência e também por uma questão de gosto pessoal; já utilizei muito esse banco de dados e que o custo de distribuir uma aplicação com ele é zero, já que ele não necessita de nenhuma DLL ou Client para rodar junto com ele; entregando sua aplicação basta entregar apenas o executável e as tabelas (funciona como um sistema de arquivos, mas os índices dezembro 2013 05 são mantidos em memória). No nosso caso, para distribuir a aplicação iremos entregar apenas o executável: nossa aplicação criará o arquivo de conexão juntamente com as tabelas, onde o banco lerá um arquivo de configuração de onde apontará onde estarão as tabelas. Figura 01 - Fluxograma de Comunicação entre o ProAgendus e o Banco de Dados DBISAM. Primeiramente, é necessário compreender a lógica fundamental do programa de como ele se “auto-configura” para setar nosso banco de dados, criando e configurando pela primeira vez quando é chamado; podendo repetir essa mesma lógica sempre quando houver perda de configuração. O programa primeiramente acessa o arquivo “cfg.ini” onde tem o diretório do banco de dados (uma pasta “BD”); se não existir esse arquivo ini o programa mesmo o cria. Se o arquivo já existir, ele será lido para apontar o caminho do BD; se o caminho for inválido será procurado de dentro do diretório atual da aplicação em uma subpasta chamada BD, e se mesmo assim não existir o próprio banco será criado automaticamente (extraindo um arquivo zipado contendo o banco de dados e descompactando em uma subpasta no diretório atual do programa). Figura 02.1 - Uma parte da função que procura todos os arquivos do BD. Figura 03 - Tela Inicial do programa. Chegamos ao ponto que mais nos interessa, que é a interação com os componentes do pacote TVisualPlanit para geração de calendários no formato de consulta por hora para um modelo de clínica particular de atendimento psicológico. Aqui, vamos detalhar mais o funcionamento da aplicação. Tecnicamente falando, o TVisualPlanit utiliza a propriedade ControlLink (passando como referência um objeto TVpControlLink) para fazer o papel semelhante ao nosso conhecido TDataSource; fazendo então “uma ponte” entre os componentes de acesso aos dados com um dataset especificado. Funcionando assim: Figura 04 - Representação básica de como o TVisualPlanit se interage com o seu Banco de Dados utilizado. Não entrarei em muitos detalhes da arquitetura desenvolvida pela TurboPower, pois isso já está largamente documentado por ela e disponibilizado para download no site do sourceforge em: http://sourceforge.net Primeiras interações com o TVisualPlanit O nosso programa conterá apenas uma tela em que carregará todo o processamento do componente TVisualPlanit, que é a tela de Agendamento de Pacientes. Lá será feito toda a realização do processo. E lá serão exibidos seus principais componentes, que são: Figura 02 - Fluxograma de carregamento da aplicação. 06 dezembro 2013 TVpDayView: Exibe um calendário em formato de horas (horas de um dia selecionado); TVpMonthView: Exibe um calendário mensal. Lembra um pouco o componente TMonthCalendar da VCL; TVpContactGrid: Exibe todos os contatos de um usuário: de acordo com o TVisualPlanit cada usuário de uma aplicação possui um ResourceID que o identifica das outras persistências dos calendários. TVpTaskList: Exibe uma lista de tarefas (como um “to-do list” ou um simples bloco de anotações) onde o usuário anota qualquer coisa referente a aplicação ou à algum processo. DrawDays, utilizada internamente pelo componente TVpMonthView para o desenho, tamanho, altura e demais posições da string informando que é dia de feriado. Figura 05 - Tela de Marcação de Consultas (Agendamento), utilizando os componentes TVisualPlanit: da esquerda pra direita: TVpDayView, TVpMonthView, TVpContactGrid e finalmente o TVpTaskList. Os componentes mencionados acima foram todos alterados por mim. A alteração do TVpMonthView foi a de exibir feriados e a de realizar as operações principais do componente dando apenas um clique do mouse - (não é algo simples; um certo trecho do código-fonte teve que ser alterado) - porque por padrão tudo é ativado com um clique duplo; algo que incomoda se certas operações forem executadas com grande frequência (imagina uma clínica dentária de grande porte, onde para cada agendamento o usuário tivesse que dar dois cliques para chamar operações básicas do programa). Para verificar os feriados foi criada a seguinte função: IsHoliday (favor ver figura abaixo nº6) Figura 06 - Função IsHoliday; utilizada para verificar se o dia a ser impresso pelo componente TVpMonthView é um potencial dia de trabalho ou se é um dia de feriado. Figura 07 - Aplicação da função booleana IsHoliday chamada na procedure Figura 08 - Componente TVpMonthView mostrando informações sobre feriados. Pondo o Cadastramento de Sessões para funcionar na prática: A classe distribuída no pacote original do TVisualPlanit também foi modificada: a classe TDlgEventEdit, chamada para adicionar ou alterar sessões (registros que atualizarão o TVpDayView e o TVpMonthView) foi bastante alterada de modo a atender nossos novos requisitos; escolhe-se o paciente (que obtém da tabela de pacientes), dados do agendamento (se está marcado ou que depois foi desmarcado), plano de saúde e plano de agendamento. Essa última informação (plano de agendamento) pode ser customizada de modo a marcar como se fosse “pré-atendimentos”, ou seja, marcar um dia da semana para várias semanas ou meses. Se não fosse isso, o paciente teria que ser marcado de sessão em sessão, abrindo essa tela toda vez, tornando o trabalho maçante. Um exemplo: “paciente José quer atendimento toda terça, às 15:00 hrs” - com esse recurso bastaria preencher as opções do plano de agendamento, simplificando todo o processo. Figura 09 - Tela de Cadastramento de Sessões. dezembro 2013 07 Outros recursos interessantes: Além de marcar agendamentos, também é possível marcar tarefas, que nada mais é do que anotar qualquer evento em um personalidado “bloco de anotações”. Essa informação é também persistida em nosso banco, e salvando em formato data, assim como toda a lógica do componente, e podendo ter a opção de “terminar tarefa”. Esse componente é o TVpTaskList Essa tela também utiliza o componente que eu desenvolvi chamado TMaskeditHV, explicado em edições anteriores. Interessante nesta tela é que o paciente é vinculado ao seu plano de saúde, e em caso do plano não existir, ele pode ser acrescentado também. Ou seja, um cadastro pode ser editado de dentro de outro. Pessoalmente, o que mais gostei do processo de cadastro é que ele é chamado apenas com um clique do mouse, e que outras validações também foram adicionadas, como CEP por estado, email, estado e cidade. Conclusão Nesta primeira parte do artigo pudemos conferir alguns dos recursos implementados no pacote de componentes da “VisualPlanit”. Foram incrementadas melhorias nos componentes: “TVpDayView”, “TVpMonthView”, “TVpContactGrid”, entre outros. Também começamos desenvolver uma aplicação que coloca tudo que foi aprendido em prática. Encontramos-nos no mês que vem para darmos procedência a este assunto, um Abraço! Figura 10 - Tela de Anotações (tarefas a fazer). Tela de Manutenção de Contato Continuando, apresentaremos a tela de cadastro de contatos. Essa é a tela que mais sofreu modificação do componente original, pois foi acrescentada muitas informações que não tinham antes ou que tinham mas não atendia pessoalmente aos requisitos de qualidade e eficiência. Sobre o autor Hamden Vogel Analista de Sistemas pós-graduado em Engenharia de Software pela UPIS e Programador Delphi com larga experiência desde 2000, tem desenvolvido e vendido softwares em Delphi para a África e Estados Unidos, além do mercado nacional. Colaborou com dicas e componentes para sites especializados em Delphi. Também desenvolve em outras linguagens como C/C++, ASP, PHP e .NET. [email protected] Figura 11 - Tela de Cadastro de Contatos. Esses contatos serão utilizados para a marcação de consultas. 08 dezembro 2013 Gerenciamento e Manipulação de Dados com Delphi Q uando se trabalha com Delphi podemos a todo o momento utilizar funções e procedimentos que diversas bibliotecas nos disponibilizam, no entanto, em certas situações se torna necessário criar ações que atendam necessidades específicas. Neste contexto iniciaremos nosso artigo. O intuito é apresentar formas de manipular os dados dinamicamente tanto no contexto do desenvolvedor como de usuário, vamos utilizar o Delphi XE2 para o exemplo, porém, a funcionalidade pode ser aplicada para outras versões. Formulário Principal Inicie um novo projeto, File / New / VCL Forms Application - Delphi, nomeie o formulário criado como ‘fmPadrao’ salve a aplicação coloque o nome da Unit de ‘unPrincipal’ e o projeto vamos nomear de ‘Gerenciador’, após isso coloque o componente ‘MainMenu’ para que possamos criar nosso menu Principal. O menu deve ficar parecido com a imagem 1: Biblioteca de Funções Para que possamos prosseguir vamos criar nossa biblioteca de funções que será responsável por abrigar os comandos que iremos utilizar durante a execução da aplicação. Vá em File / New / Unit - Delphi, salve e nomeie o arquivo como ‘unFuncoes’, feito isto podemos iniciar nossa codificação. Nesta biblioteca os procedimentos serão responsáveis por realizar a criação de nossa tabela além da manipulação dos dados que serão inseridos. Em sua ‘Unit’ declare as bibliotecas que iremos utilizar, conforme listagem 1: Listagem 1 – Uses. Uses System.SysUtils, System. Classes, FMX.Dialogs, Vcl. Forms, Data.SqlExpr, Datasnap. DBClient, Data.DB, Vcl. StdCtrls, StrUtils; Nosso primeiro procedimento será responsável pela criação da tabela, segue codificação na listagem abaixo: Imagem 1 – Menu. Listagem 2 – Procedimento Criar Tabela. Imagem 2 – Tela Principal. procedure CriarTabela(Client: TClientDataSet; Campo: string; Tipo: TFieldType; Tamanho: Integer); begin if Tamanho = 0 then begin dezembro 2013 09 Client.FieldDefs.Add(Campo, Tipo); end else begin Client.FieldDefs.Add(Campo, Tipo, Tamanho, False); end; end; Veja que na criação da tabela adicionamos os campos com suas especificações, no entanto para que a tabela seja realmente criada devemos inserir o comando ‘ClientDataSet.CreateDataSet’, no entanto, a criação deve ser feita após adicionarmos todos os campos e por isso o comando deve ficar fora deste procedimento, ele será inserido em nosso formulário Base que veremos mais a frente. Com os campos inseridos no ‘ClientDataSet‘ já podemos inserir os dados em nossa tabela temporária, lembre-se os dados ficarão em nosso ‘Client’ dinâmico, ou seja, ainda não foram salvos no banco de dados. A listagem 3 demonstra a manipulação dos dados para que sejam passados de nosso ‘Client’ temporário para o terminante. Listagem 3 – Procedimento Inserir. procedure Inserir(Client: TClientDataSet; Formulario: TForm); var CdsCopia: TClientDataSet; I: Integer; begin CdsCopia := TClientDataSet. Create(Formulario); try CdsCopia.CloneCursor(TClien tDataSet(Client), True); Client.Append; for I := 0 to Client. FieldCount - 1 do begin Client.Fields[I].Value := CdsCopia.FieldByName(Client. Fields[I].FieldName).Value; end; finally CdsCopia.Close; CdsCopia.Free; end; end; 10 dezembro 2013 Para finalizar este processo devemos percorrer os registros de nosso ‘Client’ para efetuar a gravação em nossa base de dados, veja na listagem 4 como deve ser feito: Listagem 4 – Procedimento Salvar. procedure SalvarBD(ClientLocal, ClientBanco: TClientDataSet); var I: Integer; begin ClientLocal.First; while not ClientLocal.Eof do begin ClientBanco.Open; ClientBanco.Append; for I := 0 to ClientLocal. FieldCount - 1 do begin if ClientBanco.Fields[I]. Tag = 0 then begin ClientBanco.Fields[I]. Value := ClientLocal.Fields[I]. Value; end; end; ClientBanco.Post; ClientLocal.Next; end; end; Agora que os valores estão salvos apenas execute o ‘ApplyUpdates’ em nosso ‘Client’, veremos isto também em nosso formulário base. Você deve ter visto no inicio de nossa codificação alguns parâmetros que passamos em nosso procedimento de criação da tabela como, por exemplo: campo, tipo e tamanho. Para que esses parâmetros sejam passados corretamente criamos um procedimento chamado ‘LerCampos’ que irá pegar os campos descritos pelo usuário em um Memo e realizar a criação de nossa tabela, abaixo listagem 5 demonstra a leitura dos campos. Listagem 5 – Procedimento Ler Campos. procedure LerCampos(Client: TclientDataSet; Lista: TMemo); var I, Tamanho, Contar, Max: Integer; Campo, Valor, Varchar, Valorini: string; Tipo: TFieldType; begin for I := 0 to Lista.Lines. Count - 1 do begin Valorini := Lista.Lines[I]; Campo := Copy(Valorini, 1, Pos(‘-’, Valorini) - 2); Contar := Length(Campo) + 3; Delete(Valorini, 1, Contar); Valor := Valorini; Varchar := Copy(Valor, 1, Pos(‘(‘, Valor) - 1); if Varchar <> ‘’ then Valor := Varchar; case AnsiIndexStr(Valor, [‘Integer’, Varchar, ‘Char’, ‘Date’]) of 0: begin Tipo := ftInteger; Tamanho := 0; end; 1: begin Tipo := ftString; Max := Length(Valorini); Tamanho := StrToInt(Copy(Valorini, Pos(‘(‘, Valorini) + 1, Max Pos(‘(‘, Valorini) - 1)); end; 2: begin Tipo := ftString; Max := Length(Valorini); Tamanho := StrToInt(Copy(Valorini, Pos(‘(‘, Valorini) + 1, Max Pos(‘(‘, Valorini) - 1)); end; 3: begin Tipo := ftDate; Tamanho := 0; end; end; CriarTabela(Client, Campo, Tipo, Tamanho); end; end; end. Veja que neste exemplo estamos manipulando 4 tipos de dados (Integer, String, Char e date), no entanto, outros campos podem ser adicionados caso seja necessário. Utilizando o ‘Case AnsiIndexStr’ que já vimos em outros artigos, vamos direcionar os dados de acordo com seu tipo. No final do procedimento chamamos o ‘CriarTabela’ que irá conter todos os dados necessários para a criação da tabela. Formulário Base Com nossa biblioteca criada vamos iniciar a codificação de nosso formulário base. O layout do formulário deve ficar conforme imagem 3, veja que temos um ‘Memo’ no qual passamos o valor de nossos campos, ou seja, vamos ter apenas 1 formulário que será utilizado para todas as nossas tabelas. Imagem 3 – Formulário de Cadastro. Para que possamos cadastrar devemos além de indicar os campos apontarmos nossa tabela, veja que temos um ‘Combobox’ nele podemos encontrar a lista com nossas tabelas, na listagem 6 temos a codificação para listar as tabelas automaticamente. Listagem 6 – OnShow do Formulário. DM.Conexao. GetTableNames(cbProvider.Items, False); Lembre-se nossa codificação está na Unit ‘unTabela_Temp’ que é o nosso formulário base, ou seja, a Unit ‘unPadrao’ foi herdada e por isso iremos listar os procedimentos que foram feitos no formulário pai, mas que serão executados no formulário filho. Antes de iniciar verifique as Uses do Unit se estão conforme Listagem 7: Listagem 8 – Botão Criar Tabela. Uses Vcl.Forms, Vcl.ExtCtrls, Data. DB, Datasnap.DBClient, Vcl. Controls, Vcl.StdCtrls, Vcl. DBCtrls, Vcl.Grids, Vcl. DBGrids, System.Classes,FMX. dezembro 2013 11 Dialogs; Implementation Uses unFuncoes, unDM; Listagem 7 – Uses. No botão criar do formulário base coloque a codificação conforme listagem 8: procedure TfmBase. btnCriarTabelaClick(Sender: TObject); Var I: Integer; C: TComponent; Begin For I := 0 to ComponentCount - 1 do begin C := Components[I]; if C is TClientDataSet then begin LerCampos(TClientDataSet( C),Campos); TClientDataSet(C). CreateDataSet; TClientDataSet(C).Open; end; end; end; if C is TClientDataSet then begin TClientDataSet(C).Close; TClientDataSet(C). FieldDefs.Clear; end; end; cdsPadrao.ProviderName:= ‘dsp’+cbProvider.Text; end; Neste procedimento iremos limpar os dados nossos ‘Clients’ para que possamos indicar o nome do ‘DataSetProvider’, veja que deixamos padrão para que o nome inicie como ‘dsp’, portanto, lembre-se em seu ‘DataModule’ deixe o nome de seus ‘DataSetProviders’ iniciando com ‘dsp’ assim pegamos o nome da tabela conforme Listagem 6 que vimos anteriormente e adicionamos o ‘dsp. Imagem 4 – DataModule. Veja que nosso botão ‘Criar Tabela’ irá executar nosso procedimento feito na biblioteca de funções no qual passamos nosso ‘Client’ e o ‘Memo’ que nomeamos de ‘Campos’. Listagem 9 – Evento OnSelect ComboBox (cbProviderSelect). procedure TfmBase. cbProviderSelect(Sender: TObject); Var I: Integer; C: TComponent; Begin For I := 0 to ComponentCount - 1 do begin C := Components[I]; 12 dezembro 2013 Após indicarmos os campos, tabela e realizarmos a criação podemos inserir os dados. Portanto no evento ‘OnClick’ do ‘DbNavigator’ coloque a Listagem conforme abaixo: Listagem 10 – Evento OnClick DbNavigator. if dsDinamico.State = dsInsert then begin Inserir(cdsdinamico, fmBase); end; Neste evento chamamos o procedimento ‘Inserir’ que criamos anteriormente veja que passamos nosso ‘Client’ e o formulário ‘pai’ de nosso componente, ou seja, o formulário base. Com os dados inseridos e gravados em memória podemos efetuar a gravação em nosso banco de dados, Listagem 11 – Botão Salvar. procedure TfmBase. btnSalvarClick(Sender: TObject); begin SalvarBD(cdsdinamico, cdsPadrao); ShowMessage(‘Arquivos Salvos com Sucesso!’); end; Para efetuar a gravação em nosso banco executamos o procedimento ‘SalvarBD’ que irá transferir os dados salvos em memória (cdsdinamico) para nosso banco de dados (cdspadrao). Para finalizar a gravação devemos executar o comando ‘ApplyUpdates’ em nosso ‘cdsPadrao’, veja na listagem 12: Listagem 14 – Botão Fechar Tabela. procedure TfmBase. btnFecharTabelaClick(Sender: TObject); Var I: Integer; C: TComponent; Begin For I := 0 to ComponentCount - 1 do begin C := Components[I]; if C is TClientDataSet then begin TClientDataSet(C).Close; TClientDataSet(C). FieldDefs.Clear; end; end; ShowMessage(‘Tabela Fechada!’); end; Listagem 12 – Evento After Post. procedure TfmBase. cdsPadraoAfterPost(DataSet: TDataSet); begin cdsPadrao.ApplyUpdates(0); end; Com os dados devidamente gravados podemos limpar nossa tabela para utilizamos novamente, portanto, utilize o comando da listagem 13 para remover os valores que estão no ‘cdsdinamico’. Listagem 13 – Botão Limpar Tabela. procedure TfmBase. btnLimparTabelaClick(Sender: TObject); begin cdsdinamico.EmptyDataSet; ShowMessage(‘Tabela Vazia!’); end; Outro comando que podemos utilizar caso seja necessário modificar a tabela que estamos trabalhando é botão ‘Fechar Tabela’, ele irá fechar ambos os ‘Clients’ e limpar os campos que foram criados inicialmente. Veja na listagem abaixo: Para finalizarmos esta etapa no evento ‘OnClose’ do formulário vamos fechar ambos os ‘Clients’ para que não fique nada em memória. Listagem 15 – Evento OnClose. procedure TfmBase. FormClose(Sender: TObject; var Action: TCloseAction); begin cdsdinamico.Close; cdsPadrao.Close; end; Formulário de Configurações do Banco Para deixarmos nossa aplicação ainda mais genérica criamos também um formulário que será responsável por manipular as tabelas e campos de nosso banco de dados. Inicialmente crie um formulário e o layout deve ficar conforme Imagem 5. Imagem 5 – Formulário Configurações do Banco. dezembro 2013 13 Veja que nosso formulário possui um menu oculto que só será exibido quando criarmos uma nova tabela (Imagem 6). Adicione também um componente ‘SQLQuery’ que será responsável por executar as instruções que manipularão nossa base de dados. := False; edtNomedaTabela.Text := UpperCase(Nome_Tab); end; end; end; end; Veja que em nosso menu expandido temos que passar os dados para a criação da tabela e em seguida podemos cria-la ou cancelar o processo, veja abaixo a listagem de criação. Imagem 6 – Formulário Configurações do banco (Criação da Tabela). Ao clicar no botão ‘Nova * ’ do painel ‘Tabela’ iremos primeiro passar o nome de nossa nova tabela e neste momento será verificado se a mesma já existe, feito a verificação o painel de cadastro será exibido no rodapé do formulário conforme imagem 6. Listagem abaixo demonstra o processo. Listagem 16 – Botão Nova Tabela. procedure TfmBanco. sbtnNovaTabelaClick(Sender: TObject); var Nome_Tab: string; begin Nome_Tab := InputBox(‘Nova Tabela’, ‘Nome: ‘, ‘’); if Nome_Tab <> ‘’ then begin try begin SQLQuery.Close; SQLQuery.SQL.Text := ‘Select * From ‘ + Nome_Tab; SQLQuery.Open; ShowMessage(‘Tabela Já Existe’); SQLQuery.Close; end; except if MessageDlg(‘Tabela Não Encontrada!, Deseja Criar ?’, mtConfirmation, [mbYes, mbNo], 0) = mrYes then begin fmBanco.Height := fmBanco.Height + Painel_ NovaTabela.Height + 10; Painel_Campos.Visible 14 dezembro 2013 Listagem 17 – Botão Criar Tabela. procedure TfmBanco. sbtnCriarClick(Sender: TObject); begin // Sintaxe -> CREATE TABLE TABELA (PK INTEGER) SQLQuery.Close; SQLQuery.SQL.Text := ‘’; SQLQuery.SQL.Text := ‘Create Table ‘ + edtNomedaTabela.Text + ‘ ( ‘ + edtPk.Text + ‘ ‘ + cbTipo.Text + ‘ NOT NULL) ‘; SQLQuery.ExecSQL(); // Sintaxe -> ALTER TABLE TABELA ADD CONSTRAINT PK_CODIGO PRIMARY KEY (CODIGO) SQLQuery.SQL.Text := ‘’; SQLQuery.SQL.Text := ‘ALTER TABLE ‘ + edtNomedaTabela.Text + ‘ ADD CONSTRAINT ‘ + ‘PK_’ + edtNomedaTabela.Text + ‘ PRIMARY KEY (‘ + edtPk.Text + ‘)’; SQLQuery.ExecSQL(); ShowMessage(‘Tabela Criada com Sucesso!’); cbTabelas.Text := ‘’; cbTabelas.Items.Clear; fmBanco.OnShow(nil); fmBanco.Height := fmBanco. Height - Painel_NovaTabela. Height - 10; Painel_Campos.Visible := True; edtNomedaTabela.Text := ‘’; end; Caso o usuário não queira mais criar a tabela, pode utilizar o botão ‘Cancelar’ para voltar o formulário ao estado inicial. Processo do botão ‘Cancelar’ na listagem abaixo: Listagem 18 – Botão Cancelar. procedure TfmBanco. sbtnCancelarClick(Sender: TObject); begin fmBanco.Height := fmBanco. Height - Painel_NovaTabela. Height - 10; Painel_Campos.Visible := True; edtNomedaTabela.Text := ‘’; end; Em nosso formulário temos um ‘Combobox’ nomeado de ‘cbTabelas’ ele será responsável por listar todas as tabelas que de nosso banco, listagem 19 demonstra o procedimento. SQLQuery.Close; SQLQuery.SQL.Text := ‘Drop Table ‘ + Nome_Tab; SQLQuery.ExecSQL(); ShowMessage(‘Tabela Excluída com Sucesso!’); cbTabelas.Text := ‘’; cbTabelas.Items.Clear; fmBanco.OnShow(nil); end; except ShowMessage(‘Erro ao Excluir!’); end; end; end; Para finalizarmos vamos manipular nossos campos, veja que temos um painel intitulado de ‘Campo’. Para que possamos acessar as propriedades deste painel primeiramente devemos selecionar o nome de nossa tabela, após isso o ‘Combobox’ ‘Existentes’ irá exibir o nome dos campos da tabela indicada. Veja abaixo o comando para listar os campos: Listagem 19 – Evento OnShow. Listagem 21 – Evento OnSelect Combobox(cbTabelas). procedure TfmBanco. FormShow(Sender: TObject); begin DM.Conexao. GetTableNames(cbTabelas.Items, False); end; procedure TfmBanco. cbTabelasSelect(Sender: TObject); begin DM.Conexao. GetFieldNames(cbTabelas.Text, cbExisCampo.Items); end; Podemos excluir as tabelas que já possuímos em nossa base de dados com um comando ‘Drop Table’ veja como ficou nosso processo na listagem abaixo: Listagem 20 – Botão Excluir. procedure TfmBanco. sbtnExcluirTabelaClick(Sender: TObject); var Nome_Tab: string; begin Nome_Tab := InputBox(‘Excluir Tabela’, ‘Nome: ‘, ‘’); if Nome_Tab <> ‘’ then begin try begin // Sintaxe -> DROP TABLE TABELA Neste contexto o usuário poderá adicionar um novo campo, alterar ou excluir um já existente. Por este motivo vamos demonstra cada um dos processos citados (Inclusão, alteração e exclusão). Veja na listagem 22 temos alguns blocos de comando para a criação dos campos, foram feitos 4 tipos, que podem variar de ‘Nulo’ para não ‘Nulo’ e numérico para texto. Listagem 22 – Botão Novo Campo. procedure TfmBanco. sbtnNovoCampoClick(Sender: TObject); begin // Sintaxe -> ALTER TABLE TABELA ADD CAMPO VARCHAR(50) SQLQuery.Close; SQLQuery.SQL.Text := ‘’; dezembro 2013 15 if (CheckNull.Checked = False) and (cbcTipo.Text <> ‘INTEGER’) and (cbcTipo.Text <> ‘FLOAT’) and (cbcTipo.Text <> ‘DATE’) then begin SQLQuery.SQL.Text := ‘ALTER TABLE ‘ + cbTabelas.Text + ‘ ADD ‘ + edtNomeCampo.Text + ‘ ‘ + cbcTipo.Text + ‘(‘ + edtTamanhoCampo.Text + ‘)’; end; if (CheckNull.Checked = True) and (cbcTipo.Text <> ‘INTEGER’) and (cbcTipo.Text <> ‘FLOAT’) and (cbcTipo.Text <> ‘DATE’) then begin SQLQuery.SQL.Text := ‘ALTER TABLE ‘ + cbTabelas.Text + ‘ ADD ‘ + edtNomeCampo.Text + ‘ ‘ + cbcTipo.Text + ‘(‘ + edtTamanhoCampo.Text + ‘) NOT NULL’; end; if (CheckNull.Checked = True) and (cbcTipo.Text = ‘INTEGER’) or (cbcTipo.Text = ‘FLOAT’) or (cbcTipo.Text = ‘DATE’) then begin SQLQuery.SQL.Text := ‘ALTER TABLE ‘ + cbTabelas.Text + ‘ ADD ‘ + edtNomeCampo.Text + ‘ ‘ + cbcTipo.Text + ‘ NOT NULL’; end; if (CheckNull.Checked = False) and (cbcTipo.Text = ‘INTEGER’) or (cbcTipo.Text = ‘FLOAT’) or (cbcTipo.Text = ‘DATE’) then begin SQLQuery.SQL.Text := ‘ALTER TABLE ‘ + cbTabelas.Text + ‘ ADD ‘ + edtNomeCampo.Text + ‘ ‘ + cbcTipo.Text; end; SQLQuery.ExecSQL(); cbExisCampo.Items.Clear; cbTabelas.OnSelect(nil); ShowMessage(‘Campo “’ + edtNomeCampo.Text + ‘” criado com Sucesso!’); end; 16 dezembro 2013 Em alguns casos o usuário deseja remover um campo que já não utiliza mais, e por este motivo programamos o botão ‘Excluir’, veja listagem 23. Entretanto podemos também reutilizar um campo que já está inserido em nossa tabela, porém necessitamos alterar o nome do mesmo, pensando nisso criamos o procedimento para alteração do campo, veja na Listagem 24. Listagem 23 – Botão Excluir Campo. procedure TfmBanco. sbtnExcluirCampoClick(Sender: TObject); begin // Sintaxe -> ALTER TABLE “TABELA” DROP “CAMPO” try SQLQuery.Close; SQLQuery.SQL.Text := ‘’; SQLQuery.SQL.Text := ‘ALTER TABLE “’ + cbTabelas.Text + ‘” DROP “’ + cbExisCampo.Text + ‘”’; SQLQuery.ExecSQL(); ShowMessage(‘Campo “’ + cbExisCampo.Text + ‘” Excluído com Sucesso!’); cbExisCampo.Text := ‘’; cbExisCampo.Items.Clear; cbTabelas.OnSelect(nil); except ShowMessage(‘Erro ao Excluir campo!’); end; end; Listagem 24 – Botão Alterar Campo. procedure TfmBanco. sbtnAlterarClick(Sender: TObject); var Novo_Nome: string; begin // Sintaxe -> ALTER TABLE TABELA ALTER COLUMN CAMPO TO NOVO_NOME try Novo_Nome := InputBox(‘ Novo Nome ‘, ‘Nome:’, cbExisCampo.Text); if Novo_Nome = cbExisCampo. Conclusão Text then begin ShowMessage(‘Nome já existe, favor verificar!’); end else begin SQLQuery.Close; SQLQuery.SQL.Text := ‘’; SQLQuery.SQL.Text := ‘ALTER TABLE ‘ + cbTabelas. Text + ‘ ALTER COLUMN ‘ + cbExisCampo.Text + ‘ TO ‘ + Novo_Nome; SQLQuery.ExecSQL(); ShowMessage(‘Campo “’ + cbExisCampo.Text + ‘” Alterado com Sucesso!’); cbExisCampo.Text := ‘’; cbExisCampo.Items.Clear; cbTabelas.OnSelect(nil); end; except ShowMessage(‘Erro ao Alterar!’); end; end; O intuito do artigo é demonstrar como podemos trabalhar com o Delphi de forma dinâmica, no que envolve desenvolvedor e usuário, visando demonstrar de forma simples como aplicar funcionalidades alternativas, portanto, o leitor fica livre para melhorar e implementar da forma que desejar. Espero que tenham gostado desta dica e até a próxima! Sobre o autor Jeferson Silva de Lima Consultor The Club. [email protected] dezembro 2013 17 ASP.NET MVC V ocê já deve ter ouvido falar de ASP.NET. É uma arquitetura Web para criar sites, portais, aplicações Web. Mas você sabe o que é ASP.NET MVC? Em termos gerais tem a mesma finalidade: criar sites, portais, aplicações Web etc, mas com um conceito diferente do ASP.NET “original” (também chamado Web Forms). O ASP.NET MVC é baseado no padrão MVC (Model View Controller), criado pela Xerox nos anos 70. Nesse padrão, é feita uma separação de responsabilidades nas camadas da aplicação (modelo, visão e controlador). Neste artigo quero mostrar as características do ASP.NET MVC para o leitor que não conhece, assim como mostrar dicas para desenvolvedores que já usam a arquitetura. Parte I Primeiro projeto Após essa pequena explanação, vamos entender como funciona o ASP.NET MVC na prática. Criaremos exemplos usando o Visual Studio 2012 e a versão ASP.NET MVC 4. Os exemplos também podem ser feitos no Visual Studio 2010 (você deve instalar a versão 4 do ASP.NET MVC em separado). No Visual Studio 2013, já temos a versão ASP.NET MVC 5. Crie um novo projeto ASP.NET MVC 4 Web Application no Visual Studio 2012 (Figura 1). MVC x WebForms Como sempre, temos um comparativo sobre características do Web Forms e MVC. • Web Forms: presente desde 2001, sendo o primeiro modelo de desenvolvimento do .NET e o mais utilizado atualmente. Tornou ágil o desenvolvimento de aplicações Web, usando o conceito “drag and drop” (arrastar e soltar). Possui grandes opções de controles de tela, onde o HTML e funções JavaScript são criadas “sozinhas”. Entres os contras dessa arquitetura podemos destacar: pouco controle sobre o HTML e JavaScript gerado, impossibilidade de testes de interface, difícil integração com frameworks de JavaScript. • MVC: padrão de desenvolvimento MVC, faz a separação de responsabilidades das camadas da aplicação, controle total sobre o HTML e JavaScript gerado, podemos criar testes de interface, etc. Entre os pontos negativos: não é RAD, não tem controles prontos, necessidade de aprendizado (modelo totalmente diferente do Web Forms), desenvolvimento maior de código. O que as duas arquiteturas tem em comum? Rodam sobre o mesmo runtime (ASP.NET), geram páginas ASPX, rodam no IIS, tem o mesmo acesso a dados (LINQ, ADO.NET, Entity Framework) e desenvolvidos utilizando o Visual Studio. Ou seja, sua aplicação Web Forms, ao ser “convertida” para MVC, vai rodar normalmente no servidor. 18 dezembro 2013 Figura 1. Criando um projeto ASP.NET MVC no Visual Studio 2012 Após, será aberto um editor onde escolheremos o template de projeto que podemos criar (Figura 2): • Empty: projeto vazio (sem scripts, arquivos de imagens etc); • Basic: projeto onde temos o básico da estrutura de pastas de um projeto ASP.NET MVC; • Internet Application: cria um projeto com autenticação usando Forms Authentication; • Intranet Application: cria um projeto com autenticação usando Windows Authentication; • Mobile Application: cria um projeto para aplicações mobile; • Web API: cria um projeto API para expor métodos onde outros sites irão consumir. Figura 2. Escolhendo o template de projeto ASP.NET MVC Como podemos ver na Figura 2, temos mais templates disponíveis, de acordo com a instalação de plug-ins e frameworks de terceiros. Em View Engine escolha Razor. View engine é o responsável pela criação do HTML. Temos dois tipos: Razor e ASPX. Razor é mais enxuta e praticamente é C#, já o ASPX, usa tags de scripts para a criação do HTML. Veja na Listagem 1, exemplos de Razor e ASPX. Listagem 1. Diferenças entre Razor e ASPX Razor @{ string nome = “Luciano Pimenta”; int numero = 0; } ASPX <% string nome = “Luciano Pimenta”; int numero = 0; %> No decorrer do artigo, veremos como funciona a engine Razor. Vamos escolher o template Basic para que possamos ter a estrutura básica de uma aplicação ASP.NET MVC. Model View Controller Na Figura 3 temos a estrutura da nossa aplicação. Figura 3. Estrutura de uma aplicação basic para o ASP.NET MVC Semelhante a uma aplicação ASP.NET Web Forms, temos várias pastas, mas temos três que são essenciais: Models, Views e Controllers. Na pasta Views temos as páginas (com extensão cshtml). Já em Controllers teremos as classes responsáveis pelas regras de negócios e em Models temos as classes de mapeamento do banco de dados. Vamos entender um pouco sobre MVC. O padrão MVC foi criado pela Xerox em meados dos anos 70 e tem como principal caraterísticas separar as responsabilidades das camadas da aplicação. Temos um exemplo simples de como funciona o padrão na Figura 4. Figura 4. Conhecendo o padrão de projeto MVC. Fonte: www.oficinadanet.com.br O Model é responsável por “pegar” os dados do banco e disponibilizar para o Controller. Este por sua vez, “envia” os dados para a View e recebe novamente, repassando para o Model. O Controller também é responsável pela validação dos dados antes de enviar ao Model. A View recebe os dados do Controller e exibe em tela, devolvendo para o Controller os dados alterados ou inseridos quando assim for solicitado. Veja que as responsabilidades são claras, não veremos em projeto ASP.NET MVC, código em páginas ASPX com comandos SQL no banco de dados, por exemplo. dezembro 2013 19 Nota: isso não é correto nem em aplicação ASP.NET Web Forms, mas as primeiras aplicações tinham resquícios do ASP3. Assim, sabemos que validações dos dados devem ser feitas no Controller, deixando a View com a responsabilidade de apenas exibir os mesmos. Como primeiro exemplo, vamos aprender como passar dados do Controller para a View, algo bastante comum no ASP.NET MVC. Para aprender isso, precisamos primeiro entender como o Controller trabalha com a View. Trafegando dados entre Controller e View Quando precisamos passar dados (independente se sejam oriundos de banco de dados ou não), podemos usar o ViewBag ou ViewData. ViewData podemos comparar com uma variável de sessão (objeto Session) do ASP.NET. Podemos preencher no Controller e recuperar seu valor na View. Já o ViewBag é um objeto bem mais robusto onde podemos criar propriedades dinâmicas. Ou seja, podemos indicar o valor que queremos atribuindo a uma propriedade e na View apenas referenciar essa propriedade. Vamos a um exemplo. No projeto criado, clique com o botão direito na pasta Controllers e escolha Add>Controller. No editor (Figura 5), vamos dar o nome de “HomeController”. Rotas No ASP.NET MVC temos o conceito de rotas usando o ASP.NET Routing para rotear URLs. Uma rota indica: um Controller, uma Action e um parâmetro (opcional). Não temos mais URLs, como: localhost/NomeProjeto/Index.aspx ou localhost/NomeProjeto/Index.aspx?codigo=1. Agora teremos: localhost/ NomeProjeto/Index ou localhost/NomeProjeto/Index/1. Podemos dizer que a URL ficou mais amigável e mais fácil de compreensão. Index é a rota padrão de uma aplicação ASP.NET MVC. Todo Controller deve ter um método chamado Index (customizações são permitidas). No arquivo RouteConfig.cs na pasta App_Start podemos ver o mapeamento da rota (Listagem 2). Listagem 2. Mapeamento de rotas no RouteConfig public static void RegisterRoutes(RouteCollection routes) { routes. IgnoreRoute(“{resource}.axd/ {*pathInfo}”); routes.MapRoute( name: “Default”, url: “{controller}/ {action}/{id}”, defaults: new { controller = “Home”, action = “Index”, id = UrlParameter. Optional } ); } O RegisterRoutes é chamado apartir do Application_Start do Global. asax.cs. 20 dezembro 2013 Figura 5. Criando um controller Todo Controller criado já possui um método Index. No mesmo, temos o retorno da View. Altere o Index padrão para o seguinte código: ViewData[“HelloWorld”] = “Hello World”; ViewBag.Hello = “Hello”; ViewBag.World = “World”; Atribuímos para ViewData, de nome Hello, um valor. Na ViewBag, criamos duas propriedades dinâmicas e preenchemos. Esses valores serão apresentados na View. Clique com o botão direito na pasta Views e escolha Add>New Folder. Dê o nome de “Home”. Padronizamos que as pastas dentro de Views devem ter o mesmo nome dos Controllers. Dentro da pasta Home, adicione uma View, clicando de direito e escolhendo Add>View. No editor (Figura 6), vamos dar um nome para a View: “Index”. Mas e dados ou objetos, como fazer. Também é bastante simples. Vamos criar um Model. Clique com o botão direito na pasta Models e escolha Add>Class. Dê o nome de “Pessoa.cs” para a nova classe e adicione as seguintes propriedades: public int PessoaID { get; set; } public string Nome { get; set; } public DateTime Nascimento { get; set; } As classes da pasta Models, servem para mapear objetos do banco ou simplesmente ser um repositório. Vamos modificar o método Index do Home para o código da Listagem 4. Figura 6. Criando uma view Ao criar a View, temos um arquivo cshtml (como se fosse um ASPX), onde vamos codificar nossa página. Nela temos controle total do HTML, JavaSricpt, etc. Altere o código para o da Listagem 3. Listagem 3. Codificando a View @{ ViewBag.Title = “Minha página Index”; } <p>ViewData: <b>@ ViewData[“HelloWorld”]</b></p> <p>Hello: <b>@ViewBag.Hello</ b></p> <p>World: <b>@ViewBag.World</ b></p> Note que usamos o caracter @ para invocar objetos na página. O Intelissense não funciona no ViewBag, por que as propriedades são dinâmicas. Execute a aplicação e veja o resultado (Figura 7). Listagem 4. Passando dados para a View Pessoa pessoa = new Pessoa { PessoaID = 1, Nome = “Luciano Pimenta”, Nascimento = DateTime.Now }; return View(pessoa); O código é simples. Instanciamos uma classe Pessoa e repassamos esse objeto para a View. Agora, precisamos receber esse objeto na View. Veja a Listagem 5 para ver como foi modificada a View. Listagem 5. Recebendo um objeto Pessoa na View @model HelloWorld.Models.Pessoa @{ ViewBag.Title = “Minha página Index”; } <p><b>Id</b>: @Model.PessoaID</ p> <p><b>Nome</b>: @Model.Nome</p> <p><b>Nascimento</b>: @Model. Nascimento</p> Figura 7. Executando a aplicação A primeira linha é importantíssima, pois nela indicamos qual model esta sendo recebido pela página. Com a indicação do tipo de objeto, usamos o @ Model para trabalhar com o objeto recebido pela página, assim, podemos dezembro 2013 21 exibir suas propriedades onde desejarmos. Teste a aplicação. Nota: veja que para indicarmos o objeto que a página recebe usamos o nome model em minúsculo. Para acessar as propriedades do objeto, usamos em maiúsculo. E se estivéssemos trabalhando com mais de um objeto (uma consulta que retorna vários registros)? Como faríamos? Primeiro, vamos criar um novo método no Controller, chamado “Lista” e retornar vários objetos pessoas em uma lista. Veja na Listagem 6 o método Lista. Listagem 6. Método Lista do HomeController public ActionResult Lista() { Pessoa pessoa1 = new Pessoa { PessoaID = 1, Nome = “Luciano Pimenta”, Nascimento = new DateTime(1976, 5, 8) }; Pessoa pessoa2 = new Pessoa { PessoaID = 2, Nome = “Alessandra Pimenta”, Nascimento = new DateTime(1980, 6, 9) }; Pessoa pessoa3 = new Pessoa { PessoaID = 3, Nome = “Luciano Castro”, Nascimento = new DateTime(1978, 7, 22) }; List<Pessoa> lista = new List<Pessoa>(); lista.Add(pessoa1); lista.Add(pessoa2); lista.Add(pessoa3); } return View(lista); Apenas criamos alguns objetos Pessoa e colocamos em uma lista, que é repassada para a View. Crie uma nova View, na pasta Home, dando o nome 22 dezembro 2013 de “Lista”. Na View, vamos adicionar o código da Listagem 7. Listagem 7. View que receberá a Lista de Pessoa @model List<HelloWorld.Models. Pessoa> @{ } ViewBag.Title = “Lista”; <h2>Lista</h2> <table> <tr> <th>Id</th> <th>Nome</th> <th>Nascimento</th> </tr> @foreach (var item in @ Model) { <tr> <td>@item. PessoaID</td> <td>@item.Nome</td> <td>@item. Nascimento.ToString(“dd/MM/ yyyy”)</td> </tr> } </table> Note, que você desenvolvedor é o responsável por exibir os dados na página. Não temos um Grid (componentes de terceiros nos auxiliam). A criação do HTML esta tudo em suas mãos. Agora, não estamos recebendo apenas um objeto Pessoa, mas sim um List<Pessoa>. Criamos uma tabela com os cabeçalhos e usamos um foreach para percorrer a lista e exibir os dados. Para que possamos acessar a página da lista, precisamos criar um link. Em Index, adicione o seguinte código (abaixo do código do exemplo do Index): @Html.ActionLink(“Lista”, “Lista”, “Home”) ActionLink ira redirecionar para a View que queremos. O primeiro parâmetro indica o texto do link. O segundo a Action que iremos usar e no terceiro, será a rota. Execute a aplicação e veja o resultado (Figura 8). Listagem 9. View para cadastro da pessoa @model HelloWorld.Models.Pessoa @{ } ViewBag.Title = “Cadastro”; <h2>Cadastro</h2> Figura 8. Lista de pessoas da aplicação Cadastro Precisamos criar um cadastro. Vamos cadastrar uma pessoa e mostrar os dados inseridos pelo usuário. Ainda não usaremos banco de dados, mas a adaptação como veremos no próximo artigo, será muito simples. Veja o código da Action na Listagem 8. Listagem 8. Métodos de cadastro [HttpPost] public ActionResult Create(Pessoa pessoa) { return View(“ExibeDados”, pessoa); } [HttpGet] public ActionResult Create() { return View(); } A ideia é receber o objeto Pessoa como parâmetro e repassar para o Index. Em uma aplicação real, iriamos inserir pessoa no banco de dados e depois redirecionar para onde quisermos. O ASP.NET MVC é capaz de montar objetos com os valores dos parâmetros HTTP e passá-los como argumento para as ações dos controladores (por isso usamos a marcação HttpPost no Create). Note que no objeto View, temos alguns parâmetros, entre eles, de indicar o nome da View e o model que queremos passar. Crie uma View chamada “Create”, e uso o código da Listagem 9. @using (Html.BeginForm()) { <fieldset> <legend>Cadastro</legend> <div class=”display-label”> @Html. DisplayNameFor(model => model. PessoaID) </div > <div class=”display-field”> @Html.EditorFor(model => model.PessoaID) </div > <div class=”display-label”> @Html. DisplayNameFor(model => model. Nome) </div > <div class=”display-field”> @Html.EditorFor(model => model.Nome) </div > <div class=”display-label”> @Html. DisplayNameFor(model => model. Nascimento) </div > <div class=”display-field”> @Html.EditorFor(model => model.Nascimento) </div > </fieldset> <p> <input type=”submit” value=”Cadastro” /> </p> } Como sabemos que teremos um objeto Pessoa na página, usamos @ Html.EditorFor para montar uma caixa de texto e @Html.DisplayNameFor dezembro 2013 23 para exibir um rótulo. Nota: No model, podemos marcar a propriedade para exibir o rótulo que quisermos, por exemplo usando a marcação: [Display(Name = “Código da pessoa”)] public int PessoaID { get; set; } Crie uma View chamada “ExibeDados” e implemente, semelhante ao Index, onde recebemos um model Pessoa, somente para exibição. Adicione um link no Index para ser direcionado ao cadastro criado anteriormente. Rode a aplicação e faça o teste. Validações No ASP.NET Web Forms, temos controles para validações, os Validators. Vou mostrar um exemplo, onde podemos validar os dados na Action do controller. Veja na Listagem 10, como fazer essa validação (método Create). Note que verificamos cada campo do objeto Pessoa (o que pode ser trabalhoso, dependendo da quantidade de campos validados). Quando a regra é quebrada, adicionamos a mensagem de erro no ModelState. Na View, precisamos ainda fazer uma última modificação. Abaixo de cada controle de tela (EditorFor), precisamos colocar a indicação da validação do campo. Adicione o seguinte código (alterando o nome do campo para os demais): @Html.ValidationMessageFor(model => model.PessoaID) Na parte inferior da página (após o código HTML), vamos indicar a biblioteca jQuery que auxilia na exibição das validações: @section Scripts{ @Scripts.Render(“~/bundles/ jqueryval”) } Listagem 10. Validando dados na Action do Controller if (pessoa.PessoaID == 0) ModelState. AddModelError(“PessoaID”, “Campo PessoaID: preenchimento obrigatório.”); if (string.IsNullOrEmpty(pessoa. Nome)) ModelState. AddModelError(“Nome”, “Campo Nome: preenchimento obrigatório.”); if (pessoa.Nascimento == null) ModelState. AddModelError(“Nascimento”, “Campo Nascimento: preenchimento obrigatório.”); if (ModelState.IsValid) return View(“ExibeDados”, pessoa); return View(); 24 dezembro 2013 Rode e teste a aplicação. Agora, vamos conhecer uma maneira bem mais simples de validação, o DataAnnotations. Simplesmente, criamos uma marcação na propriedade do model, indicando o que queremos validar. Veja na Listagem 11 algumas validações de Pessoa. Listagem 11. Validações com DataAnnotations [Required(ErrorMessage=”Campo PessoaID: preenchimento obrigatório”)] [Display(Name=”Código da pessoa”)] public int PessoaID { get; set; } [Required(ErrorMessage = “Campo Nome: preenchimento obrigatório”)] [StringLength(10, ErrorMessage=”Campo Nome: máximo de 10 caracteres.”)] public string Nome { get; set; Figura 9. Validações no ASP.NET MVC } [Required(ErrorMessage = “Campo Nascimento: preenchimento obrigatório”)] public DateTime Nascimento { get; set; } Note que além da obrigatoriedade dos campos, adicionamos uma validação onde o campo Nome, deve conter até 10 caracteres. Fica mais fácil marcar a propriedade com DataAnnotations, do que comparar cada campo no Controller. Rode a aplicação e tente cadastrar um registro com o nome em branco ou que a quantidade de caracteres do Nome seja maior que 10 (Figura 9). Veja a figura 9 Conclusões Sobre o autor Luciano Pimenta Luciano Pimenta (NOVO DOMINIO: www.lucianopimenta.com) é desenvolvedor Delphi/C# para aplicações Web com ASP.NET, Windows com Win32 e Windows Forms com .NET. Palestrante da 4ª edição da Borland Conference (BorCon) e da 1ª Delphi Conference. É MVP Embarcadero, grupo de profissionais que ajudam a divulgar o Delphi no mundo. Atualmente é desenvolvedor da SoftDesign fábrica de softwares em Porto Alegre-RS. Autor de mais de 90 artigos e de mais de 600 vídeos aulas publicadas em revistas e sites especializados, além de treinamentos presenciais e multimídias. É consultor da FP2 Tecnologia (www.fp2.com.br) onde ministra cursos de programação e banco de dados. www.lucianopimenta.net Vimos neste artigo os primeiros passos para desenvolver projetos Web usando o ASP.NET MVC. No próximo artigo, veremos mais dicas e como trabalhar com banco de dados usando o Entity Framework. Um grande abraço a todos e até a próxima! dezembro 2013 25 dicas the club Dicas Delphi Dica 1 - Dividir Linhas de um Texto (.Txt) no TMemo Em algumas aplicações existe a necessidade de manipularmos textos ou dados que estejam gravados em blocos de Strings, portanto, vamos demonstrar uma forma simples de trabalharmos com este tipo de funcionalidade. Utilizaremos um arquivo de texto (.txt) no qual temos valores numéricos e iremos dividir estes valores em outros arquivos de acordo com as informações que o usuário indicar. O formulário deve ficar parecido com imagem 1. Para facilitar a visualização vamos apresentar os dados em 2 Memos, o primeiro (Esquerda) irá apresentar os dados iniciais, ou seja, aqueles que serão manipulados, já em nosso segundo Memo serão apresentados os dados em execução. Vamos iniciar com o comando do botão ‘Carregar’ que irá listar os dados originais em nosso primeiro Memo, veja a codificação abaixo: Listagem 1 – Botão Carregar. procedure TForm1. Button1Click(Sender: TObject); begin Memo1.Clear; Memo2.Clear; Memo1.Lines. LoadFromFile(‘lista.txt’); Edit1.Text := IntToStr(Memo1. Lines.Count); end; Após carregarmos os dados podemos começar a manipulação, veja que temos um ‘Edit’ intitulado de ‘Dividir’ nele iremos inserir a quantidade de linhas que que indicará de quantas em quantas linhas o texto será dividido. Para evitar erros de digitação insira no evento ‘OnKeyPress’ o seguinte comando: Listagem 2 – Evento KeyPress. Imagem 1 – Formulário Principal. 26 dezembro 2013 procedure TForm1. edtDividirKeyPress(Sender: TObject; var Key: Char); begin if not (key in [‘0’..’9’, #08]) then key := #0; end; Assim nosso campo irá apenas aceitar valores numéricos. Outra restrição que podemos indicar é para que o valor inserido no campo ‘Dividir’ não seja maior que o total de linhas de nosso arquivo, para isto vamos utilizar o evento ‘OnExit’ do Edit, veja listagem abaixo: Listagem 3 – Evento OnExit. procedure TForm1. edtDividirExit(Sender: TObject); var Total, Dividir: Integer; begin if edtTotal.Text <> ‘’ then Total := StrToInt(edtTotal. Text); if edtDividir.Text <> ‘’ then Dividir := StrToInt(edtDividir.Text); if Total < Dividir then begin ShowMessage(‘Total de Linhas é Menor que o Divisor’); edtDividir.SetFocus; end; end; StrToInt(edtDividir.Text), Memo2); Total := StrToInt(edtTotal. Text); Dividir := StrToInt(edtDividir.Text); Calculado := Total Dividir; edtTotal.Text := IntToStr(Calculado); Memo2.Lines.SaveToFile(E xtractFilePath(Application. ExeName) + ‘Texto’ + edtTotal. Text + ‘.txt’); Memo2.Lines.Clear; until Dividir > Total Dividir; Memo1.Lines.SaveToFile(Extrac tFilePath(Application.ExeName) + ‘Resto.txt’); Memo1.Lines.Clear; end; Foi criado um arquivo com 1000 números chamado ‘lista.txt’, ao executar o divisor em 300 linhas foram gerados os arquivos conforme imagem abaixo: Por fim iremos executar o comando de nosso botão ‘Dividir’ que irá separar os dados e salvar em lotes dependendo do valor passado pelo usuário, abaixo a listagem do botão ‘Dividir’: Listagem 4 – Botão Dividir. procedure TForm1. btnDividirClick(Sender: TObject); var Total, Dividir, Calculado: Integer; begin repeat SepararLinhas(Memo1, Imagem 2 – Arquivos Gerados. Veja que os arquivos foram nomeados de acordo com o restante de linhas que nosso arquivo original possuía. Esta dica pode ser implementada e melhorada de acordo com as necessidades do usuário. Espero que tenham gostado e até a próxima. dezembro 2013 27 Dica 2 – Contar Registros do Banco de Dados Nesta dica vamos demonstrar uma forma simples para contar quantas vezes um determinado valor aparece dentro de uma tabela, ou seja, um ‘SELECT COUNT’, mas de forma dinâmica utilizando o Delphi. Para esta funcionalidade vamos utilizar um modelo simples de conexão com os componentes: • • • • • SQLConnection; SQLDataSet; DataSetProvide; ClientDataSet; DataSource. Vamos utilizar também um ‘SQLQuery’ para executar nossas consultas . O formulário irá ficar conforma imagem abaixo: que seja o campo ‘Parcela’. Antes de prosseguirmos insira as listagens abaixo para que a aplicação execute corretamente: Listagem 1 – Evento OnShow. procedure TForm1. FormShow(Sender: TObject); begin ClientDataSet1.Open; end; Listagem 2 – Evento OnClose. procedure TForm1. FormClose(Sender: TObject; var Action: TCloseAction); begin ClientDataSet1.Close; end; Listagem 3 – Evento SQLConnection (BeforeConnect). procedure TForm1.SQLConnection1 BeforeConnect(Sender: TObject); begin SQLConnection1. LoadParamsFromIniFile(‘Connect. ini’); end; Após definir as ‘Tags’ para cada ‘Edit’ vamos iniciar a codificação do botão ‘Contar’ veja na listagem abaixo: Listagem 4 – Botão Contar. Imagem 1 – Formulário Principal. Veja que temos 2 ‘Labels’ que seriam os apelidos de nossos campos, temos também logo a frente ‘(Tag = X)’ o que significa que o bloco de ‘Edits’ abaixo receberá em sua propriedade ‘Tag’ o valor que está indicado, portanto, marque ‘Tag = 1’ no campo que deseja indicar o campo ‘Valor’ e ‘Tag = 2’ para 28 dezembro 2013 Procedure TForm1. btnContarClick(Sender: TObject); var Campo: String; I, R: Integer; C: TComponent; begin for I := 0 to ComponentCount - 1 do begin C := Components[I]; if (C is TEdit) and (TEdit(C).Text <> ‘’) then begin SQLQuery1.Close; // Pode passar seus campos de forma Dinâmica case TEdit(C).Tag of 1: begin Campo := ‘VALOR’; SQLQuery1.SQL.Text := ‘SELECT COUNT(‘ + Campo + ‘) FROM NUMEROS WHERE ‘ + Campo + ‘ = :V’; SQLQuery1.Params. ParamByName(‘V’).Value := TEdit(C).Text; SQLQuery1.Open; R := SQLQuery1. Fields[0].AsInteger; ShowMessage(‘Valor (‘ + TEdit(C).Text + ‘) = ‘ + IntToStr(R)); end; 2: begin Campo := ‘PARCELA’; SQLQuery1.SQL.Text := ‘SELECT COUNT(‘ + Campo + ‘) FROM NUMEROS WHERE ‘ + Campo + ‘ = :V’; SQLQuery1.Params. ParamByName(‘V’).Value := TEdit(C).Text; SQLQuery1.Open; R := SQLQuery1. Fields[0].AsInteger; ShowMessage(‘Parcela (‘ + TEdit(C).Text + ‘) = ‘ + IntToStr(R)); end; end; end; end; end; ‘Campo’, veja que dentro de nossa instrução concatenamos a variável ‘Campo’ para que possamos consultar de acordo com o valor passado, por fim nossa variável ‘R’ irá receber o total de registros encontrados para que possamos exibir na tela o valor final, veja na imagem 2: Imagem 2 – Resultado da Contagem. Esta dica pode ser implementada e melhorada de acordo com as necessidades, Espero que tenham gostado e até a próxima. Para tornar a contagem dinâmica vamos utilizar uma variável do tipo ‘TComponent’ assim utilizando o comando ‘if (C is TEdit) and (TEdit(C).Text <> ‘’) then’ iremos apenas executar nossa instrução se o componente for um ‘TEdit’. Dentro do ‘Case’ iniciamos passando o valor de nosso campo a variável dezembro 2013 29 desafio the club Questões 1 - A função AnsiIndexStr utilizada para fornecer o índice de uma matriz de strings pertence a Unit ... 2 - Base para componentes que apresentam informações em uma grade bidimensional. 3 - Procedimento responsável por remover todos os registros de um DataSet. 4 - Procedimento responsável por gravar atualizações pendentes no banco de dados. 5 - Função utilizada para alterar o nome de um arquivo. 6 - Função que retorna data e hora atual. 7 - Caractere usado para separar a parte inteira da fracionária de um número. 8 - Função que retorna uma SubString de uma String ou Segmento de uma Matriz. 9 - Função que retorna o índice do primeiro caractere de uma substring especificada. 10- O procedimento Free responsável por limpar um objeto da memória pertence a Unit ... 30 dezembro 2013 dezembro 2013 05 dezembro 2013