Caro leitor, hoje eu vou falar e mostrar como criar gráficos
dinâmicos usando a linguagem C#, da Microsoft. O gráfico será criado
usando uma API do Google, que em resumo utiliza JavaScript e HTML5.
Utilizado para desenvolvimento:
- Ferramenta Visual Studio 2012
- Linguagem C#
- API do Google para gerar gráfico
Não é difícil criar gráficos de linha, de pizza e de blocos. O Google mesmo te ajuda a desenvolver esses tipos de gráficos. Nesse site você consegue utilizar as ferramentas sem qualquer problema.
Inclusive, o Google mostra alguns códigos fontes criados como
exemplo. O problema é o código HTML, JavaScript e C#. A dificuldade que
tive foi juntar o código C# com o HTML. Depois de vários testes,
consegui criar o gráfico pegando os dados do banco de dados. Agora vou
mostrar pra vocês como eu fiz isso.
Eu não vou mostrar aqui como pegar os dados do banco de dados, a
única coisa que precisa é de um “DataTable” ou uma variável do tipo
“numérica” mesmo. Com o “DataTable” basta fazer o “loop” usando “for” e
pronto.
Quando você cria a página .aspx no seu projeto, o primeiro passo é importar o arquivo JavaScript no topo da página. Listagem 1.
Listagem 1 – Importando JavaScript
<script type="text/javascript" src="https://www.google.com/jsapi"></script>
O segundo passo é adicionar o componente literal na página. Listagem 2.
Listagem 2 – Literal
<asp:Literal id="ltlResultado" runat="server" />
O terceiro passo é adicionar um div com id, tamanho e largura. Listagem 3.
Listagem 3 – Adicionando div
<div id="chart_div" style="width:950px; height: 550px;"></div>
Até agora, o código escrito foi apenas o HTML dentro do arquivo
.ASPX. O próximo passo é escrever o código em C#. Listagem 4. Em
qualquer parte do código você pode chamar o método para gerar o gráfico.
No nosso caso, vou fazer no clique do botão Buscar.
Listagem 4 – Código C#
protected void cmdBuscar_Click(object sender, EventArgs e)
{
if (Page.IsValid)
{
try
{
DataTable _dt = buscaDados();
if (_dt != null && _dt.Rows.Count > 0)
{
StringBuilder str = new StringBuilder();
str.Append("<script type='text/javascript'>");
str.Append("google.load(\"visualization\", \"1\", { packages: [\"corechart\"] });");
str.Append("google.setOnLoadCallback(drawChart);");
str.Append("function drawChart() {");
str.Append(" var data = new google.visualization.arrayToDataTable([");
str.Append(@" ['Dia', 'Likes'], ");
if (_dt.Rows.Count == 1)
str.Append("['0',0], ");
for (int i = 0; i < _dt.Rows.Count; i++)
{
str.Append("['" + _dt.Rows[i]["dia"].ToString() + "'," +
_dt.Rows[i]["contador"].ToString() + "], ");
}
str.Append(@" ]);
var options = {
colors: ['#4C7951'],
series: {2: {type:'line'}}
};
var chart = new google.visualization.LineChart(document.getElementById('chart_div'));
chart.draw(data, options);
}
</script>");
ltlResultado.Text = str.ToString().Replace("], ]", "] ]").TrimEnd(',');
}
else
ltlResultado.Text = "<Br><br> Nenhum valor encontrado.";
}
catch (Exception ex)
{
throw ex;
}
}
}
Note que existe uma variável do tipo “StringBuilder” que armazena
todos os dados em JavaScript. No início do código, eu chamo uma classe
para buscar os dados, que retorna um “DataTable”.
No meio do código eu fiz um “for” do “DataTable” e caso exista dado,
começa a escrever os valores. Para escrever os valores, bastou adicionar
o “Append” com os dados em C#. Os meus dados são: dia e contador.
No final do código eu adicionei os valores montados para o componente
literal adicionado no começo do código HTML. Existe o comando “replace”
para retirar a vírgula a fim de imprimir o gráfico corretamente no C#.
A figura 1 mostra como ficou a imagem na página. Os dados apareceram sem qualquer problema.
 gráfico dinamico
Figura 1 – Gerando gráfico
Bom, eu fico por aqui. Qualquer dúvida pode entrar em contato pelo site www.mauriciojunior.org.
|
Olá, pessoal! Continuando nosso artigo sobre o reporting services (veja a primeira parte aqui), começaremos a analisar o que chamamos de relatórios local mode.
Local mode
Também conhecidos como client-side, os relatórios ditos
locais seguem o modelo de desenvolvimento e deploy dos relatórios
desenvolvidos como o Microsoft Access e Crystal Reports, onde os
relatórios são parte integrante da aplicação.
Arquitetura
Nesse modelo de relatório, todo processamento é realizado no cliente.
A aplicação é responsável por obter os dados provenientes de qualquer
fonte de dados, e o controle ReportViewer apresenta os relatórios. A
figura abaixo apresenta a arquitetura dos relatórios Local Mode:
 Figura 2.1 – arquitetura local mode
Caracteristicas
Os relatórios “local mode” caracterizam-se especialmente por:
- A segurança é herdada da aplicação que o hospeda;
- Filtros, ordenação, agrupamento e funções de agregação estão disponíveis;
- Possui formatação rica e inteligente, com imagens, fontes e cores;
- Interatividade com bookmarks e DocumentMap;
- Liberdade para interatividade com o usuário final;
- Integração com o controle ReportViewer;
- DataSet como estrutura de dados;
- Arquivos .RDLC (nenhuma instrução de acesso e/ou conexão à base de dados).
E seus elementos fundamentais correlacionam-se conforme a figura abaixo:
 Figura 2.2 – correlação dos elementos
Processo de criação
A partir dessa sessão, começaremos a implementar alguns relatórios
exemplo. Para isso utilizaremos um banco de dados que controla pedidos
de uma loja de departamentos. O diagrama abaixo apresenta as tabelas e
seus respectivos relacionamentos.
 Figura 2.3 – modelo de dados utilizado em nossos exemplos
Retornando ao processo de criação, para qualquer relatório implementado temos que seguir basicamente os seguintes passos:
- Modelagem do repositório de dados local
DataSet – estrutura de dados com integridade relacional:
- Elaboração do layout e “inteligência” do relatório
Header, Body, Footer:
- Uso de patterns – dados agrupados, tabular, matriz, colunas múltiplas, gráficos.
Criação de parâmetros, formatação condicional:
- Recuperação dos dados, preenchimento do dataset e bind com o relatório
- APIs do ADO .NET, Stored Procedures, T-SQL
- Controle ReportViewer
Template de aplicação
Para nossos exemplos, tomaremos uma aplicação Windows Forms, como
apresentado na figura abaixo. Atente para as pastas DataSources e
Reports, onde respectivamente armazenaremos os DataSets e os relatórios
criados.
 Figura 2.4 – template de aplicação
Repositório de dados local – dataset
Relatórios são representações formatadas de um conjunto de registros
provenientes de uma consulta em um repositório de dados. Para os
relatórios criados na plataforma do Reporting Services é necessário um
DataSet tipado com uma ou mais tabelas, que serão a estrutura de dados
volátil contendo as informações dos relatórios. Esse dataSet será
preenchido no aplicativo que hospeda o relatório e será utilizado na sua
formatação.
Nota: Um DataSet é uma representação na memória de um banco de dados relacional. Maiores informações, consultar a página do MSDN especifica sobre essa estrutura de dados.
 Figura 2.5 – criação de datasets
Podemos criar objetos DataSets de diversas formas.
Utilizaremos aqui o wizard do Visual Studio para a criação dos nossos,
bem como das tabelas necessárias para criação dos relatórios. Nesse
primeiro exemplo teremos um relatório tabular com os produtos, suas
respectivas categorias, quantidade em estoque e valor unitário. Então,
modelaremos um dataset com uma única tabela contendo esses campos como
mostrado na figura 2.6. A figura 2.5 ilustra a criação de um novo
dataset através da inclusão de um novo item (DataSet) ao projeto.
 Figura 2.6 – datatable do dataset exemplo
Formatando os relatórios
Tipos e estrutura do relatório
Uma vez modelado o DataSet, é hora de utilizá-lo para formatar o
relatório. O primeiro passo é decidir que tipo de relatório será
utilizado. Por exemplo, se os dados estiverem relacionados a agrupamento
de itens, a melhor escolha é utilizar um relatório tabular (como no
caso desse nosso primeiro exemplo). No entanto, relatórios com gráficos
são mais indicados para representar dados sumarizados. A estrutura dos
relatórios do RS inclui três sessões como mostrado na figura 2.7:
- Header: indicado para incluir informações estáticas referentes ao
relatório, tais como título, data, logo da empresa e, se for o caso,
alguns dos parâmetros informados pelo usuário;
- Body: é a região dos detalhes do relatório, onde os dados
provenientes das consultas (armazenados no DataSet), filtros e ordenação
serão exibidos;
- Footer: ideal para outras informações do relatório, tais como número de página e informações de direitos autorais.
 Figura 2.7 – sessões do relatório e dataSet
Report itens
Parte fundamental da formatação dos relatórios, os report items,
disponíveis na Toolbox do Visual Studio, funcionam como um canal entre o
DataSource e a estrutura do relatório. Os Report Itens são simples
objetos, parecidos com os controles das aplicações Window e Web Forms, e
como tal, o grande segredo do bom uso desses itens é conhecer suas
propriedades. A figura 2.8 apresenta nossa caixa de ferramentas, onde já
utilizamos alguns textbox e um table para formatar as sessões header e
body.
 Figura 2.8 – Toolbox
A tabela a seguir descreve resumidamente os itens da nossa caixa de ferramentas:
Item |
Descrição |
Poiter |
Seleciona os itens do relatório. |
Textbox |
Item mais utilizado da toolbox – exibe informações provenientes do datasource ou mesmo textos estáticos. |
Line |
Desenha uma linha como separador de informações. |
Table |
Exibe detalhadamente as informações do relatório em formato tabular, além de disponibilizar sessões de cabeçalho e rodapé. |
Matrix |
Exibe detalhadamente as informações do relatório correlacionando linhas e colunas. |
Rectangle |
Agrupa informações relacionadas. |
List |
Exibe detalhadamente as informações do
relatório. Parecido com o table, no entanto sem tantos recursos, tais
como as sessões de cabeçalho e rodapé. |
Image |
Permite inserir imagens no relatório. |
Subreport |
Inclui outro(s) relatório(s) dentro de um relatório principal. |
Chart |
Exibe as informações do relatório em formato gráfico, com diversas opções de formatação. |
Mais informações sobre os itens mais importantes:
- Textbox
Pode-se dizer que não é possível construir um relatório sem o Textbox,
que é sem dúvida o componente mais versátil que temos à disposição. Ele
pode ser utilizado para diversas finalidades, como o título do relatório
no header e a exibição de totalizadores. Esse controle é usado para
exibir textos estáticos, fazer bind com data source, campos calculados e
expressões. - Table
É o melhor item para relatórios detalhados. Cada tabela possui uma
estrutura com sessões Header, Detail e Footer – não confundir com as
sessões homônimas do próprio relatório. O Header é indicado para os
nomes das colunas; no Details, temos um conjunto de linhas provenientes
do datasource e, finalmente, no Footer, temos informações sumarizadas
dos dados do relatório. É possível ter mais de uma tabela em um
relatório. É muito importante dominar quais são as propriedades do
componente Table (figura 2.9 abaixo) – especialmente as tabs Groups,
onde é possível configurar diversos agrupamentos das informações e
Filter, onde podemos estabelecer restrições aos dados visíveis aos
usuários.
 Figura 2.9 – Table Properties
Subreport
Um relatório é considerado um subreport quando inserido em outro
relatório. O sub-relatório funciona como um filho do relatório que o
hospeda (parent), tornando os sub-relatórios uma poderosa ferramenta
para, por exemplo, implementar o tão requisitado conceito master/detail.
No entanto é preciso ter muita cautela na sua utilização, uma vez que
temos perdas consideráveis na performance do relatório.
Chart
O item Chart é responsável pela apresentação de informações numéricas
em formato de gráficos. As ferramentas de gráficos foram inseridas nos
relatórios do RS pela empresa Dunda Software, estando à disposição os
tipos mais comuns de gráficos: pizza, barra e colunas.
Formatação
Não se faz um relatório capaz de atrair a atenção dos leitores se
suas informações não forem bem formatadas. Dados numéricos, por exemplo,
são muito melhor compreendidos se devidamente formatados conforme seu
tipo – numérico inteiro, decimal, moeda ou científica, por exemplo.
Outra informação digna de atenção na sua formatação são os campos
referentes à data e hora. No processo de criação dos relatórios, a
formatação é feita através de uma caixa de dialogo na tab Format das
propriedades de uma caixa de texto, vide abaixo – figura 2.10.
 Figura 2.10 – Formatação texto
Dicas importantes:
- Certifique-se que o tipo do campo esteja devidamente bem definido no DataTable, do contrário a formatação simplesmente não funciona. E o tipo default dos campos é System.String;
- Garanta que o idioma do relatório esteja devidamente configurado;
- Considere o uso de Expressions do tipo, Common Functions à Text (Format, FormatCurrency, FormatDateTime, FormatNumber e FormatPercent).
Ainda com o intuito de tornar nossos relatórios atrativos aos
usuários, outros atributos das caixas de texto podem ser customizados,
tais como Fontes, Cor, Alinhamento e Decoração. Todos esses, além de
outros atributos, podem ser configurados na janela de propriedades do
Textbox, como mostrado na figura 2.11.
 Figura 2.11 – Formatação texto
Dentro da formatação, eis um recurso muito poderoso dos relatórios do
RS, que é a formatação condicional, onde através do editor de Expressions, que utiliza um dialeto da linguagem Visual Basic, é possível criar instruções condicionais como a descrita abaixo.
=IIf(Fields!QT_ESTOQUE.Value<230,”Red”,”Blue”)
Parametrização
Os relatórios possuem um mecanismo de parametrização onde é possível
passar informações a partir do cliente para o relatório em tempo de
execução. A figura 2.12 ilustra a janela Report Parameters para criação dos parâmetros de um relatório, onde para acessar, basta clicar com o botão direito fora das sessões do relatório.
 Figura 2.12 – parâmetros
Os parâmetros aqui criados podem ser utilizados para formatação condicional ou em expressões. Ao contrário dos relatórios remote mode,
esse modelo de relatórios não tem uma área para que o usuário selecione
ou digite o valor dos parâmetros, sendo responsabilidade do cliente
providenciar uma interface para coleta dessas informações. Dessa forma,
gerar o conjunto de dados devidamente filtrado e carregá-lo no dataSet,
os parâmetros são pouco utilizados para seleção dos registros, uma vez
que é mais indicado fazer essa restrição diretamente na pesquisa, ainda
que tenhamos como aplicar filtros (propriedade das tabelas, tab
Filters). Essa funcionalidade é mais indicada para criação de relatórios
do tipo master/detail com subreports.
Consumindo o relatório
Controle reportviewer
Para interação dos relatórios com os clientes, temos o controle
ReportViewer, disponível no visual Studio em duas versões – uma para web
e outra para Windows forms. Com ele é possível disponibilizar para as
aplicações um conjunto de funcionalidades, tais como:
- Exportação dos dados nos formatos Excel e PDF;
- Suporte a impressão e visualização de impressão do relatório
- Rica interatividade com navegação, document map, bookmarks e ordenação;
- Pesquisa de texto no corpo do relatório;
- Zoom.
O controle é capaz de processar e renderizar os relatórios
independente do seu modelo, local ou remote. A figura abaixo exibe o
controle ReportViewer em ação renderizando um relatório.
 Figura 2.13 – reportviewer
Parte dos recursos do ReportViewer, tais como Zoom, botão Stop, os
botões de pesquisa, de exportação, impressão, dentre outros, podem ser
desativados na sua janela de propriedade, como mostrado na figura
abaixo. Outra propriedade importantíssima do ReportViewer é seu
ProcessingMode.
 Figura 2.14 – propriedades do reportviewer
Código cliente
Uma vez modelados, o relatório e seu respectivo DataSet, chegou a
hora de relacionar tudo. E como já dissemos, todo processamento é feito
no cliente – da obtenção dos dados no repositório para carga do dataset,
à renderização do relatório via controle ReportViewer. A figura 2.15
apresenta o fluxo padrão de um código cliente para utilização de
relatórios RS em client-mode.
 Figura 2.15 – fluxo padrão do código cliente
Eis um pseudocódigo utilizado em um cliente de um relatório local mode.
string cnString = "Database=[banco];Server=[servidor];User Id=sa;PassWord=sa";
SqlConnection conReport = new SqlConnection(cnString);
SqlCommand cmdReport = new SqlCommand();
DataSet dsReport = new WFormReport.DataSources.ProdutosporCategoria();
conReport.Open();
SqlParameter[] parms = {new SqlParameter("@idCategorias", SqlDbType.VarChar,20)};
parms[0].Value = “1,2,3”;
cmdReport.CommandType = CommandType.StoredProcedure;
cmdReport.Connection = conReport;
foreach (SqlParameter parm in parms)
cmdReport.Parameters.Add(parm);
cmdReport.CommandText = "getProdutosinCategorias";
SqlDataReader drReport = cmdReport.ExecuteReader();
dsReport.Tables[0].Load(drReport);
drReport.Close();
conReport.Close();reportViewer1.LocalReport.ReportPath = “ProdutosporCategoria.rdlc";ReportDataSource rds = new ReportDataSource();rds.Name = "ProdutosporCategoria_ProdutosEstoque";
rds.Value = dsReport.Tables[0];reportViewer1.LocalReport.DataSources.Clear();
reportViewer1.LocalReport.DataSources.Add(rds);
reportViewer1.RefreshReport();
Por hoje é isso pessoal. Na próxima edição imperdível, trarei só códigos! Diversos exemplos para boas horas de diversão.
Grande abraço e até lá. *** Artigo de Caio Azevedo
|
Olá pessoal,
Neste artigo eu gostaria de mostrar e falar um pouco sobre como escrever log no event view do Windows, usando a linguagem C#.NET. São dois métodos simples. É basicamente criar um novo item junto do event view, ficando assim mais um item na tela de evento.
Itens utilizados:
- Ferramenta: Visual Studio .NET
- Tipo da plataforma: Classe geral
Figura 1.

O item marcado como Transferir Arquivos foi criado pelo código. Então vamos lá!
O primeiro método chamado EscreverLog passa quatro parâmetros do tipo string e EventLogEntryType.
No caso deste artigo, vou mostrar o método que verifica se foi
passado o nome do diretório (Transferir Arquivos). Por exemplo, se não
for passado o nome do diretório, o log será gravado dentro do item
(Aplicativo) conforme mostrado na figura 1.
Code 1.
public static void EscreverLog(string source, string logName, string message, EventLogEntryType type) { if (String.IsNullOrEmpty(source)) { throw (new ArgumentException(Resources.NullOrEmptyValue, "source")); }
if (String.IsNullOrEmpty(message)) { throw (new ArgumentException(Resources.NullOrEmptyValue, "message")); }
EventLogWriter.VerificaDiretorio(source, logName);
EventLog.WriteEntry(source, message, type); }
Note
que na penúltima linha existe um método chamado VerificaDiretorio (source, logName). Esse método verifica se a
string logName é igual a null.
Se for
igual a null, ele grava o log dentro do item Application ou Aplicativo.
Se não for igual a null, ele cria um item (como se fosse um diretório)
dentro do
event view de acordo com o nome passado. O código 2 mostra como é
feito.
Code 2.
private static void VerificaDiretorio(string source, string logName) { if (String.IsNullOrEmpty(logName)) { logName = "Application"; }
if (!EventLog.SourceExists(source)) { EventSourceCreationData sourceData = new EventSourceCreationData(source, logName);
EventLog.CreateEventSource(sourceData); } }
Criei
um outro método público chamado EscreverErro
com apenas dois parâmetros de entrada, isso significa que, o evento será
gravado dentro do item padrão do event view. Ele não cria um novo item, apenas
registra. Com estes métodos você pode usar um ou outro dependendo da sua
necessidade.
Code 3.
public static void EscreverErro(string source, string message)
{
EventLogWriter.Write(source, null, message, EventLogEntryType.Error);
}
Lembre-se
que no código 1, o último parâmetro é do tipo EventLogEntryType
que identifica o ícone de registro. Outra dica importante é colocar no início da
sua classe o using System.Diagnostics.
É necessário para entender o EventLogEntry.

Espero
que tenham gostado desta forma de escrita do log no event view do Windows usando linguagem C#.NET.
Qualquer dúvida pode entrar em contato, ou deixe suas impressões e testes no espaço abaixo para comentários.
Até à próxima!
|
Olá,
pessoal!
Neste artigo, gostaria de informar e mostrar como abrir uma tela modal usando o
ModalPopupExtender, depois que executou alguma pesquisa ou regra
dentro do código C#.NET. Funciona para as outras linguagens, mas o meu teste
está sendo feito apenas com a linguagem C#.NET.
Referências:
- Ferramenta:
Visual Studio 2010
- Linguagem:
C#.NET
- Plataforma:
ASP.NET - AjaxControlToolkit
O
AjaxControlToolkit foi desenvolvido para ajudar os desenvolvedores na criação de
web sites e aplicativos web. Você pode fazer download da dll ou código fonte aqui.
Em um artigo anterior, mostrei como usar o ModalDialogExtender, falei de css e do código para chamar a tela. O
problema maior foi que a tela é mostrada sem que acesse diretamente o código
para qualquer processamento antes de aparecer.
Veremos primeiro o processamento dentro da linguagem e no final, o
resultado será mostrado dentro da tela modal. Dessa maneira, fica muito mais
fácil usar essa grande funcionalidade, que evita abrir popup que muitas vezes
são bloqueados pelos browsers.
Mostrando o código
O
primeiro passo é colocar a dll referenciada em seu Toolbox. Criei uma nova aba e adicionei a dll que fiz download no
site asp.net.

Para
colocar todas as funcionalidades mostradas na Imagem 1, clique com o botão
direito em cima do Toolbox e
selecione a opção Add Tab.

Coloque
o nome que quiser na nova aba criada. Clique dentro da aba com o botão direito e
escolha a opção chamada Choose Items. Uma
tela nova é aberta para a indicação da dll.

Depois
de abrir a tela com as dlls, clique em Browser
e indica a dll localizada em um lugar do seu computador.

Depois
destes passos, vamos começar a desenvolver uma página de exemplo. Arraste
o componente da Toolbox chamado ModalPopupExtender para a página .aspx. Automaticamente
o componente coloca no início da página uma indicação.
<%@ Register Assembly="AjaxControlToolkit" Namespace="AjaxControlToolkit" TagPrefix="cc1" %>
Para
que funcione perfeitamente a popupextender, é necessário criar um Panel
normal dentro da página e com os componentes dentro. Componentes como GridView, Formulário, Image e outros do
.NET.
<asp:Panel id="pnlImagem" runat="server" CssClass="modalPopup" Style="display:none" Width="600px">
<div align="center">
<asp:Image ID="imgChequinhos" runat="server" Width="600px" />
<asp:Button ID="cmdFechar" runat="server" Text="Fechar" />
</div>
</asp:Panel>
Note
que coloquei o nome do Painel de pnlImage, o CssClass coloquei o modalPopup criado no artigo anterior e
um Style=”display:none” para não
aparecer na tela, só quando eu chamar.
Depois
de criar o Painel, criei um label
normal chamada lblTeste.
<asp:Label ID="lblTeste" runat="server"></asp:Label>
Ainda
falta colocar o modal indicando o painel e o label.
<cc1:ModalPopupExtender ID="ModalPopupExtender1" runat="server"
BackgroundCssClass="modalBackground"
CancelControlID="cmdFechar" DropShadow="true"
PopupControlID="pnlImagem" PopupDragHandleControlID="panel3" TargetControlID="lblTeste">
</cc1:ModalPopupExtender>
Note
que foi adicionada uma propriedade chamada BackgroundCSSClass=”modalBackground”
indicando a parte do css, foi adicionado também um botão para fechar a tela
CancelControlID=”cmdFechar” localizado dentro do painel (code 2), foi colocado também a propriedade
PopupControlID=”pnlImagem”, que é o nome do painel criado, e a
TargetControlID=”lblTeste” indicando a label.
Após o
processamento de um clique qualquer, o código passa pelos métodos e depois
mostra o popup. No exemplo, no clique da grid ele deve mostrar uma imagem
de acordo com o registro.

Usei o
RowCommand para fazer essa funcionalidade. Não vou detalhar muito porque não é
o nosso foco falar dessa propriedade do grid. Mas depois de clicado e
processado, que chamo o modal .Show();
protected void gridImagem_RowCommand(object sender, GridViewCommandEventArgs e)
{
if (e.CommandName == "PesquisarImagem")
{
ModalPopupExtender1.Show();
}
}
O nome
do id modal chama ModaPopupExtender1,
assim basta chamar o Show. O segredo está no componente label adicionado na
página e indicado no TargetControlID. No artigo anterior, o que era indicado
nessa propriedade era um botão e no clique dele aparecia o popup sem que
passasse pelo código .cs. Agora o processamento é feito primeiro para depois
aparecer o popup.

Fico
por aqui e qualquer dúvida pode entrar em contato.
artigo publicado originalmente no iMasters, por Mauricio Junior
|
Confira uma forma bem resumida de como criar uma
aplicação ASP .NET em 3 camadas usando a linguagem C#. Acompanhe cada
etapa e deixe suas impressões ao final do artigo.
O significa criar uma aplicação em camadas?
Quando acessa a página do seu banco na internet, você está usando uma
aplicação que possui uma tela de apresentação, na qual o usuário recebe
e entra com as informações.
- Quando você faz o login na sua conta acessando a página do seu
banco na internet, existe uma interface na qual você informa seu login e
senha.
- Quando você submete essa informação, a aplicação aplica as regras de negócios para verificar se seu login e senha são válidos.
- Para isso, a aplicação consulta um cadastro de informações, que está
em um banco de dados, e verifica se o que o usuário digitou corresponde
ao que está no cadastro.
Com esse exemplo bem simples, podemos perceber que temos três partes distintas atuando:
- A interface representada pela tela de login solicitando login e senha.
- As regras de validação que serão aplicadas representando as regras de negócio.
- As informações armazenadas no cadastro representando o banco de dados.
A figura abaixo procura mostrar de forma resumida esses três componentes, identificando e nomeando cada um deles.

Podemos identificar as seguintes camadas:
- Camada de Apresentação (Presentation Tier)
- Camada de Negócios (Business Logic Tier)
- Camada de Acesso a dados (Data Tier)
Embora para o cliente tudo seja apenas uma única aplicação, para o
desenvolvedor criar uma aplicação em camadas significa desenvolver
separadamente cada um dos componentes identificados no exemplo acima de
forma a facilitar a manutenção e a ganhar produtividade.
Chama-se a isso uma aplicação com arquitetura em três camadas. Lembrando que podemos ter aplicações em n-camadas. Resumindo:
A arquitetura em três camadas é uma arquitetura cliente
servidor na qual a interface do usuário, os processos de negócios e o
armazenamento de dados são desenvolvidos e mantidos em módulos
independentes, ou em plataforma separadas.
Basicamente existem três camadas:
- Camada de apresentação: User Interface (UI)
- Camada de Negócios: Business Logic Layer (BLL)
- Camada de Acesso a dados: Data Access Layer (DAL)
Cada camada pode ser desenvolvida e testada separadamente. Para a
nossa aplicação ASP .NET, podemos resumir a arquitetura em três camadas
da seguinte forma:

- A camada de apresentação contém os elementos da interface do
usuário do site e acrescenta toda a lógica que inclui a interação entre o
visitante e as regras de negócio. (ASP .NET Web Forms, Users Controls e
Master Pages)
- A camada de negócio (BLL) recebe a requisição da camada de
apresentação e retorna o resultado dependendo da lógica de negócio.
(Classes C#)
- A camada de acesso a dados contém as classes que acessam o banco de
dados e retornam o resultado a camada de negócio. (Classes C#)
Criando a aplicação ASP .NET em três camadas
Definindo o banco de dados, a tabela e a stored procedure
Em nosso exemplo, iremos criar uma aplicação ASP .NET para gerenciar as informações de clientes existentes na tabela Clientes do banco de dados Macoratti.mdf do SQL Server. O script para gerar o banco de dados Macoratti.mdf e a tabela Clientes é apresentado abaixo:
CREATE DATABASE [Macoratti] ON PRIMARY ( NAME = N'Macoratti', FILENAME = N'c:Program FilesMicrosoft SQL ServerMSSQL10.SQLEXPRESSMSSQLDATAMacoratti.mdf' , SIZE = 3072KB , MAXSIZE = UNLIMITED, FILEGROWTH = 1024KB ) LOG ON ( NAME = N'Macoratti_log', FILENAME = N'c:Program FilesMicrosoft SQL ServerMSSQL10.SQLEXPRESSMSSQLDATAMacoratti_log.ldf' , SIZE = 1024KB , MAXSIZE = 2048GB , FILEGROWTH = 10%) GO
USE [Macoratti] GO
CREATE TABLE [dbo].[Clientes]( [id] [int] IDENTITY(1,1) NOT NULL, [nome] [nvarchar](50) NULL, [email] [nvarchar](150) NULL, [nascimento] [date] NULL, CONSTRAINT [PK_Clientes] PRIMARY KEY CLUSTERED ( [id] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] ) ON [PRIMARY]
GO
Se você desejar incluir dados na tabela Clientes usando o SQL Server Management Studio, pode usar o seguinte script:
INSERT INTO [Macoratti].[dbo].[Clientes] ([nome] ,[email] ,[nascimento]) VALUES (<nome, nvarchar(50),> ,<email, nvarchar(150),> ,<nascimento, date,>) GO
Em VALUES, inclua os dados que deseja incluir. O banco de dados Macoratti.mdf foi criado no SQL Server Management Studio e nele também foi criado uma stored procedure chamada GetClientes, conforme mostra a figura abaixo:

Essa stored procedure GetClientes oferece acesso à tabela Clientes e retorna todos os registros da tabela.
Vamos usar o Visual Web Developer 2010 Express Edition para criar o nosso site. No menu File, clique em New Web Site e a seguir selecione a linguagem Visual C#, o template ASP .NET Empty Web Site, informe o nome ASPNET_3Camadas e clique no botão OK.

Criando o projeto no Visual Web Developer Express
Na janela Solution Explorer, você poderá ver a estrutura do projeto contendo apenas o arquivo web.config. Vamos incluir uma Master Page no projeto. No menu WebSite, selecione Add New Item e a seguir selecione o template Master Page, informe o nome Site.master e clique no botão Add.

Após incluir a Master Page, vamos incluir nela uma tabela com 3 linhas e 1 coluna a partir do menu Table->Insert Table, definindo na página o seguinte layout:

Definindo as Classes do projeto
Vamos agora definir três classes em nosso projeto:
- Configuração: classe responsável por obter a string de conexão e o nome do provedor usado.
- AcessoDados: classe que contém os métodos para acesso aos dados.
- Cliente: classe que irá chamar os métodos da classe AcessoDados.
Vamos criar uma nova pasta no projeto chamada App_Code para conter essas três classes.
A pasta App_Code é uma pasta especial na qual você
pode armazenar seu código-fonte e ele será compilado automaticamente em
tempo de execução.O assembly resultante está acessível a todos os outros
códigos no aplicativo da Web. Dessa forma, a pasta App_Code funciona como a pasta Bin, exceto pela possibilidade de armazenar código-fonte nela em vez de código compilado.
A pasta App_Code e seu status especial em um
aplicativo ASP.NET tornam possível criar classes personalizadas e outros
arquivos que contém somente código-fonte e usá-los em seu aplicativo da
Web sem ter que compilá-los independentemente.
A pasta App_Code pode conter quantos arquivos e
sub-pastas quanto você precisar. Você pode organizar seu código-fonte de
qualquer forma que você achar conveniente.
No menu WebSite, clique em Add ASP .NET Folder e selecione App_Code:

Criando a classe Configuracao.cs
Vamos agora criar a classe Configuracao.cs na pasta App_Code. Clique com o botão direito do mouse sobre a pasta App_Code e selecione Add New Item. Selecione o template Class, informe o nome Configuracao.cs e clique no botão Add. Em seguida, digite o código abaixo na classe Configuracao.cs:
using System.Configuration;
public static class Configuracao { private static string dbConnectionString; private static string dbProviderName;
static Configuracao() { dbConnectionString = ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString; dbProviderName = ConfigurationManager.ConnectionStrings["ConnectionString"].ProviderName; }
public static string DbConnectionString { get { return dbConnectionString; } }
public static string DbProviderName { get { return dbProviderName; } } }
Nesse código, estamos usando o namespace System.Configuration, pois vamos obter a string de conexão e o nome do provedor a partir do arquivo de configuração Web.Config.
Vamos então abrir o arquivo Web.Config e incluir na seção connectionStrings a string de conexão para acesso ao banco de dados Macoratti, além do nome do provedor conforme abaixo:
<connectionStrings> <add name="ConnectionString" connectionString="Data Source=.SQLEXPRESS;Initial Catalog=Macoratti;Integrated Security=True" providerName="System.Data.SqlClient"/> </connectionStrings>
Criando a classe AcessoDados.cs
Clique com o botão direito do mouse sobre a pasta App_Code e selecione Add New Item. Selecione o template Class, informe o nome AcessoDadaos.cs e clique no botão Add. Em seguida, digite o código abaixo na classe AcessoDados.cs:
using System; using System.Data; using System.Data.Common;
namespace Macoratti { public static class AcessoDados { static AcessoDados() { }
public static DbCommand CreateCommand() { string dbProviderName = Configuracao.DbProviderName; string dbConnectionString = Configuracao.DbConnectionString; DbProviderFactory factory = DbProviderFactories.GetFactory(dbProviderName); DbConnection connection = factory.CreateConnection(); connection.ConnectionString = dbConnectionString; DbCommand command = connection.CreateCommand(); command.CommandType = CommandType.StoredProcedure; return command; }
public static DataTable ExecuteReader(DbCommand command) { DataTable table; try { command.Connection.Open(); DbDataReader reader = command.ExecuteReader(); table = new DataTable(); table.Load(reader); } catch (Exception ex) { throw ex; } finally { command.Connection.Close(); } return table; }
public static int ExecuteNoneQuery(DbCommand command) { int linhasAfetadas = -1; try { command.Connection.Open(); linhasAfetadas = command.ExecuteNonQuery(); } catch (Exception ex) { throw ex; } finally { command.Connection.Close(); } return linhasAfetadas; }
public static string ExecuteScalar(DbCommand command) { string valor = ""; try { command.Connection.Open(); valor = command.ExecuteScalar().ToString(); } catch (Exception ex) { throw ex; } finally { command.Connection.Close(); } return valor; } } }
Nessa classe, definimos 4 métodos para acessar os dados:
- CreateCommand: cria um novo comando a partir do nome do provedor
O método CreateCommand() é do tipo DbCommand e cria
um novo comando usando uma fábrica de provedores, além de utilizar o
nome do provedor e a string de conexão para criar um comando para o
provedor definido no arquivo Web.Config.
O novo modelo de provedor disponível a partir da ADO.NET 2.0 está baseado em um série de classes base no namespace System.Data.Comom. A classe DBProviderFactories permite a realização de dois tipos de tarefas:
- Obter uma lista de todos os provedores existentes via método estático GetFactoryClasses
- Criar uma instância de um determinado Factory conforme o seu tipo via método GetFactoryClass
Uma classe base de provedor é um objeto factory, que é usado para criar um conjunto de objetos relacionados como SqlConnection e SqlCommand. Eles retornam um tipo de classe abstrata do tipo DBConnection.
As classes de provider factory são derivadas de uma classe base abstrata: System.Data.Common.DbProviderFactory. Para cada tipo de base de dados a ser acessado, temos uma nova classe derivada dessa classe base abstrata. A classe DbDataProvider define o número de funções que essa subclasse precisa implementar:
CreateComand() |
Cria um objeto
Command derivado de DBCommand. |
CreateCommandBuilder() |
Cria um objeto derivado de DbCommandBuilder |
CreateConnection() |
Cria um objeto
derivado de DbConnection. |
CreateConnectionStringBuilder() |
Cria um objeto
derivado de DbConnectionStringBuilder |
CreateDataAdapter() |
Cria um objeto
derivado de DbDataAdapter. |
CreateDataSourceEnumerator() |
Cria um objeto
derivado de DbDataSourceEnumerator. |
CreateParameter() |
Cria um objeto
derivado de DbParameter. |
CreatePermission() |
Cria um objeto
derivado de CodeAccessPermission, |
Funções
DbDataProvider |
Desde que o DbProviderFactory apropriado foi criado, a função na tabela acima pode ser usada para criar o objeto apropriado em vez de usar o operador New como anteriormente. Para determinar todas as classes DbProviderFactory disponíveis e criar suas classes adicionais, é fornecida a classe System.Data.Common.DbProviderFactories.
Cada provedor de dados faz o registro de uma classe ProviderFactory no arquivo machine.config da plataforma .NET. A classe base DbProviderFactory e a classe ProviderFactories podem retornar um DataTable de informações sobre os diferentes provedores registrados no arquivo machine.config. Eles podem recuperar a ProviderFactory conforme a sequência do provedor fornecida ou um DataRow de um DataTable.
- ExecuteReader: retorna um DataTable usando para
instruções SELECT com objetivo de obter os dados retornado por consultas
SQL usando SELECT
O método ExecuteReader possui um parâmetro DbCommand. Esse comando irá obter um DataTable resultado da consulta SELECT. O DbDataReader irá ler todos os dados a partir das tabelas e finalmente o comando irá retornar o resultado como um DataTable.
- ExecuteNonQuery: usado para instruções INSERT, UPDATE,
DELETE. Neste caso, não teremos dados retornados apenas as
linhas(registros) que foram afetadas
- ExecuteScalar: usado para obter somente o primeiro dado retornado pela consulta SELECT
Criando a classe Cliente.cs
Clique com o botão direito do mouse sobre a pasta App_Code e selecione Add New Item. Selecione o template Class, informe o nome Cliente.cs e clique no botão Add. Em seguida, digite o código abaixo na classe Cliente.cs:
using System.Data; using System.Data.Common;
namespace Macoratti { public class Cliente { public static DataTable GetClients() { DbCommand command = AcessoDados.CreateCommand(); command.CommandText = "GetClientes"; return AcessoDados.ExecuteReader(command); } } }
Nesse código, criamos um comando para usar a stored procedure GetClientes, criada no banco de dados Macoratti.mdf. A seguir, executamos o método ExecuteReader da classe AcessoDados que retornar um DataTable com os dados dos clientes.
Definindo a camada de apresentação
Vamos incluir no projeto um novo Web Forms para exibir as informações da tabela Clientes usando as classes que criamos nos tópicos anteriores. No menu WebSite, clique em Add New Item e a seguir selecione o template Web Form. Informe o nome ListaClientes.aspx, marque a opção Select master page e clique no botão Add.

A seguir, selecione a master page Site.master e clique em OK.

Em seguida, na página ListaClientes.aspx, inclua um controle GridView alterando seu ID para gdvClientes. A seguir, abra o arquivo ListaClientes.aspx.cs e defina o código abaixo no evento Load da página:
namespace Macoratti {
public partial class _Default : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { gdvClientes.DataSource = Cliente.GetClientes(); gdvClientes.DataBind(); } } }
Pegue o projeto completo Versão C# e compartilhe seus experimentos em três camadas.
Até a próxima!
artigo publicado originalmente no iMasters, por José Carlos Macoratti
|
Programar se aprende programando, certo? E nada
melhor para aprender do que ter um protótipo funcional com o código
fonte a partir do qual podemos estudar.
Este singelo projeto feito na linguagem C# realiza o acesso e as
operações de inclusão, edição e exclusão em uma base de dados SQL
Server.
Vamos ao que interessa...
O projeto poderá ser aberto nos seguintes IDEs:
Além disso você deverá instalar os seguintes recursos:
O banco de dados SQL Server
A aplicação acessa a tabela Livros de um banco de dados SQL Server
definido como Catalogo. Na figura abaixo temos a estrutura da tabela:
 O script para criar o banco de dados, as tabelas e as stored procedures no SQL Server é dado a seguir:
USE [Catalogo] GO /****** Object: Table [dbo].[Autores] Script Date: 03/28/2011 10:52:09 ******/ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO CREATE TABLE [dbo].[Autores]( [autorid] [int] IDENTITY(1,1) NOT NULL, [nome] [nchar](10) NULL, CONSTRAINT [PK_Autores] PRIMARY KEY CLUSTERED ( [autorid] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] ) ON [PRIMARY] GO /****** Object: Table [dbo].[Livros] Script Date: 03/28/2011 10:52:09 ******/ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO CREATE TABLE [dbo].[Livros]( [livroid] [int] IDENTITY(1,1) NOT NULL, [autorid] [int] NOT NULL, [titulo] [nvarchar](150) NULL, [preco] [money] NULL, CONSTRAINT [PK_Livros] PRIMARY KEY CLUSTERED ( [livroid] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] ) ON [PRIMARY] GO /****** Object: StoredProcedure [dbo].[SelAutores] Script Date: 03/28/2011 10:52:08 ******/ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO CREATE PROCEDURE [dbo].[SelAutores] AS SELECT * FROM Autores RETURN GO /****** Object: StoredProcedure [dbo].[SchLivros] Script Date: 03/28/2011 10:52:08 ******/ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO CREATE PROCEDURE [dbo].[SchLivros] AS SELECT * FROM Livros RETURN GO /****** Object: StoredProcedure [dbo].[IncluirAutor] Script Date: 03/28/2011 10:52:08 ******/ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO -- ============================================= -- Author: <Author,,Name> -- Create date: <Create Date,,> -- Description: <Description,,> -- ============================================= CREATE PROCEDURE [dbo].[IncluirAutor] @nome nvarchar(150) AS INSERT INTO Autores (nome) Values(@nome) GO
Você pode executar o script acima no SQL Server Management Studio para criar o banco de dados e as tabelas.
A interface da aplicação
A seguir temos a interface da aplicação no formulário form1.cs que utiliza os seguintes controles:
- DataGridView - dgvLista;
- TextBox - txtPesquisar, txtTitulo e txtPreco;
- Button - btnAtualizar, btnSalvar, btnCancelar, btnIncluir, btnDeletar e btnFechar;

O código da aplicação (partes principais)
No início do formulário temos a definição dos namespaces usados no projeto:
using System; using System.Data; using System.Drawing; using System.Windows.Forms; using System.Data.SqlClient;
Note que estamos referenciando o namespace para acessar as classes ADO .NET para o SQL Server.
A
seguir logo após a declaração do formulário temos a definição das
variáveis ADO .NET para conexão com o banco de dados SQL Server:
SqlConnection sqlCon = new SqlConnection(); SqlDataAdapter daLivros = new SqlDataAdapter(); DataSet dsLivros = new DataSet();
A string de conexão usada no programa é a seguinte:
sqlCon.ConnectionString = @"Data Source=.SQLEXPRESS;Initial Catalog=Catalogo;Integrated Security=True";
Se você pretende usar outro banco de dados basta alterar os nomes dessas variáveis conforme o provedor pertinente.
1 - Código da rotina SalvaMudancas() - Esta rotina verifica qual a
ação a ser realizada : inclusão ou edição dos dados. Para incluir
informações é usado os métodos NewRow()/Add e para atualizar os dados
BeginEdit()/EndEdit() e ao final o método Update();
private void SalvaMudancas() { try { SqlCommandBuilder cbLivros = new SqlCommandBuilder(daLivros);
DataTable dtLivros = dsLivros.Tables["tblLivros"]; DataRow drLivros;
if (isIncluirFlag) { drLivros = dtLivros.NewRow();
drLivros["titulo"] = txtTitulo.Text; drLivros["preco"] = Convert.ToDecimal(txtPreco.Text); dtLivros.Rows.Add(drLivros); } else if (isEditarFlag) { drLivros = dtLivros.Rows.Find(dgvLista.SelectedRows[0].Cells[0].Value);
drLivros.BeginEdit(); drLivros["titulo"] = txtTitulo.Text; drLivros["preco"] = Convert.ToDecimal(txtPreco.Text); drLivros.EndEdit(); }
daLivros.Update(dsLivros, "tblLivros"); formataGridView(); } catch (Exception ex) { MessageBox.Show(ex.Message.ToString()); }
AtualizaDataSet();
SetButtons(true); SetEnabled(false); }
2 - Código do botão Deletar - O código utiliza o método Find e a
seguir o método Delete; ao final para persistir as alterações usa o
método Update();
private void btnDeletar_Click(object sender, EventArgs e) { if (MessageBox.Show("Tem certeza?", "Deletar", MessageBoxButtons.YesNo) == DialogResult.Yes) { try { DataTable dtLivros = dsLivros.Tables["tblLivros"]; DataRow drLivros;
if (dgvLista.SelectedRows.Count > 0) { drLivros = dtLivros.Rows.Find(dgvLista.SelectedRows[0].Cells[0].Value); drLivros.Delete();
SqlCommandBuilder cbLivros = new SqlCommandBuilder(daLivros);
daLivros.Update(dsLivros, "tblLivros"); AtualizaDataSet(); } } catch (Exception ex) { MessageBox.Show(ex.Message.ToString()); } } }
3 - Código do evento Click do DataGridView
private void dgvLista_CellClick(object sender, DataGridViewCellEventArgs e) { if (e.RowIndex > -1) { txtTitulo.Text = dgvLista.Rows[e.RowIndex].Cells[2].Value.ToString(); txtPreco.Text = dgvLista.Rows[e.RowIndex].Cells[3].Value.ToString(); } }
No evento Click do controle DataGridView estamos obtendo os valores
para o titulo e preco do livro e exibindo nos controles de formulário.
Executando o projeto iremos obter:
 Enfim
uma aplicação simples mas que mostra como você pode realizar a
manutenção dos dados acessando um banco de dados SQL Server.
Pegue o projeto completo aqui: AcessoSQLServer_CSharp.zip
Eu sei é apenas C# , mas eu gosto...
artigo publicado originalmente no iMasters, por José Carlos Macoratti
|
Está prevista, ainda para o
primeiro semestre deste ano, uma nova versão do Entity Framework
4, com o objetivo de tornar a ferramenta cada
vez melhor.
Enquanto a versão final não sai, vamos falar um pouco sobre uma das
suas últimas atualizações, a Entity Framework Feature Community
Technology Preview - CTP5, mais precisamente da funcionalidade
Code-First e POCO.
Obs: Para baixar a versão CTP5 aqui: http://tinyurl.com/5rg52tg
Nota: A
versão anterior, a CTP4, já permitia usar o recurso do
First-Code com um banco de dados existente mas exigia mais
intervenção do desenvolvedor com a CTP5 tudo ficou mais
simples.
O Entity Framework é uma ferramenta
OR/M que realiza o mapeamento objeto relacional gerando entidades
e mapeando-as para as tabelas do banco de dados.. Em sua primeira
versão, praticamente não havia o que é conhecido como Code-First(Código Primeiro), ou seja, a possibilidade de
gerar o modelo de negócios e suas entidades sem ter que primeiro
criar o banco de dados.
Para quem trabalha usando o
paradigma da orientação a objetos deveria ser natural iniciar o
desenvolvimento pelo modelo de entidades, onde as classes são
definidas para representar o domínio do negócio.
Posteriormente, e a partir destas classes, seria gerado o banco
de dados usado pela aplicação para realizar a persistência das
informações. Deveria ser assim, mas a primeira
versão do EF não permitia esse recurso.
Tentando contornar este problema
eram feitos certos malabarismos, mas ainda assim, havia
uma dependência muito forte do mapeamento gerado pelo EF4 através
do Entity Data Model, o que incomodava muita
gente. Até que a Microsoft liberou atualizações que permitem maior independência do Framework, através da
criação de classes POCO (Plain Old CLR Objects) que não herdam das classes base
geradas pelo EF.
Quando decidimos usar o Code-First
não precisamos começar nossa aplicação criando o banco de
dados ou definindo um esquema mas podemos iniciar escrevendo
classes .NET para definir o modelo de objetos do nosso domínio
sem ter que misturar a lógica de persistência de dados com as
classes.
O Entity Framework, por padrão, adota
algumas convenções (Conventions) que ele usa
para realizar algumas operações.
Mas o que são essas convenções?
Consultando o dicionário teremos a
seguinte definição: Acordo, pacto,
contrato: convenção verbal , aquilo que está geralmente
admitido ou tacitamente contratado.
Em nosso contexto, podemos dizer que
uma convenção é uma regra padrão pelo qual não teremos que
fazer algumas configurações de mapeamento para nossas
entidades, sendo que o EF4 vai , baseado nessas convenções,
realizar as tarefas de forma automática.
Na CTP5 , as convenções estão
definidas por uma hierarquia de subclasses que implementam um
contrato comum chamado IConvention. Uma simples
definição deste contrato pode ser visto no código abaixo:
C#
public interface IConvention { }
VB .NET
Public Interface IConvention End Interface
Debaixo de IConvention
temos elementos como AttributeConfigurationConvention,
IDbConvention e IEdmConvention que nos interessam mais,
uma vez que eles representam os contratos através dos quais
foram implementadas as diversas convenções.
Antes de entrarmos em detalhes sobre as Convenções, criaremos um exemplo no EF4, para mostrar como ele se comporta
usando as convenções padrão, para entendermos o seu
comportamento e assim alterá-lo se assim desejarmos.
CTP5
- Usando POCO com as convenções padrão
Se usarmos o EF para realizar o
mapeamento criando o Entity Data Model teremos
uma grande ajuda da ferramenta, mas em muitos casos isso ao invés
de ajudar acabará atrapalhando, pois o código verboso gerado pode
ser um problema para integrar com o nosso modelo ou mesmo
transmitir usando Web Services.
Vamos então mostrar como usar POCO
sem criar o Entity Data Model e também usar o Code-First
gerando o banco de dados e as tabelas a partir de nossas
entidades.
Mas o que são essas classes POCO?
POCO - Plain Old CLR Object - são classes simples de domínio que
possuem apenas get/sets e um construtor e que não dependem de nenhum
framework; as classes POCO não são obrigadas a herdar de nenhuma outra
classe ou implementar nenhuma interface.Portanto as classes POCO são
independente de frameworks.
Vamos iniciar criando o nosso modelo
de negócio através da definição das classes do nosso
domínio. Para tornar a tarefa mais suave e de fácil
entendimento adotaremos um modelo simplificado que pode ser visto
no diagram de classes a seguir:

A cardinalidade é um
conceito importante para ajudar a definir o relacionamento, ela
define o número de ocorrências em um relacionamento. Para
determinar a cardinalidade, deve-se fazer a pergunta relativa ao
relacionamento em ambas as direções. No exemplo a seguir, temos
- Um
Curso possui quantos alunos? R: no mínimo 1 e no
máximo N;
- Um
aluno está alocado em quantos cursos? R- no mínimo em 1
e no máximo em 1;
Para implementar o nosso exemplo, usaremos o Visual
Basic 2010 Express Edition e
criando um novo projeto chamado EF4_Poco_Escola
via menu File->New Project escolhendo o
template Windows Forms Application;
Obs: Você
vai precisar ter instalado o SQL Server 2005 ou 2008 Express
Edition.
No menu Project
clique em Add Reference. Selecione a guia Browse e localize a
dll EntityFramework na pasta onde foi instalada
a CTP5 (c:Arquivos Programas)

Os recursos da EF Code First
CTP5 tem um nome de assembly atualizado e novo
namespace .NET:
- Nome do Assembly: EntityFramework.dll
- Namespace:
System.Data.Entity
No formulário form1.vb vamos
definir uma interface bem simples apenas para exibir as mensagens
durante a execução do código. Inclua um controle ListBox (lstResultado)
e um botão de comando (btnExecutar) conforme o layout
da figura abaixo:

Definindo
as classes de negócio
Vamos definir as classes Curso e
Aluno no projeto da seguinte forma:
1 - No menu Project selecione Add
Class e informe o nome Modelo.vb e
clique no botão Add.

A seguir defina as classes Curso
e Aluno no arquivo Modelo.vb conforme o
código abaixo:
Public Class Curso
Private m_CursoId As Integer Public Property CursoId() As Integer Get Return m_CursoId End Get Set(ByVal value As Integer) m_CursoId = valu End Set End Property
Private m_nome As String Public Property Nome() As String Get Return m_nome End Get Set(ByVal value As String) m_nome = value End Set End Property
Private m_escolaid As Integer Public Property EscolaId() As Integer Get Return m_escolaid End Get Set(ByVal value As Integer) m_escolaid = value End Set End Property
Public Property Alunos() As ICollection(Of Aluno) Get Return m_Alunos End Get Set(ByVal value As ICollection(Of Aluno)) m_Alunos = value End Set End Property Private m_Alunos As ICollection(Of Aluno) End Class
Public Class Aluno
Private m_AlunoId As Integer Public Property AlunoId() As Integer Get Return m_AlunoId End Get Set(ByVal value As Integer) m_AlunoId = value End Set End Property
Private m_nome As String Public Property Nome() As String Get Return m_nome End Get Set(ByVal value As String) m_nome = value End Set End Property
Private m_Email As String Public Property Email() As String Get Return m_Email End Get Set(ByVal value As String) m_Email = value End Set End Property
Public Property Curso() As Curso Get Return m_curso End Get Set(ByVal value As Curso) m_curso = value End Set End Property Private m_curso As Curso
End Class
2 - No menu Project
selecione Add Class e informe o nome AcessoDados.vb
e clique no botão Add.
Vamos definir a classe AcessoDados
que herda de DbContext e utilizar:
Imports System.Data.Entity
Public Class AcessoDados
Public Class ContextoCurso Inherits DbContext
Private m_Cursos As DbSet(Of Curso) Public Property Cursos() As DbSet(Of Curso) Get Return m_Cursos End Get Set(ByVal value As DbSet(Of Curso)) m_Cursos = value End Set End Property
Private m_Alunos As DbSet(Of Aluno) Public Property Alunos() As DbSet(Of Aluno) Get Return m_Alunos End Get Set(ByVal value As DbSet(Of Aluno)) m_Alunos = value End Set End Property End Class
End Class
Um dos aprimoramentos digno
de nota é que o CTP5 é uma versão simples das duas
classes:
- ObjectContext permite consultar,
controle de alterações e salvar no banco de dados.
- ObjectSet encapsula os conjuntos de
objetos semelhantes.
O
DbContext é um invólucro para ObjectContext
e além disso esta classe contém:
- Um conjunto de APIs que
são mais fáceis de usar do que a exposta pelo ObjectContext;
- As APIs que permitem utilizar o recurso do Code-First e
as convenções;
O DbSet é
um invólucro para ObjectSet.
Definindo o código para executar a
criação das tabelas do banco de dados e a persistência dos
dados. Vamos agora definir o código no
formulário form1.vb no evento Click
do botão de comando vamos chamar a rotina geraTabelasBD:
Private Sub btnExecutar_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnExecutar.Click geraTabelasBD() End Sub
O código da rotina geraTabelasBD
é visto a seguir:
Private Sub geraTabelaBD()
lstResultado.Items.Clear() lstResultado.Items.Add("Gerando as tabelas e o banco de dados") Using contextoCurso As New ContextoCurso()
Dim curso As New Curso() With { .Nome = "Entity Framework", .EscolaId = 100 }
lstResultado.Items.Add("") lstResultado.Items.Add("Entidade Curso criada com sucesso: nome='Entity Framework', Escolaid=100")
contextoCurso.Cursos.Add(curso)
lstResultado.Items.Add("") lstResultado.Items.Add("O curso foi incluído na coleção Cursos")
Dim macoratti As New Aluno() With { .Nome = "Jose Carlos Macoratti", .Curso = curso, .Email = "macoratti@yahoo.com" }
lstResultado.Items.Add("") lstResultado.Items.Add("Entidade Aluno criada com sucesso: nome='Jose Carlos Macoratti'")
contextoCurso.Alunos.Add(macoratti)
lstResultado.Items.Add("O aluno foi incluído na coleção Alunos")
Dim registros As Integer = contextoCurso.SaveChanges()
lstResultado.Items.Add("As entidades foram persistidas") lstResultado.Items.Add("") lstResultado.Items.Add("Registros afetados :" + registros.ToString())
End Using End Sub
Executando o projeto e clicando no
botão iremos obter o seguinte resultado:

Feito isso, vamos verificar como o
Entity Framework se comportou e quais as operações que ele
realizou. Agora vamos dar uma olhada no SQL Server
instalado na máquina local através do SQL Server
Management Studio.
Na figura abaixo vemos que o banco
de dados EF4_Poco_Escola.AcessoDados+ContextoCurso
foi criado. Foram criadas também as tabelas Alunos
e Cursos e também foram persistidas os dados conforme
mostra a figura a seguir:
Obs: O
nome das tabelas geradas foram Alunoes e Cursoes. O EF4 aplicou
uma convenção baseada na gramática inglesa que cria a tabela
com o nome da classe no plural.(*)

O conteúdo as
tabelas Cursos e Alunos exibindo os dados incluídos:

Partindo das nossas classes POCO,
o EF4 - CTP5 realizou todo o trabalho de criação do
banco de dados e das tabelas e também da persistência das
informações.
Resumindo o que o EF4 fez:
- Se conectou a
uma instãncia do SQL Server na máquina local (.SQLEXPRESS)
usando a autenticação do Windows;
- Verificou a
existência do banco de dados com o nome qualificado da
classe que herda de DbContext;
- Descobriu as
propriedades das classes Aluno e Curso;
- Inferiu a
existência do relacionamento um-para-muitos entre
a classe Curso e a classe Aluno;
- Criou as
tabelas Alunos e Cursos com os tipos e
os relacionamentos pertinentes;
- Inclui os dados
em cada uma das tabelas executando o comando SaveChanges();
Caramba! Como ele sabe fazer tudo
isso sozinho?
Elementar meu caro, ele usa as
convenções pré-definidas.
E quais seriam então essas
convenções?
Segue um resumo :
- Se você não definir um
endereço para o servidor , o EF4 CTP5 irá tentar
realizar uma conexão local;
- O nome da tabela criada será o
nome da classe no plural (usando a sintaxe da
gramática da língua Inglesa.No exemplo: Alunoes
e Cursoes);
- Se não for definido um nome
para o banco de dados , ele será criado com o nome do
projeto mais o nome da classe do contexto;
- Se uma classe tem uma
propriedade de navegação para outra classe e esta
possuir uma coleção da primeira, o EF infere que existe
um relacionamento do tipo um-para-muitos entre as
classes;
- Se existe uma propriedade com
nome igual ao nome da classe mas termina em Id ('nomeClasse'+Id)
ou se o nome da propriedade é apenas Id esta propriedade
será a chave primária;
- Se a chave primária é do tipo
inteiro ele é do tipo Identity;
Você pode alterar as convenções
padrão definindo suas próprias convenções e assim ter um
maior controle sobre as tarefas realizadas mas isso é um assunto
para outro artigo.
Pegue o projeto completo em: EF4_Poco_Escola.zip (versão VB .NET) e EF4_Poco_Conventions.zip (Versão C#)
Eu sei é apenas EF, mas eu
gosto...
artigo publicado originalmente no iMasters, por José Carlos Macoratti
|
Um aviso aos leitores deste artigo: boa parte do
conteúdo é uma tradução do artigo “Thread Synchronization (C# and
Visual Basic)” disponibilizado pela Microsoft. Aproveite a leitura!
Um dos benefícios do uso de múltiplas threads em uma aplicação é que cada
uma delas é
executada de forma assíncrona. Em aplicações desktop, isto
permite que tarefas
que consomem muito tempo possam ser executada em segundo plano enquanto a janela do aplicativo e os
controles continuam
respondendo.
Para aplicações em servidores, múltiplas
tarefas fornecem a capacidade de lidar com
cada solicitação de entrada com uma thread diferente, caso contrário, cada novo pedido não será
atendido até que o pedido anterior
tenha completado.
No entanto, a natureza assíncrona de threads significa que o acesso a recursos compartilhados, como arquivos, conexões de rede e memória devem ser sincronizados. Caso contrário, duas ou mais threads podem acessar o mesmo recurso ao mesmo tempo, e cada um desconhece a atuação da outra ação. O
resultado é a corrupção de dados imprevisível e possíveis deadlocks.
Há algum tempo, fiz outros artigos que demonstram o uso de
threads em C# e Visual Basic. Você pode encontrá-los aqui:
Lock e SyncLock
O Lock (C#) e o SyncLock (VB.NET) são
declarações que podem ser utilizadas para garantir que um bloco de código seja
executado até sua conclusão, prevenindo a interrupção da execução por outras
threads.
Essas declarações são interpretadas pelo compilador como bloqueios
para um determinado objeto em um bloco de códigos. Se outra thread tenta
executar o código envolvido pelo lock/SyncLock, ela evai esperar até que a
primeira thread termine a execução e libere o objeto/código bloqueado.
public class LockTest { public void TestarLock() { lock (this) { } } }
Sincronização de eventos e Wait Handles
Existem dois tipos de sincronização: AutoResetEvent e
ManualResetEvent. Eles diferem apenas na medida em que as mudanças são setadas
automaticamento no AutoResetEvent e manualmente no ManualResetEvent. O
ManualResetEvent permite que qualquer número de threads possa ser alinhado e
ter seu estado atualizado.
Métodos são usados para esperar a execução de um ou mais
threads. Esses métodos indicam ao compilador quando e quantas threads devem ter
o processamento concluído para que o fluxo continue. São eles: WaitOne, WaitAny
e WaitAll.
WaitOne faz com que o compilador espere a execução de um único
thread estar concluída. WaitAny faz o compilador aguardar a execução dos
métodos indicados. WaitAll bloqueia a execução até que todas as threads estejam
concluídas. Para sinalizar a conclusão da execução de uma thread, usa-se o
método Set.
namespace GerenciaSincronizacao { public class GerenciarThreads { private ManualResetEvent[] manualResetEvent;
private void ExecutarThread0(object obj) { Thread.Sleep(20000); Console.WriteLine("Thread 0 concluída!"); manualResetEvent[0].Set(); }
private void ExecutarThread1(object obj) { Thread.Sleep(13000); Console.WriteLine("Thread 1 concluída!"); manualResetEvent[1].Set(); }
private void ExecutarThread2(object obj) { Thread.Sleep(9000); Console.WriteLine("Thread 2 concluída!"); manualResetEvent[2].Set(); }
private void ExecutarThread3(object obj) { Thread.Sleep(17000); Console.WriteLine("Thread 3 concluída!"); manualResetEvent[3].Set(); }
public void Executar() { manualResetEvent = new ManualResetEvent[4];
manualResetEvent[0] = new ManualResetEvent(false); ThreadPool.QueueUserWorkItem(this.ExecutarThread0);
manualResetEvent[1] = new ManualResetEvent(false); ThreadPool.QueueUserWorkItem(this.ExecutarThread1);
manualResetEvent[2] = new ManualResetEvent(false); ThreadPool.QueueUserWorkItem(this.ExecutarThread2);
manualResetEvent[3] = new ManualResetEvent(false); ThreadPool.QueueUserWorkItem(this.ExecutarThread3);
WaitHandle.WaitAll(manualResetEvent); } }
class Program { static void Main(string[] args) { GerenciarThreads gt = new GerenciarThreads(); gt.Executar();
Console.WriteLine("Pressione ENTER para terminar."); Console.ReadKey(); } } }
A classe
Interlocked
Você pode usar os métodos da classe Interlocked para evitar
problemas que podem ocorrer quando várias threads tentam simultaneamente
atualizar ou comparar um mesmo valor. Os métodos dessa classe permitem que você
assegure o incremento, decremento, troca e comparação entre valores em qualquer
thread.
As operações mais utilizadas desta classe são:
- O método Add adiciona um valor inteiro para
uma variável e retorna o novo valor da variável.
- O método Read lê um valor inteiro de 64 bits.
- Os métodos Increment e Decrement são
utilizados para incrementar ou decrementar valores em uma variável e retornam o
valor resultante.
O
código a seguir demonstra o uso do Increment:
private static ManualResetEvent[] manualResetEvents;
public void Teste() { int intQuantidadeInteracoes = 10; int intContador = 0;
manualResetEvents = new ManualResetEvent[intQuantidadeInteracoes];
for (int i = 0; i < intQuantidadeInteracoes; i++) { manualResetEvents[intContador] = new ManualResetEvent(false);
ThreadPool.QueueUserWorkItem(this.Executar, intContador);
Interlocked.Increment(ref intContador); }
WaitHandle.WaitAll(manualResetEvents); }
public void Executar(object intContador) { Console.WriteLine("Posição atual do contador: {0}", Convert.ToInt32(intContador));
manualResetEvents[Convert.ToInt32(intContador)].Set(); }
Referências
artigo publicado originalmente no iMasters, por Fernando Ottoboni
|
O desenvolvimento de software não é algo trivial, como costuma dizer meu amigo Vinicius Quaiato.
Se o software for algo "pequeno" (entende-se por pequeno aplicações de
pequeno porte), é possível que um ou outro desenvolvedor entenda que,
como não foram utilizados alguns padrões, o desenvolvimento daquela
aplicação é simples.
Entretanto, construir bons softwares (e bons programadores sabem
disso) requer uma série de características do desenvolvedores. E, a principal delas é o cuidado com a arquitetura.
Se você é o tipo de desenvolvedor que não se preocupa com a escrita de testes unitários, design pattern,
inversão de controle, etc., aqui vai um conselho: ou começa a se
preocupar com isso, ou seus sistemas tornar-se-ão legados
prematuramente.
É bem verdade que seja possível escrever aplicações
com a ausência de tais conceitos, entretanto, a reflexão que o
desenvolvedor deve realizar aqui é "este software, está bem escrito? A
manutenibilidade, é boa? É extensível? É testável?"
Se suas respostas às perguntas acima forem: não, não, não e não, será
preciso repensar a maneira como você escreve suas aplicações.
No artigo de hoje, veremos um destes conceitos fundamentais para a
escrita de aplicações bem elaboradas: o conceito de injeção de
dependência. E nesta primeira parte, implementaremos a DI (Dependency Injection) de forma manual, e logo depois utilizaremos uma ferramenta para sua implementação.
O que é injeção de dependência?
Trata-se de um design pattern que consiste na
passagem de uma classe para outra, sendo que esta última irá utilizá-la
(consumí-la), visando eliminar o forte acoplamento geralmente existente
entre os módulos da aplicação. Para que essa ideia fique um pouco mais
clara, considere a situação proposta logo abaixo:

A figura acima apresenta uma situação hipotética, onde um módulo para o gerenciamento de downloads existe. Para este exemplo, estamos propondo três camadas (classes com naturezas diferentes):
- clsDown (uma camada de nível mais alto),
- clsDownBusiness (camada onde são implementadas as regras de negócios da aplicação),
- clsDownData (camada mais baixa de acesso a dados).
Note que para que uma instância da classe clsDown exista, é fundamental que a classe clsDownBusiness também exista. E para que esta última exista, clsDownData
também precisa existir. Portanto, a dependência entre as camadas está
apresentada. Mas a pergunta aqui é "qual o problema desta
abordagem?"
A problemática implícita (motivação para implementação da ID)
A
característica de "dependência" mencionada acima, onde uma classe
concreta (de objetos reais) depende diretamente de outra é uma relação
desinteressante do ponto de vista da arquitetura do software. Isso se
deve há alguns motivos, dentro os quais podemos destacar os dois mais
importantes:
- Testabilidade:
escrever testes unitários para aplicações é uma prática extremamente
recomendável, e, para que esta possa ser realizada com sucesso, as
classes e métodos necessitam ser definidas de forma isolada. Testar
classes com dependencia(s) direta(s) de outra(s) é uma prática
praticamente impossível de ser realizada com sucesso.
- Extensibilidade:
a correta aplicação da injeção de dependência resulta em módulos
"plugáveis", extensíveis. Isto é, módulos podem ser utilizados por
outras aplicações sem que estas sintam o impacto da "herança".
Injeção de dependência: alguns conceitos fundamentais
Basicamente, a injeção de dependência pode ser implementada de três formas:
- Construtor:
as dependências do objeto são injetadas diretamente em seu construtor.
Vale salientar que, esta abordagem deve ser adotada quando se pretende
injetar todas as dependências externas.
- Propriedade: dependências do objeto são injetadas via setter em alguma(s) propriedade(s).
- Interface:
o objeto a ser injetado oferece fornece uma abstração de seus serviços
(na forma interface ou mesmo classe abstrata), sendo que a injeção é
realizada via instância da abstração.
Não existe uma regra geral que defina qual a melhor abordagem dentre
as três mencionadas. Como quase tudo em computação dependerá da situação
problema, a injeção de dependência via construtor é mais
comumente encontrada nas aplicações.
Obs.: Vinicius Quaiato escreveu um bom
artigo em seu blog sobre a definição da melhor abordagem. E você pode
efetuar a leitura deste artigo aqui.
Existem diversos frameworks para implementação de injeção de
depencia em uma aplicação .NET, sendo que o mais famoso deles é o
Unity. Por ora, implementaremos a injeção de dependência de
forma manual, depois implementaremos ID utilizando o Unity. Dessa forma
você poderá mensurar qual a melhor abordagem e qual se adequa
mais a seu contexto.
Implementando injeção de dependência
Para que possamos entender de fato este conceito, utilizaremos a
situação problema proposta pela figura citada logo acima. Temos um objeto "clsDown" que,
para que possa existir, depende do objeto "clsDownBusiness" que, por
dua vez depende do objeto "clsDownData".
Temos objeto "clsDown"
que pode ser entendido neste caso como uma camada de visualização. Para
que os dados sejam exibidos corretamente, a lógica foi implementada no
objeto "clsDownBusiness". E para que a lógica possa funcionar corretamente, o objeto "clsDownData" cuida do acesso a dados.
Assim, considere o trecho de código apresentado Listagem 1:
namespace InjecaoDependencia_1.Controllers { public class clsDownController : Controller { public ActionResult NovoDownload(Download objDown) { var objDownBusiness = new clsDownBusiness(); objDownBusiness.SalvarDownloadBD(objDown); return View(); } } }
public class clsDownBusiness { public void SalvarDownloadBD(Download objDown) { var objDownData = new clsDownData(); objDownData.ConexaoBanco();
} }
public class clsDownData { public void ConexaoBanco() { } }
public class Download { }
Em uma
rápida observação do código apresentado pela listagem acima é possível
ver as relações de dependência entre os objetos.
Note que a action "NovoDownload" precisa utilizar do objeto "objDownBusiness", que é do tipo "clsDownBusiness" e, esta última, precisa da informação de conexão com o banco de dados, que é provida pelo objeto "objDownData", que é do tipo "clsDownData".
Para que
possamos implementar o mecanismo de injeção de dependência, vamos
criar abstrações (interfaces) onde as dependências existem. No
caso, a abstração ocorre para o objeto que será "injetado". Assim, a
dependência entre "clsDown" e "clsDownBusiness" será realizada através de uma interface, chamada por nós de "IDownBusiness". Assim, temos nossa arquitetura um pouco modificada.
A Listagem 2 apresenta o código sugestivo para "IDownBusiness", a Listagem 3 apresenta o código sugestivo para "IDownData" e a Listagem 4 apresenta a estrutura da aplicação modificada.
public interface IDownBusiness { public void SalvarDownloadBD(Download objDown); }
Listagem 2: Código sugestivo para "IDownBusiness"
public interface IDownData { public bool ConexaoBanco(); }
Listagem 3: Código sugestivo para "IDownData"
public class clsDownController : Controller { private IDownBusiness iObjDownBusiness;
public clsDownController(IDownBusiness _iObjDownBusiness) { this.iObjDownBusiness = _iObjDownBusiness; }
public ActionResult NovoDownload(Download objDown) { iObjDownBusiness.SalvarDownloadBD(objDown); return View(); } }
public class clsDownBusiness : IDownBusiness { private IDownData iObjDownData;
public clsDownBusiness(IDownData _iObjDownData) { this.iObjDownData = _iObjDownData; }
public void SalvarDownloadBD(Download objDown) { iObjDownData.ConexaoBanco();
//Salva no BD } }
public class clsDownData : IDownData { public void ConexaoBanco() { //Conecta no banco de dados } }
Listagem 4: "Injetando dependência" em nossos objetos de forma indireta "IDownData"
Nas Listagens 2, 3 e 4 tivemos a inserção de todos os conceitos importantes neste artigo:
- Listagem 2: criamos uma abstração (interface) do objeto a ser injetado em "clsDown" e, dentro dela, assinamos o método "SalvarDownloadBD".
- Listagem 3: criamos uma abstração (interface) do objeto a ser injetado em "clsDownBusiness" e dentro dela assinamos o método "ConexaoBanco".
- Listagem 4:
em função da implementação das abstrações, temos agora que "injetar" a
dependência destas nas classes que as consomem. O primeiro aspecto a ser
notado é: as classes "clsDownBusiness" e "clsDownData" implementam as interfaces "IDownBusiness" e "IDownData" respectivamente. Isso pode ser observado nas linhas 17 e 34. Outra observação importante é que: a classe "clsDown" espera um objeto qualquer que implemente a interface "IDownBusiness", por inércia, temos a dependência direta com classe "clsDownBusiness" quebrada. O mesmo se repete em relação as classes "clsDownBusiness" e "clsDownData". Estas situações podem ser observadas nas linhas 3, 5, 6, 7, 19, 21, 22 e 23.
Nossa injeção de dependência foi realizada. Um próximo passo poderia ser a utilização de Abstract Factory,
por exemplo, para centralizar todas as dependências. Como o foco deste
texto consiste apenas na apresentação dos conceitos de injeção de
dependência, ficamos por aqui.
Até a próxima! E não esqueça de deixar seu feedback através dos comentários. artigo publicado originalmente no iMasters, por Fabrício Lopes Sanchez
|
Já publiquei outros artigos
sobre o Windows Presentation Foundation - WPF, e uma grande parte sobre
os recursos do DataBinding. Neste artigo, veremos como criar um menu em
tempo de execução em uma aplicação WPF. Você pode criar aplicações WPF usando as seguintes ferramentas:
Pela sua simplicidade o projeto poderá ser aberto em qualquer uma das
versões citadas. A linguagem escolhida poderia ser C# ou VB .NET, pois o
código também é bem simples, mas usaremos o SharpDevelop justamente
para mostrar que podemos usar o recurso de converter o código para C# ou
VB .NET.
Agora abra o SharpDevelop 4.0 e no menu File selecione New -> Solution:

Na janela New Project , observe as opções oferecidas. Vamos
selecionar a linguagem C# e o item WPF e em Templates selecionar WPF
Application. Em seguida, vamos informar o nome WPF_Menu_c e clicar no
botão Create.

Será criada a solução, e em uma das suas visões, selecionando a aba
Projects veremos a estrutura da solução. Selecionando a guia Source,
veremos a janela Window1.xam.

Agora clique sobre o arquivo Window1.xaml.cs para ver o código:

Vamos incluir a rotina criarMenu(), depois definir o seu código para criar um menu Arquivo com duas opções: Abrir e Sair.
private void criarMenu() { Menu mainMenu = new Menu(); contentGrid.Children.Add(mainMenu); mainMenu.HorizontalAlignment = System.Windows.HorizontalAlignment.Stretch; mainMenu.VerticalAlignment = System.Windows.VerticalAlignment.Top;
MenuItem fileMenuItem = new MenuItem(); fileMenuItem.Header = "_Arquivo"; mainMenu.Items.Add(fileMenuItem);
MenuItem openMenuItem = new MenuItem(); fileMenuItem.Items.Add(openMenuItem); openMenuItem.Header = "_Abrir"; openMenuItem.Click += openMenuItem_Click; ToolTip openToolTip = new ToolTip(); openMenuItem.ToolTip = openToolTip; openToolTip.Content ="Abrir um novo Arquivo";
MenuItem exitMenuItem = new MenuItem(); fileMenuItem.Items.Add(exitMenuItem); exitMenuItem.Header = "S_air"; exitMenuItem.Click += exitMenuItem_Click; ToolTip exitToolTip = new ToolTip(); exitMenuItem.ToolTip = exitToolTip; exitToolTip.Content = "Encerrar"; } private void openMenuItem_Click(object sender, RoutedEventArgs e) { MessageBox.Show("Abrir um novo arquivo"); } private void exitMenuItem_Click(object sender, RoutedEventArgs e) { MessageBox.Show("Até logo!"); this.Close(); }

Agora é só alegria! Executando o projeto iremos obter:

Simples né?
Agora vamos converter o código do projeto que foi
feito na linguagem C# para a linguagem VB .NET. Selecione o arquivo
Window1.xaml.cs e no menu Project selecione Convert -> From C# to VB
.NET.

Será criado um novo projeto na solução, já convertido para a linguagem VB .NET conforme figura abaixo:

Simples assim!
O projeto completo disponível aqui: WPF_Menu_c.zip
No próximo artigo veremos como criar menus em tempo de projeto! Eu sei, é apenas WPF, mas eu gosto! artigo publicado originalmente no iMasters, por José Carlos Macoratti
|
Olá, pessoal!
Neste artigo, veremos como criar novas sections customizadas. Até o
momento, a solução foi testada no Visual Studio .NET 2010 e 2005 e
funcionou perfeitamente. Acredito que funcione nas outras versões sem
qualquer problema.
Usado para desenvolvimento:
- Visual Studio .NET 2010
- Linguagem C#.NET
- Web.config
O primeiro passo foi gerar a o website ou o projeto do tipo web.
Dependendo da forma que gerar, será necessário inserir alguns dados a
mais no web.config da aplicação. Com base neste artigo, você pode criar
várias outras formas de desenvolvimento e customização de
sectionConfigurations.
O segundo passo foi gerar uma classe .cs para configuração do arquivo. Criei a classe CustomConfiguration.cs.
Importes necessários:
using System; using System.Data; using System.Configuration; using System.Web; using System.Web.Security; using System.Web.UI; using System.Web.UI.WebControls; using System.Web.UI.WebControls.WebParts; using System.Web.UI.HtmlControls;
É necessário estender a classe ConfigurationSection.
public class CustomConfiguration : ConfigurationSection {}
O passo seguinte foi gerar duas propriedades dentro do arquivo de configuração. Os dois artigos são do tipo Int32.
[ConfigurationProperty("firstNumber", DefaultValue=1, IsRequired=true)] [IntegerValidator(MinValue=-100, MaxValue=100)] public Int32 FirstNumber { get { return (Int32)this["firstNumber"]; } set { this["firstNumber"] = value; } }
[ConfigurationProperty("secondNumber", DefaultValue=1, IsRequired=true)] [IntegerValidator(MinValue=-100, MaxValue=100)] public Int32 SecondNumber { get { return (Int32)this["secondNumber"]; } set { this["secondNumber"] = value; } }
Gerei o construtor recebendo dois parâmetros de entrada. Um construtor vazio e outro recebendo parâmetro.
public CustomConfiguration() { }
public CustomConfiguration (Int32 firstValue, Int32 secondValue) { FirstNumber = firstValue; SecondNumber = secondValue; }
O próximo passo é gerar dentro do arquivo web.config as configurações
customizadas. Dentro da tag <configuration> existe
<configSections> responsável para configuração da sectionGroup.
<sectionGroup name="customSection"> <section name="settings" type="CustomConfiguration" allowLocation="true" allowDefinition="Everywhere" /> </sectionGroup>
Note que o tipo (type) é o mesmo nome da classe de configuração. O
nome (name) settings é o nome que escolhi para gerar a segunda tag
customizada. Se a sua aplicação estiver usando namespace, basta colocar
no tipo todo o namespace até a classe.
<sectionGroup name="customSection"> <section name="settings" type="MinhaAplicacao.Classe.Util,CustomConfiguration" allowLocation="true" allowDefinition="Everywhere" /> </sectionGroup>
Depois de fechar a tag </configSections>, é necessário inserir a outra customizada com os valores e as duas propriedades.
<customSection> <settings firstNumber="20"secondNumber="43" /> </customSection>
Note que a sessão customizada possui os mesmos nomes colocados na
primeira tag. O nome customSection foi gerado na segunda tag XML e assim
por diante. As duas propriedades firstNumber e secondNumber possuem
valores do tipo inteiro na segunda tag XML adicionada.
<configSections> <sectionGroup name="customSection"> <section name="settings" type=" MinhaAplicacao.Classe.Util.CustomConfiguration, MinhaAplicacao" allowLocation="true" allowDefinition="Everywhere" /> </sectionGroup> </configSections>
Dessa maneira, a classe de leitura foi feita e o arquivo config
gerado, basta agora mostrar como é feita a leitura desses valores. Para
ler o arquivo, basta colocar o código abaixo:
CustomConfiguration config = (CustomConfiguration)System.Configuration.ConfigurationManager.GetSection("customSection/settings");
Essa linha de código pode ser colocada no seu Page_Load sem qualquer problema.
O GetSection("customSection/settings"); busca diretamente as tags com
esse nome. Fica simples, depois basta pegar as propriedades.
Colocando a instância e ponto aparece o nome da propriedade.
Int32 primeiro = config.FirstNumber Int32 segundo = config.SecondNumber
Somando os valores, veja o resultado:
Até a próxima! artigo publicado originalmente no iMasters, por Mauricio Junior
|
Vou começar este texto fazendo uma referência à minha introdução já feita no artigo Criando uma aplicação SilverLight 4 com DataBinding.
Tenho escrito pouco sobre a tecnologia SilverLight, primeiro devido à
falta de tempo e depois pelas constantes mudanças e evoluções que o
SilverLight tem passado. Você vai dormir usando a versão 3 e quando
acorda já tem a versão 4.
De qualquer forma, em 2011 pretendo dar um pouco mais de atenção ao
SilverLight e um bom começo é ter o ambiente corretamente ajustado para
poder usar a tecnologia.
Lembrando que o SilverLight foi lançado em meados de 2007 e desde
então tem evoluído muito. Enquanto o ASP .NET é uma plataforma para
desenvolvimento do lado do servidor, com a chegada do
SilverLight o foco muda para o lado do cliente, visto que uma aplicação
SilverLight roda no navegador do cliente em uma versão específica da
CLR (Common Language Runtime).
Se o SilverLight é algo totalmente novo mas você conhece o WPF, fique
sabendo que o SilverLight pode ser considerado como uma versão reduzida
do WPF, sendo possível inclusive reutilizar código escrito no
SilverLight 4 no WPF 4 e vice-versa.
Preparando o terreno
Para iniciar o desenvolvimento de aplicações SilverLight precisamos ter instalados as ferramentas e os SDKs necessários.
- Instalar o Visual Studio 2010 ou o Visual Web Developer Express 2010;
- Instalar o SilverLight 4 Tools for Visual Studio 2010;
- Instalar o Expression Blend 4;
Após baixar e instalar as ferramentas acima, não ocorrendo nenhum
erro, tudo estará pronto para você dar início a saga de desenvolver
aplicações para o SilverLight.
Invocando um serviço que expõe dados
Ao trabalhar em um projeto Silverlight que envolve serviços, o WCF
(Windows Comunication Foundation) é a escolha preferida para a
construção de um serviço se temos que criar este e o aplicativo cliente
do Silverlight que irá utilizá-lo. Dessa forma, usando o WCF temos um
controle completo sobre quais tipos serão enviados para o cliente.
Quando queremos construir uma aplicação Silverlight que trabalha com
os dados disponíveis sobre o serviço (talvez proveniente de um banco de
dados ou outro serviço externo), precisamos ter em mente as seguintes
questões:
- Como devemos projetar o serviço que expõe os dados de modo que possa ser acessível a partir do Silverlight?
- Como devemos proceder para projetar o aplicativo do Silverlight, para que ele se comunica com o serviço?
Para mostrar como podemos nos conectar a partir do Silverlight com um
serviço WCF que expõe os dados, vamos começar com a concepção do
próprio serviço.
Observação: O artigo foi baseado em alguns exemplos prontos que foram adaptados e ajustados.
Vamos supor que estamos construindo uma aplicação que contém uma
janela de visualização onde o usuário poderá obter informações sobre os
funcionários de uma empresa.
Os dados do funcionário serão expostos pelo serviço e o aplicativo
Silverlight irá se conectar ao serviço e trabalhar com os dados no lado
do cliente. A seguir estão os passos que precisa executar para começar
este trabalho.
Dica importante: para tornar mais simples o exemplo não vamos trabalhar com um banco de dados mas iremos preencher os dados via código.
Dando a partida: criando a aplicação SilverLight 4
Abra o Visual Web Developer 2010 Express Edition no menu File
selecione New Project. A seguir selecione Visual C# e o template
SilverLight > SilverLight Application, informe o nome
SilverLightFuncionarios e clique em OK.

Será apresentada a janela abaixo, onde vemos o projeto do tipo ASP
.NET Web Application Project selecionado como o tipo de projeto web que
será usado para hospedar a aplicação SilverLight. Note que a versão do
SilverLight escolhida é a versão 4.

Após fazer estas verificações clique em OK. Será criada uma solução com dois projetos:
- O projeto SilverLight: SilverLightFuncionarios;
- O projeto Web: SilverLightFuncionarios.web - responsável por hospedar o conteúdo SilverLight;

Vamos nos concentrar primeiro na aplicação web. Os dados que
desejamos expor consistem em informações sobre os funcionários. Vamos
então definir as classes que representam o domínio do nosso problema.
A seguir vemos o diagrama de classes que mostra as classes do nosso domínio:

O diagrama de classes acima mostra o relacionamento entre as classes e
a enumeração CarroTipo. Note que a classe Funcionario é uma classe
abstrata e que as demais classes herdam da classe Funcionario.
Dica Importante: Utilizando classes
abstratas você pode declarar classes que definam apenas parte de uma
implementação, deixando que as classes estendidas forneçam a
implementação específica de alguns ou de todos os métodos. Uma classe
abstrata em geral será destinada apenas a servir como base para a
criação de outras classes.
O próximo passo é criar as classes no projeto
SilverLightFuncionarios.web. Vamos começar criando a classe Funcionario.
Selecione o projeto SilverLightFuncionarios.web e no menu Project
clique em Add Class. A seguir informe o nome Funcionario.cs e clique no
botão Add.

Repita o procedimento acima e crie as seguintes classes:
- Gerente.cs
- Consultor.cs
- Administrativo.cs
- CarroTipo.cs
Após criar os arquivos para as classes vamos definir o código da classe Funcionario.cs conforme abaixo:
using System; using System.Runtime.Serialization;
namespace SilverlightFuncionarios.Web { [DataContract] [KnownType(typeof(Gerente))] [KnownType(typeof(Consultor))] [KnownType(typeof(Administrativo))] public abstract class Funcionario { [DataMember] public int funcionarioid { get; set; }
[DataMember] public string nome { get; set; }
[DataMember] public string email { get; set; }
[DataMember] public DateTime nascimento { get; set; } } }
Vamos entender a classe Funcionario:
- A classe é uma classe abstrata e isso indica que a classe não pode ser instanciada e deve ser herdada por outra classe.
- O atributo DataContract usado na classe indica que o tipo pode ser enviado via rede.
- DataContract especifica que o tipo define ou implementa um contrato
de dados e é serializável por um serializador, como o
DataContractSerializer. Para fazer o seu tipo serializável, os autores
do tipo devem definir um contrato de dados para o seu tipo.
- O atributo DataMember usado nos campos da classe será incluído no tipo e poderá ser enviado via rede para o lado do cliente.
- O DataMember quando aplicado ao membro de um tipo, especifica que o
membro faz parte de um contrato de dados e é serializável pelo
DataContractSerializer.
- O atributo KnowType marca os tipos a serem incluídos no processo de serialização.
- O atributo de classe KnownType permite que você especifique,
antecipadamente, os tipos que devem ser incluídos para apreciação
durante a desserialização.
Agora vamos definir o código da classe Gerente conforme o código a seguir:
using System.Runtime.Serialization;
namespace SilverlightFuncionarios.Web { public class Gerente : Funcionario { [DataMember] public double Gratificacao { get; set; }
[DataMember] public CarroTipo Carro { get; set; } } }
A classe Gerente herda da classe Funcionario e define os campos:
Observação: Para poder usar os atributos
DataContrat e DataMember, talvez você terá que incluir uma referência a
System.RunTime.Serialization no projeto web.
Abaixo temos a definição da classe Consultor:
using System.Runtime.Serialization;
namespace SilverlightFuncionarios.Web { public class Consultor : Funcionario { [DataMember] public CarroTipo Carro { get; set; } } }
A classe Consultor herda da classe Funcionario e define o campo:
Observação: Para poder usar os atributos
DataContrat e DataMember talvez você terá que incluir uma referência a
System.RunTime.Serialization no projeto web.
A seguir temos o código da classe Administrativo:
namespace SilverlightFuncionarios.Web { public class Administrativo : Funcionario { } }
A classe Administrativo herda da classe Funcionario. Finalmente o código da enumeração CarroTipo:
namespace SilverlightFuncionarios.Web { public enum CarroTipo { Esportivo, Passeio, Utilitario } }
Nosso próximo objetivo será criar uma classe chamada FuncionarioRepositorio
que será usada para carregar os dados de exemplo. Em uma aplicação real
geralmente carregaríamos os dados de um banco de dados. Para criar a
classe repita o procedimento usado para criar a classe Funcionario.
O código desta classe é definido como:
using System; using System.Collections.Generic;
namespace SilverlightFuncionarios.Web { public class FuncionarioRepositorio { private static List<Funcionario> todosFuncionarios;
public FuncionarioRepositorio() { carregaFuncionarios(); }
private void carregaFuncionarios() { if (todosFuncionarios == null) { todosFuncionarios = new List<Funcionario>() { new Gerente() { funcionarioid=1, nome="Macoratti", email="macoratti@yahoo.com", carro=CarroTipo.Esportivo, gratificacao=10000.00, nascimento=new DateTime(1960, 1, 1) }, new Consultor() { funcionarioid=2, nome="Mario", email="mario@bol.com.br", carro=CarroTipo.Passeio, nascimento=new DateTime(1976, 11, 9) }, new Consultor() { funcionarioid=3, nome="Janice", email="janice@uol.com.br", carro=CarroTipo.Utilitario, nascimento=new DateTime(1983, 3, 12) }, new Consultor() { funcionarioid=4, nome="Jefferson", email="jeff@net.com", carro=CarroTipo.Passeio, nascimento=new DateTime(1984, 6, 7) }, new Administrativo() { funcionarioid=5, nome="Miriam", email="miriam@uol.com.br", nascimento=new DateTime(1970, 9, 22) },
new Administrativo() { funcionarioid=6, nome="Jose", email="jose@bol.com.br", nascimento=new DateTime(1973, 2, 19) }, }; }
public List<Funcionario> TodosFuncionarios { get { return todosFuncionarios; } }
} }
A classe FuncionarioRepositorio usa uma lista estática de funcionários: private static List<Funcionario> todosFuncionarios.
Agora que definimos as classes do nosso domínio e a classe que irá
popular os objetos da nossa classe vamos incluir um serviço WCF no
projeto web. Selecione o projeto SilverLightFuncionarios.web e no menu
Project clique em Add New Item.
Na caixa de diálogo Add New Item veremos duas opções para adicionar um serviço WCF:
- SilverLight-enabled WCF Service;

Vamos selecionar o item SilverLight-enabled WCF Service e informe o
nome FuncionarioService e clique no botão Add. Será criado um arquivo
FuncionarioService.csv conforme a figura abaixo:

Vamos fazer alguns ajustes no arquivo FuncionarioService gerado para
habilitar os serviços WCF. O serviço deverá apresentar dois métodos:
- O primeiro deverá recuperar todos os funcionários;
- O outro deverá recuperar um funcionário pela identificação do funcionário;
Cada método deverá estar disponível no lado do cliente e deverá ter o
atributo OperacionContract que indica que o método define uma operação
que é parte de um contrato de serviço em uma aplicação.
Dessa forma o código implementado no serviço deverá chamar o método
TodosFuncionarios da classe FuncionarioRepositorio conforme abaixo:
using System.Linq; using System.ServiceModel; using System.ServiceModel.Activation; using System.Collections.Generic;
namespace SilverlightFuncionarios.Web { [ServiceContract(Namespace = "")] [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)] public class FuncionarioService { [OperationContract] public List<Funcionario> GetTodosFuncionarios() { return new FuncionarioRepositorio().TodosFuncionarios; }
[OperationContract] public Funcionario GetFuncionarioPorId(int funciid) { return new FuncionarioRepositorio().TodosFuncionarios.Where (e => e.funcionarioid == funciid).FirstOrDefault(); } } }
Com isso encerramos os ajustes do lado do cliente e podemos partir
para o lado do servidor. Antes de continuar compile a aplicação (Build).
Selecione o projeto SilverLight SilverLightFuncionarios e no menu
Project clique em Add Service Reference.
A seguir clique no botão Discover e selecione: Services in Solution.
Se o serviço estiver disponível ele deverá aparecer na caixa Services.

Se o serviço puder ser conectado sem erros, ele irá aparecer na lista
de serviços e em Operations serão exibidos os nomes dos métodos
criados. A seguir selecione o serviço e informe o nome
FuncionarioService e clique no botão OK.

Depois de clicar no botão OK, Visual Web Developer 2010 Express
tentará construir um proxy que é mais ou menos uma cópia do lado do
cliente da classe de serviço. Na janela Solution Explorer o serviço
poderá ser visto conforme mostra a figura a seguir:

Vamos agora cuidar da interface onde iremos usar o serviço criado.
Selecione o projeto SilverLightFuncionarios e no menu Project clique em
Add Reference e inclua referência a System.Windows.Controls.Data. Em
seguida clique com o botão direito do mouse sobre o projeto e selecione
Add > New Folder e informe o nome Converters para a pasta criada.
Depois vamos incluir dois arquivos que serão usados como conversores
de data para o campo Nascimento e moeda para o campo Gratificação:
Observação: Não vou entrar em detalhes sobre os conversores, irei apenas usá-los no projeto. Se você quiser saber mais sobre eles consulte este link.
Selecione o arquivo MainPage.xaml e a partir da ToolBox inclua os seguintes controles conforme o leiaute da figura abaixo;
- TextBlock
- TextBox
- Button
- DataGrid
A seguir temos a exibição do código XAML correspondente:

<UserControl xmlns:data="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data"
x:Class="SilverlightFuncionarios.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
xmlns:local="clr-namespace:SilverlightFuncionarios.Converters" Loaded="UserControl_Loaded"
d:DesignHeight="450" d:DesignWidth="550" DataContext="{Binding}">
<UserControl.Resources>
<local:ShortDateConverter x:Key="localShortDateConverter"></local:ShortDateConverter>
<local:CurrencyConverter x:Key="localCurrencyConverter"></local:CurrencyConverter>
</UserControl.Resources>
<Grid x:Name="LayoutRoot" Background="White" Height="450" Width="550">
<Grid.RowDefinitions>
<RowDefinition Height="60"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBlock x:Name="TitleTextBlock" Grid.Row="0" Grid.ColumnSpan="2" Text="Macoratti.net - SilverLight" FontSize="24" FontWeight="Bold" HorizontalAlignment="Center"></TextBlock>
<StackPanel Grid.Row="1" Background="Bisque" >
<Grid Margin="3" HorizontalAlignment="Center" >
<Grid.RowDefinitions>
<RowDefinition Height="50"></RowDefinition>
<RowDefinition Height="300"></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="3*"></ColumnDefinition>
<ColumnDefinition Width="2*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<StackPanel Grid.Row="0" Orientation="Horizontal" Grid.ColumnSpan="2">
<TextBlock x:Name="FunciIDTextBlock" VerticalAlignment="Center" Margin="2">Cod. Funci.::</TextBlock>
<TextBox x:Name="FunciIDTextBox" HorizontalAlignment="Left" Width="200" VerticalAlignment="Center" Margin="2"></TextBox>
<Button x:Name="ProcuraFunciButton" Click="ProcuraFunciButton_Click" Margin="2" Content="Procurar Funci" Width="120" Height="30" HorizontalAlignment="Center"></Button>
<TextBlock x:Name="ErrorTextBlock" Foreground="Red"></TextBlock>
</StackPanel>
<data:DataGrid x:Name="FunciDataGrid" Grid.Row="1" SelectionChanged="FunciDataGrid_SelectionChanged" CanUserReorderColumns="False"
IsReadOnly="True" AutoGenerateColumns="False" Width="316" Margin="0,0,3,0">
<data:DataGrid.Columns>
<data:DataGridTextColumn Binding="{Binding funcionarioid}" Header="Cod.Funci"></data:DataGridTextColumn>
<data:DataGridTextColumn Binding="{Binding nome}" Header="Nome"></data:DataGridTextColumn>
<data:DataGridTextColumn Binding="{Binding email}" Header="Email"></data:DataGridTextColumn>
</data:DataGrid.Columns>
</data:DataGrid>
<Grid x:Name="DetailGrid" Grid.Row="1" Grid.Column="1" Width="219" Margin="3,3,-10,3">
<Grid.RowDefinitions>
<RowDefinition Height="20"></RowDefinition>
<RowDefinition Height="20"></RowDefinition>
<RowDefinition Height="20"></RowDefinition>
<RowDefinition Height="20"></RowDefinition>
<RowDefinition Height="20"></RowDefinition>
<RowDefinition Height="20"></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100"></ColumnDefinition>
<ColumnDefinition Width="100"></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBlock x:Name="FunciIdTextBlock" Grid.Row="0" Grid.Column="0" Text="Cod. Funci:" FontWeight="Bold"></TextBlock>
<TextBlock x:Name="FunciIdValueTextBlock" Grid.Row="0" Grid.Column="1" Text="{Binding funcionarioid}"></TextBlock>
<TextBlock x:Name="NomeTextBlock" Grid.Row="1" Grid.Column="0" Text="Nome:" FontWeight="Bold"></TextBlock>
<TextBlock x:Name="NomeTextBlockValue" Grid.Row="1" Grid.Column="1" Text="{Binding nome}" ></TextBlock>
<TextBlock x:Name="EmailTextBlock" Grid.Row="2" Grid.Column="0" Text="Email:" FontWeight="Bold"></TextBlock>
<TextBlock x:Name="EmailTextBlockValue" Grid.Row="2" Grid.Column="1" Text="{Binding email}" ></TextBlock>
<TextBlock x:Name="NascimentoTextBlock" Grid.Row="3" Grid.Column="0" Text="Nascimento:" FontWeight="Bold"></TextBlock>
<TextBlock x:Name="NascimentoTextBlockValue" Grid.Row="3" Grid.Column="1" Text="{Binding nascimento, Converter={StaticResource localShortDateConverter}}" ></TextBlock>
<TextBlock x:Name="GratificacaoTextBlock" Grid.Row="4" Grid.Column="0" Text="Gratificação:" FontWeight="Bold"></TextBlock>
<TextBlock x:Name="GratificacaoTextBlockValue" Grid.Row="4" Grid.Column="1" Text="{Binding gratificacao, Converter={StaticResource localCurrencyConverter}}" ></TextBlock>
<TextBlock x:Name="CarroTextBlock" Grid.Row="5" Grid.Column="0" Text="Carro:" FontWeight="Bold"></TextBlock>
<TextBlock x:Name="CarroTextBlockValue" Grid.Row="5" Grid.Column="1" Text="{Binding carro}" ></TextBlock>
</Grid>
</Grid>
</StackPanel>
</Grid>
</UserControl>
Na interface teremos as informações dos funcionários exibidas no
controle DataGrid e os seus detalhes nos controles TextBlock conforme o
funcionário selecionado. Observe o uso dos conversores localShortDateConverter e localCurencyConverter para os campos nascimento e gratificação.
Observe que estamos utilizando os recursos do DataBinding, vinculando
cada controle ao nome do membro e definido na classe de domínio. A
classe Binding está no namespace System.Windows.Data e é
responsável por manter a comunicação entre a origem e o destino, expondo
uma série de propriedades que nos permite customizar o comportamento
dessa comunicação.
Entre as principais propriedades, temos:
- ElementName: define o nome do elemento que
servirá como fonte. Utilize esta propriedade quando desejar preencher
uma outra propriedade com o valor de um controle do WPF.
- Mode: determina a direção das informações.
- NotifyOnSourceUpdated: valor boleano indicando se o evento SourceUpdated é disparado quando alguma atualização na fonte das informações ocorrer.
- NotifyOnTargetUpdated: valor boleano indicando se o evento SourceUpdated é disparado quando alguma atualização no destino das informações ocorrer.
- Path: espefica o nome da propriedade que será exibida.
- RelativeSource: especifica uma fonte de forma relativa à posição do objeto atual.
- Source: define o nome do objeto que servirá como
fonte. Utilize esta propriedade quando desejar preencher com uma
instância de um objeto.
- XPath: a mesma finalidade da propriedade Path, mas define uma expressão XPath quando a fonte de informações for um arquivo Xml.
Dessa forma temos a interface pronto para ser usada, receber e exibir as informações de funcionários.
Acompanhe a segunda parte do artigo onde vamos implementar o código no arquivo MainPage.xaml.cs referente ao evento Click do botão Procurar Funci, que irá chamar a rotina carrega TodosFuncionarios - responsável por usar o serviço criado para obter as informações dos funcionários.
Eu sei é apenas SilverLight 4,
mas eu gosto...
artigo publicado originalmente no iMasters, por José Carlos Macoratti
|
O alerta em javascript com Link Button é uma funcionalidade muito
usada no dia a dia dos programadores de softwares e aplicativos. Ela
pode ser usada tanto para websites como para mobile web.
Foi usado:
- Visual Studio.NET 2010
- Framework: 4.0
- Tipo do projeto: ASP.NET
- Linguagem: C#.NET
- Linguagem de interpretação: JavaScript
No primeiro
passo, foi criado o projeto do tipo ASP.NET. O Visual Studio .NET 2010 monta
todo layout, com style, javascript e tudo mais. Isso melhora bastante no
processo de desenvolvimento.

O
aplicativo monta toda a estrutura web de desenvolvimento:

O segundo
passo é colocar via código o LinkButton
do asp.net:
<asp:LinkButton ID="lnkTeste" runat="server" Text="Teste"></asp:LinkButton>
Foi dado o nome de lnkTeste. O quarto passo é clicar na aba
Designer e clicar duas vezes em cima
do LinkButton. É criado
automaticamente o método dentro do código C#:
protected void lnkTeste_Click(object sender, EventArgs e)
{
}
O quinto
passo foi acrescentar um label na
página para mostrar o resultado depois do clique. Foi dado o nome de lblResultado.
<asp:Label ID="lblResultado" runat="server"></asp:Label>
Dentro do
código C#.NET e do método criado anteriormente (código 2), foi digitado uma linha
de código como passo quinto:
protected void lnkTeste_Click(object sender, EventArgs e)
{
lblResultado.Text = "Clicou OK";
}
A parte em
C# está pronta. Agora é necessário criar a parte em javascript.
Dentro
da mesma página, foi criado uma função em javascript responsável por mostrar a
pergunta no momento do clique:
<script type="text/javascript">
function pergunta() {
if (confirm("Deseja confirmar essa operação?")) {
return true;
} else {
return false;
}
}
</script>
Note que, no código acima, a
função usa o simples confirm do
javascript e retorna true ou false. Se o true for retornado, a página faz o submit, se o false for retornado
a página não faz nada, ou seja, mantém o mesmo estado. Para vincular a função
javascript com o linkButton, é necessário
adicionar mais um parâmetro na linha do linkButton.
<asp:LinkButton ID="lnkTeste" runat="server" Text="Teste"
OnClientClick="javascript:return pergunta();" onclick="lnkTeste_Click"></asp:LinkButton>
Foi acrescentada a seguinte
linha: OnClientClick=”javascript:return
pergunta();”. Isso faz com que a função seja executada antes de passar pelo
código C#.NET, retornado true o
método continua seus passos.
Segue a
tela mostrando o resultado final:

Ao clicar
no botão OK, aparece a seguinte imagem:

Para melhor
entendimento, segue todo o código da página .aspx:
<%@ Page Title="Home Page" Language="C#" MasterPageFile="~/Site.master" AutoEventWireup="true"
CodeBehind="Default.aspx.cs" Inherits="ArtigoLinkButton._Default" %>
<asp:Content ID="HeaderContent" runat="server" ContentPlaceHolderID="HeadContent">
</asp:Content>
<asp:Content ID="BodyContent" runat="server" ContentPlaceHolderID="MainContent">
<script type="text/javascript">
function pergunta() {
if (confirm("Deseja confirmar essa operação?")) {
return true;
} else {
return false;
}
}
</script>
<h2>
Welcome to ASP.NET!
</h2>
<p>
To learn more about ASP.NET visit <a href="http://www.asp.net" title="ASP.NET Website">www.asp.net</a>.
<br /><br />
<asp:LinkButton ID="lnkTeste" runat="server" Text="Teste"
OnClientClick="javascript:return pergunta();" onclick="lnkTeste_Click"></asp:LinkButton>
<asp:Label ID="lblResultado" runat="server"></asp:Label>
</p>
<p>
You can also find <a href="http://go.microsoft.com/fwlink/?LinkID=152368&clcid=0x409"
title="MSDN ASP.NET Docs">documentation on ASP.NET at MSDN</a>.
</p>
</asp:Content>
Segue todo
o código da página C#.NET:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace ArtigoLinkButton
{
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
protected void lnkTeste_Click(object sender, EventArgs e)
{
lblResultado.Text = "Clicou OK";
}
}
Bom, eu
fico por aqui e qualquer dúvida pode entrar em contato pelo site artigo publicado originalmente no iMasters, por Mauricio Junior
|
Existem situações em que é necessário retornar informações quando a
execução da thread estiver concluída para que elas sejam usadas na
continuação do processamento da thread principal da aplicação. O intuito
deste artigo é mostrar uma maneira de receber e tratar retornos de
threads.
tags: c#, thread
Como mostrei no artigo
anterior, todo programa desenvolvido em C# possui uma thread principal e
podemos desenvolver outras threads para serem executadas em segundo plano. Podemos
também chamar Threads passando parâmetros para elas. Além da passagem de dados
para a Thread, existem situações em que é necessário retornar informações quando
a execução da thread estiver concluída.
Para recuperar dados da thread, devemos
criar um método que aceita os resultados de retorno como parâmetro. Em seguida,
devemos criar um delegate
para esse método. O construtor da classe deve aceitar um delegate que
representa o método call-back. Antes que a thread esteja concluída, ela chama o
delegate de retorno.
O código a seguir é uma calculadora simples, na qual a
operação é executada através de uma thread em segundo plano, e o resultado é
retornado para a thread principal, para ser mostrado para o usuário. No
interior deste código estão os comentários explicando cada bloco.
class Program { static void Main(string[] args) { Console.WriteLine(); Console.Write("Informe o primeiro valor: "); double d1 = Convert.ToDouble(Console.ReadLine());
Console.WriteLine(); Console.Write("Informe o segundo valor: "); double d2 = Convert.ToDouble(Console.ReadLine());
Console.WriteLine(); Console.WriteLine("OPERAÇÕES"); Console.WriteLine("1 - Soma"); Console.WriteLine("2 - Subtração"); Console.WriteLine("3 - Multiplicação"); Console.WriteLine("4 - Divisão"); Console.Write("Informe a operação desejada: "); Operacao op = (Operacao)Convert.ToInt32(Console.ReadLine());
Calculadora calc = new Calculadora(d1, d2, op, new ResultDelegate(ResultCallback));
System.Threading.ThreadStart ts = new System.Threading.ThreadStart(calc.Calcular); System.Threading.Thread t = new System.Threading.Thread(ts);
t.Start();
Console.WriteLine(); Console.WriteLine("Thread principal em execução."); t.Join(); Console.WriteLine(); Console.WriteLine("Processamento concluído."); Console.ReadKey(); }
public static void ResultCallback(double valor) { Console.WriteLine("Valor Retornado da Calculadora: {0}", valor); } }
public class Calculadora { private double valor1; private double valor2; private Operacao operacao;
private ResultDelegate callback;
public Calculadora(double _valor1, double _valor2, Operacao _operacao, ResultDelegate _callback) { this.valor1 = _valor1; this.valor2 = _valor2; this.operacao = _operacao; callback = _callback; }
public void Calcular() { double valorResultado;
if (this.operacao == Operacao.Soma) valorResultado = this.valor1 + this.valor2; else if (this.operacao == Operacao.Subtracao) valorResultado = this.valor1 - this.valor2; else if (this.operacao == Operacao.Multiplicacao) valorResultado = this.valor1 * this.valor2; else if (this.operacao == Operacao.Divisao) valorResultado = this.valor1 / this.valor2; else valorResultado = 0;
if (callback != null) callback(valorResultado); } }
public delegate void ResultDelegate(double valor);
public enum Operacao { Soma = 1, Subtracao = 2, Multiplicacao = 3, Divisao = 4 }
O resultado dessa execução deverá ser algo como mostra a imagem abaixo:

Nota: Fique sempre atento para a ocorrência de deadlocks.
Sempre que necessário, utilize locks nos locais onde a concorrência pode ser
grande e causar deadlocks. Isso é assunto para um outro artigo, mas, por enquanto,
se quiser saber mais sobre isso, veja este link.
Código fonte
Os códigos fontes podem ser baixados aqui.
Referências
artigo publicado originalmente no iMasters, por Fernando Ottoboni
|