Finalmente, vamos agora para a implementação do pattern Repository usando o Entity Framework. Na Parte 2 nós criamos a interface IRepository e também o ContextManager, um helper para a criação do contexto. A implementação será chamada EFRepository e definirá, através de generics, dois tipos, sendo que um será o tipo do objeto que será persistido e o outro será o tipo (classe) do contexto do Entity Framework. Vamos para o código!

   1: using System;
   2: using System.Collections.Generic;
   3: using System.Data;
   4: using System.Data.Metadata.Edm;
   5: using System.Data.Objects;
   6: using System.Data.Objects.DataClasses;
   7: using System.Linq;
   8: using System.Linq.Expressions;
   9: using Net.Bragil.Data.Context;
  10:  
  11: namespace Net.Bragil.Data.Repository
  12: {
  13:     /// <summary>
  14:     /// Repositório genérico para o Entity Framework com as operações mais comuns de persistência, como inserção, atualização,
  15:     /// exclusão e seleção.
  16:     /// </summary>
  17:     /// <typeparam name="E">Tipo do objeto a ser persistido</typeparam>
  18:     /// <typeparam name="C">Tipo do contexto</typeparam>
  19:     public class EFRepository<E, C> : IRepository<E, C>, IDisposable
  20:         where E : EntityObject
  21:         where C : ObjectContext
  22:     {
  23:         /// <summary>
  24:         /// Contexto do Entity Framework
  25:         /// </summary>
  26:         private C context;
  27:  
  28:         /// <summary>
  29:         /// Contexto do Entity Framework
  30:         /// </summary>
  31:         public C Context
  32:         {
  33:             get { return context; }
  34:             set { context = value; }
  35:         }
  36:  
  37:         /// <summary>
  38:         /// Retorna o nome do EntitySet do objeto persistente
  39:         /// </summary>
  40:         private string entitySetName;
  41:  
  42:         /// <summary>
  43:         /// Retorna o nome do EntitySet do objeto persistente
  44:         /// </summary>
  45:         protected string EntitySetName
  46:         {
  47:             get
  48:             {
  49:                 if (String.IsNullOrEmpty(entitySetName))
  50:                 {
  51:                     entitySetName = GetEntitySetName(typeof(E).Name);
  52:                 }
  53:                 return entitySetName;
  54:             }
  55:         }
  56:  
  57:         /// <summary>
  58:         /// Construtor padrão, sem argumentos. Obtém o contexto do Entity Framework usando o ContextManager.
  59:         /// </summary>
  60:         public EFRepository()
  61:         {
  62:             // Obtém o contexto
  63:             this.context = ContextManager.GetContext<C>();
  64:         }
  65:  
  66:         /// <summary>
  67:         /// Insere um novo objeto persistente
  68:         /// </summary>
  69:         /// <param name="entity">Objeto a ser inserido</param>
  70:         public void Insert(E entity)
  71:         {
  72:             context.AddObject(EntitySetName, entity);
  73:         }
  74:  
  75:         /// <summary>
  76:         /// Atualiza um objeto existente.
  77:         /// </summary>
  78:         /// <param name="entity">Objeto persistente</param>
  79:         public virtual void Update(E entity)
  80:         {
  81:             EntityKey key;
  82:             object originalItem;
  83:             if (entity.EntityKey == null)
  84:                 // Obtém o entity key do objeto que será atualizado
  85:                 key = Context.CreateEntityKey(EntitySetName, entity);
  86:             else
  87:                 key = entity.EntityKey;
  88:             try
  89:             {
  90:                 // Obtém o objeto original
  91:                 if (Context.TryGetObjectByKey(key, out originalItem))
  92:                 {
  93:                     if (originalItem is EntityObject &&
  94:                         ((EntityObject)originalItem).EntityState != EntityState.Added)
  95:                     {
  96:                         // Autaliza o objeto
  97:                         context.ApplyPropertyChanges(key.EntitySetName, entity);
  98:                     }
  99:                 }
 100:             }
 101:             catch (Exception ex)
 102:             {
 103:                 throw ex;
 104:             }
 105:  
 106:         }
 107:  
 108:         /// <summary>
 109:         /// Exclui um objeto persistente
 110:         /// </summary>
 111:         /// <param name="entity">Objeto persistente que será excluído</param>
 112:         public void Delete(E entity)
 113:         {
 114:             context.DeleteObject(entity);
 115:         }
 116:  
 117:         /// <summary>
 118:         /// Retorna um objeto que satisfaça a cláusula passada como parâmetro.
 119:         /// </summary>
 120:         /// <param name="expression">Expressão Lambda da cláusula WHERE</param>
 121:         public E SelectOne(Expression<Func<E, bool>> where)
 122:         {
 123:             return context.CreateQuery<E>(EntitySetName).Where(where).FirstOrDefault();
 124:         }
 125:  
 126:         /// <summary>
 127:         /// Salva as alterações no banco de dados.
 128:         /// </summary>
 129:         public void SaveChanges()
 130:         {
 131:             context.SaveChanges();
 132:         }
 133:  
 134:         /// <summary>
 135:         /// Retorna todos os objetos persistentes.
 136:         /// </summary>
 137:         /// <returns>Coleção com todos os objetos</returns>
 138:         public List<E> SelectAll()
 139:         {
 140:             return context.CreateQuery<E>(EntitySetName).ToList();
 141:         }
 142:  
 143:         /// <summary>
 144:         /// Retorna um IQueryable com todos os objetos
 145:         /// </summary>
 146:         /// <returns>IQueryable com todos os objetos</returns>
 147:         public IQueryable<E> QueryAll()
 148:         {
 149:             return context.CreateQuery<E>(EntitySetName).AsQueryable<E>();
 150:         }
 151:  
 152:         /// <summary>
 153:         /// Retorna todos os objetos usando paginação.
 154:         /// </summary>
 155:         /// <param name="maximumRows">Quantidade de objetos por página</param>
 156:         /// <param name="startRowIndex">Linha a partir do qual os objetos serão retornados</param>
 157:         /// <returns>Coleção com todos os objetos</returns>
 158:         public List<E> SelectAll(int maximumRows, int startRowIndex)
 159:         {
 160:             return context.CreateQuery<E>(EntitySetName).Skip<E>(startRowIndex).Take(maximumRows).ToList();
 161:         }
 162:  
 163:         /// <summary>
 164:         /// Retorna um IQueryable com todos os objetos usando paginação
 165:         /// </summary>
 166:         /// <param name="maximumRows">Quantidade de objetos por página</param>
 167:         /// <param name="startRowIndex">Linha a partir do qual os objetos serão retornados</param>
 168:         /// <returns>IQueryable com todos os objetos</returns>
 169:         public IQueryable<E> QueryAll(int maximumRows, int startRowIndex)
 170:         {
 171:             return context.CreateQuery<E>(EntitySetName).Skip<E>(startRowIndex).Take(maximumRows);
 172:         }
 173:  
 174:         /// <summary>
 175:         /// Retorna todos os objetos que satisfaçam a cláusula passada
 176:         /// </summary>
 177:         /// <param name="where">Expressão Lambda da cláusula WHERE</param>
 178:         public List<E> SelectWhere(Expression<Func<E, bool>> where)
 179:         {
 180:             return context.CreateQuery<E>(EntitySetName).Where(where).ToList();
 181:         }
 182:  
 183:         /// <summary>
 184:         /// Retorna todos os objetos que satisfaçam a cláusula passada, usando paginação
 185:         /// </summary>
 186:         /// <param name="where">Expressão Lambda da cláusula WHERE</param>
 187:         /// <param name="maximumRows">Quantidade de objetos por página</param>
 188:         /// <param name="startRowIndex">Linha a partir do qual os objetos serão retornados</param>
 189:         public List<E> SelectWhere(Expression<Func<E, bool>> where, int maximumRows, int startRowIndex)
 190:         {
 191:             return context.CreateQuery<E>(EntitySetName).Where(where)
 192:                           .Skip<E>(startRowIndex).Take(maximumRows).ToList();
 193:         }
 194:  
 195:         /// <summary>
 196:         /// Retorna o número de objetos
 197:         /// </summary>
 198:         /// <remarks>Para ser usado na configuração da paginação</remarks>
 199:         public int GetCount()
 200:         {
 201:             return context.CreateQuery<E>(EntitySetName).Count();
 202:         }
 203:  
 204:         /// <summary>
 205:         /// Retorna o número de objetos que satisfaçam a cláusula passada
 206:         /// </summary>
 207:         /// <remarks>Para ser usado na configuração da paginação</remarks>
 208:         public int GetCount(Expression<Func<E, bool>> where)
 209:         {
 210:             return context.CreateQuery<E>(EntitySetName).Where(where).Count();
 211:         }
 212:  
 213:         /// <summary>
 214:         /// Libera os recursos do Entity Framework.
 215:         /// </summary>
 216:         public void Dispose()
 217:         {
 218:             if (context != null)
 219:                 context.Dispose();
 220:         }
 221:  
 222:         /// <summary>
 223:         /// Retorna o nome do EntitySet, possibilitando a criação de métodos genéricos.
 224:         /// </summary>
 225:         /// <param name="entityTypeName">String com o nome do tipo</param>
 226:         /// <returns>String contendo o EntitySet</returns>
 227:         private string GetEntitySetName(string entityTypeName)
 228:         {
 229:             var container = context.MetadataWorkspace.GetEntityContainer(context.DefaultContainerName, DataSpace.CSpace);
 230:             string entitySetName = (from meta in container.BaseEntitySets
 231:                                     where meta.ElementType.Name == entityTypeName
 232:                                     select meta.Name).FirstOrDefault();
 233:             return entitySetName;
 234:         }
 235:  
 236:     }
 237:  
 238:  
 239: }

Na primeira parte deste artigo, criamos o banco de dados e geramos o contexto do Entity Framework para o modelo. Agora, vamos começar a definir o componente para o pattern Repository. Segue uma lista dos requisitos para o componente:

Deverá oferecer a possibilidade de trabalhar independente dos tipos envolvidos

Ou seja, poderemos usar o mesmo componente para persistir qualquer objeto, independente do contexto usado. Isso é facilmente conseguido através do uso de Generic Types, sendo possível parametrizar os tipos que serão trabalhados durante as operações de persistência.

Deverá simplificar o desenvolvimento para as rotinas básicas de persistência

O objetivo será tornar o desenvolvimento o mais simples possível, procurando encapsular todo o “trabalho sujo” e criar uma interface limpa e amigável para o programador.

Baseado nas especificações acima, segue a Interface do componente Repository para o Entity Framework:

   1: using System;
   2: using System.Collections.Generic;
   3: using System.Linq;
   4: using System.Linq.Expressions;
   5:  
   6: namespace Net.Bragil.Data.Repository
   7: {
   8:     /// <summary>
   9:     /// Interface para a implementação do padrão Repository usando o Entity Framework.
  10:     /// </summary>
  11:     /// <typeparam name="E">Tipo do objeto persistente</typeparam>
  12:     /// <typeparam name="C">Tipo do contexto do Entity Framework</typeparam>
  13:     public interface IRepository<E, C>
  14:     {
  15:         /// <summary>
  16:         /// Contexto do Entity Framework
  17:         /// </summary>
  18:         C Context { get; set; }
  19:  
  20:         /// <summary>
  21:         /// Inserção
  22:         /// </summary>
  23:         void Insert(E entity);
  24:  
  25:         /// <summary>
  26:         /// Atualização
  27:         /// </summary>
  28:         void Update(E entity);
  29:  
  30:         /// <summary>
  31:         /// Exclusão
  32:         /// </summary>
  33:         void Delete(E entity);
  34:  
  35:         /// <summary>
  36:         /// Retorna o objeto que satisfaça a cláusula passada como argumento (cláusula WHERE)
  37:         /// </summary>
  38:         E SelectOne(Expression<Func<E, bool>> where);
  39:  
  40:         /// <summary>
  41:         /// Retorna todos os objetos de um tipo
  42:         /// </summary>
  43:         List<E> SelectAll();
  44:  
  45:         /// <summary>
  46:         /// Retorna os objetos usando paginação
  47:         /// </summary>
  48:         List<E> SelectAll(int maximumRows, int startRowIndex);
  49:  
  50:         /// <summary>
  51:         /// Retorna todos os objetos que satisfaçam a cláusula passada
  52:         /// </summary>
  53:         /// <param name="where">Cláusula WHERE</param>
  54:         List<E> SelectWhere(Expression<Func<E, bool>> where);
  55:  
  56:         /// <summary>
  57:         /// Retorna os objetos que satisfaçam a cláusula passada, usando paginação
  58:         /// </summary>
  59:         /// <param name="where">Cláusula WHERE</param>
  60:         List<E> SelectWhere(Expression<Func<E, bool>> where, int maximumRows, int startRowIndex);
  61:  
  62:         /// <summary>
  63:         /// Retorna um objeto IQueryable, possibilitando formar queries usando expressões Lambda
  64:         /// </summary>
  65:         IQueryable<E> QueryAll();
  66:  
  67:         /// <summary>
  68:         /// Retorna um IQueryable com os objetos usando paginação
  69:         /// </summary>
  70:         IQueryable<E> QueryAll(int maximumRows, int startRowIndex);
  71:  
  72:         /// <summary>
  73:         /// Retorna a quantidade de objetos persistentes.
  74:         /// </summary>
  75:         int GetCount();
  76:  
  77:         /// <summary>
  78:         /// Retorna a quantidade de objetos persistentes que satisfaçam a cláusula WHERE
  79:         /// </summary>
  80:         int GetCount(Expression<Func<E, bool>> where);
  81:     }
  82: }

Como você pode ver, o componente oferecerá a maioria dos recursos de persistência, de uma forma muito mais amigável do que usando o Entity Framework diretamente.

Foi necessário também a criação de uma classe auxiliar para instanciação do contexto do Entity Framework usando a estratégia “One-Per-Request”, ou seja, é criada apenas uma instância do contexto por requisição. O objeto do contexto é armazenado em HttpContext.Current.Items, de modo que as chamadas subsequentes dentro da mesma requisição retornam o contexto anteriormente instanciado e armazenado na requisição. Segue o código:

   1: using System.Web;
   2: using System.Data.Objects;
   3:  
   4: namespace Net.Bragil.Data.Context
   5: {
   6:     /// <summary>
   7:     /// Classe gerenciadora do contexto do Entity Framework. Utiliza generics para determinar em tempo de execução o 
   8:     /// tipo do contexto e Reflection para instanciar o tipo genérico. Armazena o contexto no HttpContext, de modo que 
   9:     /// não seja necessário instanciar o contexto nas próximas chamadas dentro da requisição web.
  10:     /// </summary>
  11:     public sealed class ContextManager
  12:     {
  13:         /// <summary>
  14:         /// Construtor privado, não será possível instanciar a classe usando new
  15:         /// </summary>
  16:         private ContextManager()
  17:         {
  18:         }
  19:  
  20:         /// <summary>
  21:         /// Obtém o contexto do Entity Framework usando generics.
  22:         /// </summary>
  23:         /// <typeparam name="T">Tipo do contexto do Entity Framework (deve herdar de ObjectContext)</typeparam>
  24:         /// <returns>Contexto do Entity Framework</returns>
  25:         public static T GetContext<T>()
  26:             where T: ObjectContext
  27:         {
  28:             string ocKey = "ocm_" + HttpContext.Current.GetHashCode().ToString("x");
  29:             if (HttpContext.Current != null)
  30:             {
  31:                 if (!HttpContext.Current.Items.Contains(ocKey))
  32:                 {
  33:                     // Instancia o contexto através de Reflection
  34:                     T ctx = typeof(T).GetConstructor(System.Type.EmptyTypes).Invoke(System.Type.EmptyTypes) as T;
  35:                     // Armazena na requisição
  36:                     HttpContext.Current.Items.Add(ocKey, ctx);
  37:                 }
  38:                 return HttpContext.Current.Items[ocKey] as T;
  39:             }
  40:             else
  41:                 // Caso a aplicação não seja web, instancia e retorna o contexto.
  42:                 return typeof(T).GetConstructor(System.Type.EmptyTypes).Invoke(System.Type.EmptyTypes) as T;
  43:             
  44:         }
  45:  
  46:     }
  47: }

Já estamos quase lá! No próximo artigo vamos desenvolver a implementação da classe EFRepository.


Este é o primeiro de uma série de artigos abordando a criação de um Repository para o Entity Framework. Para quem não sabe, o Repository é um Design Pattern que abstrai as complexidades da camada de acesso a dados, oferendo uma interface de mais alto nível que possibilita um menor acoplamento com a tecnologia de persistência. Para um melhor entendimento, vamos apresentar de forma prática a criação da camada de persistência para um modelo simples de banco de dados, a geração do contexto do Entity Framework, o desenvolvimento do Repository e finalmente um pequeno exemplo mostrando os recursos do componente criado.

Os requisitos para o desenvolvimento proposto são os seguintes:

  • Visual Studio 2008 SP1
  • .Net Framework 3.5
  • Banco de dados SQL Server Express Edition

Obs: é importante salientar que há outros bancos de dados cujos drivers possuem suporte ao Entity Framework. Verifique se o banco de dados que você usa possui driver para .Net com suporte ao Entity Framework.

Vamos trabalhar com um modelo de dados bem simples, mas suficiente para o nosso exemplo, conforme segue:

 

db

Basicamente, um cadastro simples de pessoas com endereço completo. Depois de definido o modelo de dados, vamos realizar a geração do contexto do Entity Framework (edmx). Se você não sabe como fazer isso, leia este artigo.

edmx

Pronto, já temos o banco de dados e o contexto do Entity Framework. O tipo do objeto de contexto do Entity Framework foi nomeado como DbEntities.

entities

No próximo artigo vamos abordar o desenvolvimento do componente Repository.


Trabalhar com paginação de dados no PostgreSQL é muito fácil. As cláusulas usadas para paginação são LIMIT e OFFSET. A fórmula básica seria o seguinte:

   1: SELECT * FROM tabela 
   2:     LIMIT <número de itens por página> 
   3:     OFFSET(<página> - 1) * <número de itens por página>

Agora, os exemplos… Para trazer os 20 registros da página 2:

   1: SELECT * FROM tabela 
   2:     LIMIT 20
   3:     OFFSET (2 - 1) * 20
Muito fácil! :)

Posted in: PostgreSQL  Tags: ,
Admin posted on September 15, 2009 08:59

Uma dica rápida, mas que pode poupar um bom tempinho. Usar ORDER BY em queries que usam a cláusula UNION é bem mais simples do que parece. Suponhamos que temos duas tabelas, tb_cidades e tb_paises, e queremos trazer em uma única query o id e o nome tanto de tb_cidades quanto de tb_paises. Para isso combinamos duas queries SELECT usando a cláusula UNION:

SELECT c.cidade_id, c.nome FROM tb_cidades c
UNION
SELECT p.pais_id, p.nome FROM tb_paises p

Teremos assim, em uma única query, tanto cidades quanto países. Mas, e a ordenação?? É aí que muita gente se atrapalha, mas a solução é bem simples:

1) Atribua um alias em comum para as colunas que serão ordenadas. Se for a coluna de ID, coloque o mesmo alias tanto para cidades quanto para países.

2) Utilize este alias no ORDER BY.

Então vamos alterar a query acima para ordenar pela coluna nome de tb_cidades e tb_paises:

SELECT c.cidade_id, c.nome AS coluna_nome FROM tb_cidades c
UNION
SELECT p.pais_id, p.nome AS coluna_nome FROM tb_paises p
ORDER BY coluna_nome

Simples assim. Wink


Posted in: PostgreSQL  Tags: , ,
Admin posted on August 19, 2009 05:11

Os arquivos de configuração .INI há um bom tempo foram substituídos no .Net pelos arquivos XML, muito mais flexíveis e padronizados. Entretanto, quando trabalhamos com sistemas legados, seja para fazer integrações, migrações ou o que quer que seja, acabamos nos deparando com os saudosos arquivos .INI. Ao invés de criar rotinas caseiras para trabalhar com estes arquivos, que tal uma biblioteca em C# que cumpra esse papel com louvor? A biblioteca Nini faz isto e muito mais: além dos arquivos .INI, ela abstrai o acesso a arquivos de configuração XML, .Net Config, Registry e argumentos de linha de comando. O site do projeto não possui nada, apenas os links para poder baixar, mas a documentação vem junto com o arquivo baixado.

Segue um exemplo do próprio manual da Nini:

; MyApp.ini
[Logging]
File Name = MyApp.log
MessageColumns = 5
MaxFileSize = 40000000000000

   1: // Usando C#
   2: using Nini.Config;
   3: IConfigSource source = new IniConfigSource("MyApp.ini");
   4:  
   5: string fileName = source.Configs["Logging"].Get("File Name");
   6: int columns = source.Configs["Logging"].GetInt("MessageColumns");
   7: long fileSize = source.Configs["Logging"].GetLong("MaxFileSize");
   1: 'E usando VB.Net
   2: Imports Nini.Config
   3:  
   4: Dim source As New IniConfigSource("MyApp.ini")
   5:  
   6: Dim fileName As String = source.Configs("Logging").Get("File Name")
   7: Dim columns As Integer = source.Configs("Logging").GetInt("MessageColumns")
   8: Dim fileSize As Long = source.Configs("Logging").GetLong("MaxFileSize")

Posted in: .Net , C#  Tags: , , ,

Neste post vou apresentar um aplicativo para Windows Mobile 6 que recebe como entrada o valor do litro do álcool, da gasolina e exibe uma mensagem dizendo qual dos dois é mais vantajoso abastecer, bastante útil quando o seu veículo é flex. Faça o download do código fonte do projeto: AlcoolGasolina.zip (56,97 kb). Caso você queira apenas o .cab do aplicativo para instalar em seu smartphone, ele está na pasta AlcoolGasolinaSetup/Release.

Requisitos:

O código é bem simples, o valor do litro do álcool é dividido pelo valor do litro da gasolina, se o resultado for maior ou igual a 0,7 compensa abastecer com gasolina, caso contrário, abasteça com álcool.

   1:  using System;
   2:  using System.Text;
   3:  using System.Windows.Forms;
   4:   
   5:  namespace AlcoolGasolina
   6:  {
   7:      public partial class frmPrincipal : Form
   8:      {
   9:          public frmPrincipal()
  10:          {
  11:              InitializeComponent();
  12:          }
  13:   
  14:          /// <summary>
  15:          /// Método de validação da entrada. Considera inválidos strings vazias e 
  16:          /// valores menores ou iguais a zero.
  17:          /// </summary>
  18:          /// <param name="valor">O valor de entrada, formato string</param>
  19:          /// <returns>True para válido, False para inválido.</returns>
  20:          private bool isValid(string valor)
  21:          {
  22:              // Não deve ser uma string vazia ou nula
  23:              if (String.IsNullOrEmpty(valor))
  24:                  return false;
  25:              try
  26:              {
  27:                  // deve ser um valor numérico válido
  28:                  double num = Convert.ToDouble(valor);
  29:   
  30:                  // não deve ser menor ou igual a zero
  31:                  if (num > 0)
  32:                      return true;
  33:                  else
  34:                      return false;
  35:              }
  36:              catch (Exception)
  37:              {
  38:                  return false;
  39:              }
  40:          }
  41:   
  42:          /// <summary>
  43:          /// Verifica se os valores digitados são válidos e, em caso positivo, 
  44:          /// faz o cálculo e apresenta a mensagem para o usuário informando
  45:          /// qual é mais viável abastecer, álcool ou gasolina. Se os valores 
  46:          /// não forem válidos para o cálculo, será exibida uma mensagem de 
  47:          /// alerta, informando que os valores de entrada são inválidos.
  48:          /// </summary>
  49:          /// <param name="sender"></param>
  50:          /// <param name="e"></param>
  51:          private void btnCalcular_Click(object sender, EventArgs e)
  52:          {
  53:              if (isValid(txtAlcool.Text.Trim()) && isValid(txtGasolina.Text.Trim()))
  54:              {
  55:                  double alcool = Convert.ToDouble(txtAlcool.Text.Trim());
  56:                  double gasolina = Convert.ToDouble(txtGasolina.Text.Trim());
  57:   
  58:                  double resultado = alcool / gasolina;
  59:                  if (resultado >= 0.7)
  60:                      lblResultado.Text = "Abasteça com Gasolina";
  61:                  else
  62:                      lblResultado.Text = "Abasteça com Álcool";
  63:              }
  64:              else
  65:              {
  66:                  MessageBox.Show("Valores de entrada inválidos.", 
  67:                                  "Erro", 
  68:                                  MessageBoxButtons.OK, 
  69:                                  MessageBoxIcon.Exclamation, 
  70:                                  MessageBoxDefaultButton.Button1);
  71:              }
  72:              txtAlcool.Text = string.Empty;
  73:              txtGasolina.Text = string.Empty;
  74:          }
  75:   
  76:          /// <summary>
  77:          /// Fecha a aplicação.
  78:          /// </summary>
  79:          private void mnuSair_Click(object sender, EventArgs e)
  80:          {
  81:              Application.Exit();
  82:          }
  83:   
  84:          /// <summary>
  85:          /// Menu "Sobre...", exibe uma mensagem com o nome da aplicação, 
  86:          /// nome do autor e endereço do blog do autor.
  87:          /// </summary>
  88:          private void mnuSobre_Click(object sender, EventArgs e)
  89:          {
  90:              StringBuilder mensagem = new StringBuilder("Álcool ou Gasolina\n\n");
  91:              mensagem.Append("Por Rogério Bragil\n\nBlog do Bragil - www.bragil.net");
  92:              MessageBox.Show(mensagem.ToString(), 
  93:                              "Sobre", 
  94:                              MessageBoxButtons.OK, 
  95:                              MessageBoxIcon.None, 
  96:                              MessageBoxDefaultButton.Button1);
  97:          }
  98:      }
  99:  }

 

 


Posted in: .Net , C# , Windows Mobile  Tags: , ,

Páginas

Calendário

«  March 2010  »
MoTuWeThFrSaSu
22232425262728
1234567
891011121314
15161718192021
22232425262728
2930311234
View posts in large calendar