O NeoMatrix Tech está de casa nova!

Você deverá ser redirecionado em 6 segundos. Se não, visite:
http://www.leonelfraga.com/neomatrixtech
e atualize seus favoritos.

Aviso IMPORTANTÍSSIMO!

Aviso aos navegantes:

O NeoMatrix Tech mudou de casa!!!

A partir de agora, acessem pelo novo endereço:

http://www.leonelfraga.com/neomatrixtech

Ué... mas é só o domínio mudou de lugar?

R: Na verdade, não é bem assim hehe. Este domínio que você acessa agora aponta para um blog hospedado no Blogger, enquanto no novo, aponta para um blog na plataforma Wordpress, hospedagem própria, muito mais rápida e com um layout mais agradável de ler ;)

Não vou fechar este domínio igual ao que eu fiz com o NM Light (que já está 100% na nova plataforma). Talvez beeeeeeem depois eu faça isso.

Todos os posts daqui se encontram lá, e novos posts serão colocados somente no novo endereço.
A única coisa que não consegui importar foram os comentários. Mas em breve vai ter um post contando sobre a epopéia que foi migrar o NeoMatrix Tech!

Somente vou fechar a área de comentários daqui. Caso queiram comentar, favor ver o post correspondente no "Novo NeoMatrix Tech" e comentem por lá. É bem melhor! (pena que os permalinks "amigáveis para SEO" não funcionam lá, dá erro 404 e não consigo fazer a configuração funcionar. E olha que eu já vi vários artigos falando desse assunto :( ).

Quem assina o feed, já está lendo o conteúdo do novo NeoMatrix Tech!

sábado, 30 de maio de 2009

Fazendo o SWIV 3D reconhecer o CD no DOSBox

Sempre gostei de jogos antigos, e hora ou outra sinto vontade de jogar algum.

Só que alguns deles não funcionam nas versões XP e Vista (a que eu mais uso) do Windows, porém possuem suas versões DOS.

Para estes jogos, instalei o emulador DOSBox, que na minha máquina equipada com um processador Core2Duo da Intel e 4 GiB de RAM rodam perfeitamente (não precisam de aceleração 3D :-) ).

Porém, na hora de tentar jogar o SWIV 3D, da SCI (ela mesma, a que fez o polêmico Carmageddon) sempre aparecia uma mensagem de CD-ROM não encontrado.

Executava o comando MOUNT do DOSBox com vários parâmetros e nada, o CD não era encontrado nem a pau.

Eis que dou uma pesquisada no Google e caio nesta página do Wiki do DOSBox, em que eu encontro as seguintes instruções:

  1. Abra o arquivo SWIV_DOS.EXE em um editor hexadecimal
  2. Vá até o endereço 0x2CE7F (hex) e altere este byte para 0x84 (hex)

Veja no screenshot abaixo como ficou.

SWIV_DOS aberto em um editor hexadecimal

Executei o programa novamente e BINGO!!! O programa finalmente reconheceu o CD-ROM (detalhe: este CD é ORIGINAL, e veio na Revista Bigmax nº 15, acho) inclusive com a parte CD-DA (o wiki diz que a música do CD não era executada – não sei se é o caso da unidade óptica que o cara testou isso, mas o meu drive é um gravador de DVD da LG modelo GH20NS10).

SWIV 3D @ DOSBox PS: O editor hexadecimal utilizado é o XVI32.

Um abraço!

Leia o restante deste post...

quarta-feira, 27 de maio de 2009

Review Retrô: Infoway Itautec A96 (P 133 MHz)

Você se lembra do seu primeiro microcomputador PC?

Mexi pela primeira vez em um PC pelos anos de 1995, em uma escola chamada Clube do Micro, cuja configuração começava em 286 e chegava até 486, acho.

O Sistema Operacional era o velho MS DOS, acompanhado do Windows 3.11.

Mas o primeiro PC que minha família comprou já era um dos mais avançados para a época, cuja propaganda passava na TV.

Se trata de um microcomputador Itautec Infoway modelo A96, cuja configuração é:

  • Processador Pentium 133 MHz
  • 16 MB de RAM
  • Disco Rígido de 1,2 GiB
  • Monitor de 15’’ Multimídia
  • Drive de Disquete
  • CD-ROM 8x
  • Placa de Captura de TV, capaz de exibir 16 canais simultaneamente
  • Alarme
  • Despertador
  • Fax-Modem 28.8 Kbps
  • Rádio FM
  • Videochamada
  • Sistema Operacional Windows 95
  • Diversos softwares em CD-ROM

Veja o comercial que passava na TV na época:

Após o break, vamos a um review detalhado (da parte de hardware; o máximo que eu puder lembrar hehe) do bicho.

1. Gabinete:

Painel frontal do Infoway A96

Embora a foto que tirei (10/05/2009) já não reflita a situação na qual veio o microcomputador (sim, ele tem mais de 10 anos!), pode-se ver que é um gabinete do tipo desktop, e em que seu painel frontal temos (tínhamos hehe) o acesso aos drives de CD-ROM e Disquete, os botões de Power e Reset, leds de Power e atividade do disco rígido, além de um sensor para o controle remoto.

Painel traseiro do Infoway A96

No painel traseiro temos os conectores de energia, sendo uma entrada e outro saída (geralmente para o monitor).

Alí está localizada também a entrada para um teclado AT.

Indo da esquerda para a direita, temos: Conectores dos sensores de alarme, portas serial e paralela, placa de rede (colocada posteriormente), conectores da placa de captura de vídeo (antena de TV, FM, conector da entrada A/V, saída de monitor) e por último conector do fax-modem e placa de som (saídas speaker e entradas line-in e microfone e conector MIDI).

2. Configuração

Vista geral do Infoway A96

A placa mãe é do tipo AT (naquela época, o ATX estava engatinhando lá fora), possuindo três slots PCI e dois ISA, sendo ocupados pela placa de captura e placa de fax-modem integrada à placa de som.

Como era padrão nas caixas AT, a desorganização dos cabos impera dentro do gabinete.

Placa controladora

Embora AT, este microcomputador, graças à placa da imagem acima, tinha seu comportamento bem semenhante às placas ATX atuais, permitindo ser ligada via controle remoto, fax-modem, rede (wake on modem, wake on LAN) e desligamento via sistema operacional, ou seja, não aparecia a famosa mensagem “Você agora pode desligar seu computador com segurança” do Windows 95.

Processador Intel Pentium 133 instalado

O processador é um Intel Pentium com frequência de 133 MHz, um processador forte para a época, podendo ser trocado por um processador Pentium de até 200 MHz (sem MMX).
Como você pode notar, não há memória cache na placa mãe, e isto fazia com que o desempenho da máquina ficasse abaixo de outras da mesma categoria com uma placa COAST instalada no slot.

Memórias EDO RAM

Originalmente, a memória RAM era de 16 MiB, do tipo EDO, os quais foram expandidos para 32 MiB.
Para a época, era uma excelente quantidade de memória, e os programas rodavam muito bem com 16 MiB na época.

3. Vídeo e Som

Chipset gráfico ATI Mach 64

A placa de vídeo era do tipo onboard, com um chip ATI Mach 64 com 1 MiB de memória dedicada, expansíveis até 2 MiB através de soquetes na própria placa mãe.
Chegava a uma resolução de 1280x1024 em modo 16 cores (4 bits), sendo que o ideal para a época era uma resolução de 800x600 em High Color (16 bits), que esta placa era capaz de fornecer sem problemas (era a minha configuração padrão).

Em modo True Color (24 bits), a resolução máxima era de 640x480.

Detalhe da Placa RTV

A placa de vídeo era ligada através de dois flat cables com a placa de captura: uma enviava o sinal capturado pela placa para processamento, e o outro ligava o chipset gráfico Mach 64 ao monitor.

Esta placa de captura, cujo fabricante não veio especificado, sintonizava canais de TV via antena e cabo, além de ter entrada para dispositivos externos tais como videocassete.

O software de captura era da própria Itautec, na época junta com a marca Philco, que consistia de uma “TV” com um controle remoto ao lado onde estavam os comandos que podiam ser acessados pelo mouse. Este programa inclusive fazia a gravação de vídeos em formato AVI (não me lembro qual era o codec utilizado, mas na epoca nem sequer imaginaríamos um DivX :P).

A placa também fazia a sintonia de Rádio FM, e o software de controle imitava um “3 em um”, que além das funções de rádio tinha reprodução de CD, arquivos WAVE e MIDI, além de gravação de arquivos WAVE (MP3? WTF?).

Destaque da placa de som/modem MMAT3100

A placa de som era do modelo MM AT 3100, da Aztech Labs (empresa já falecida :-(), sendo que possui 16 bits, com taxa de amostragem de 44,1 KHz, sendo compatível com Sound Blaster 16.

Possui um fax-modem de 28.8 Kbps integrada, com funções de secretária eletrônica e voz e fax. O Infoway possuia um aplicativo chamado Visual Phone, com o qual você discava para outro PC Itautec e poderia fazer uma videoconferência através de uma câmera acoplada à Placa RTV (a placa de captura). Este aplicativo também recebia chamadas e gravava, como uma secretária eletrônica.

4. Armazenamento

HD Seagate 10 GiB

Originalmente, possuia um HD de 1,2 GiB, da Western Digital, que por fatalidades do destino acabou sendo substituído por um HD Seagate de 10 GiB.

A placa mãe reconhece discos de até 8 GiB, então, para poder utilizar a capacidade máxima deste disco foi utilizado um programa particionador/formatador especial, chamado Disk Manager (da própria Seagate) para criar a função LBA na trilha 0.

Também possuia uma unidade de disquetes de 3,5’’, além de uma unidade de CD-ROM de 8 velocidades, que acabou sendo substituída por uma de 32 velocidades.

5. Manuais e Softwares

Manual do Infoway

Veio com manuais para a instalação básica, certificados de garantia e as licenças do sistema operacional e de um editor de textos, o Redator, que acompanhavam a caixa.

O sistema operacional Windows 95 veio pré-instalado, e possui um CD de recuperação que contém a imagem do disco rígido, já com todos os programas instalados e configurados.

Esse sistema operacional foi substituído pelo Windows 98 SE. Os drivers do hardware eram compatíveis com esse sistema operacional, porém eu tinha alguns problemas em fazer funcionar alguns dos aplicativos. Não sei por que milagre, uma hora funcionou.

Um detalhe referente a estes aplicativos, era que eles eram feitos em Visual Basic 3, acho, visto que ele instalava o runtime do mesmo.

Como CD’s brinde, veio com os jogos Cyclemania e Sonic, as revistas em CD Neo e Neo Wave, a enciclopédia Compton 96, e um CD-ROM do Instituto Butantã.

Veja o screenshot abaixo, ele é bem antigo. Este era o WIndows 98 com um shell alternativo, que mudava a aparência da barra de tarefas:

Windows 98 rodando o Avant Browser

Este foi um PC valente, resistiu por bravos 7 anos, sendo meu companheiro nas horas vagas em que eu me divertia jogando, programando, navegando na net, entre outras coisas.

E vocês, se lembram de seu primeiro PC?

Um abraço!

Leia o restante deste post...

sábado, 23 de maio de 2009

Objetos de acesso a dados e Regras de negócio: Direto na UI ou separar?

Quando pela primeira vez coloquei as mãos em um código ASP.NET, usando a linguagem C# com banco de dados Firebird, eu tremi nas bases.

Primeiro pois NUNCA tinha mexido com esta tecnologia antes. Hoje posso até me considerar um fanboy do C# (mas não um CSharptard hehe :P).

O código da página era monstruoso, e todos os objetos de acesso a dados, regras de negócio e afins estavam codificados na interface de usuário.

Utilizando os componentes data-aware e fazendo as ligações segundo o método “empurrador de mouse” do Visual Studio 2003? Que isso, TUDO, era feito via código.

Tinha uma classe que “abstraía” certas atividades relacionadas ao banco de dados, mas mesmo assim todo o código é engessado na interface de usuário.

Quando fiz meu primeiro programa em ASP.NET do zero, após ter feito um curso, já pensei logo de cara em fazer o projeto em mais de uma camada: separar regras de negócio, componentes de acesso a dados e camada de apresentação em coisas distintas, sendo regras de negócio e componentes de acesso a dados mantendo um acoplamento um pouco mais forte (Classe de Conexão e derivadas!).

Acompanhem o raciocínio sobre as duas abordagens: fazer tudo dentro da UI e fora:

Multicamadas ou Camada Única?

Quando fazemos tudo dentro da UI, com um forte acoplamento entre objetos de acesso (providers) de banco de dados, regras de negócio e camada de apresentação, nosso código fica fortemente engessado, ou seja, ele somente serve para aquela página e mais nada praticamente.

Com isso, um código que serviria para outra página, teria que ser reescrito, ou seja, temos um baixo reaproveitamento de regras de negócio que são utilizadas em N lugares de um sistema.

E consequentemente, a manutenção fica mais difícil: Uma alteração de uma regra de negócio que é utilizada em N lugares demandaria alteração nas N áreas do sistema em que ela é aplicada.

Falei apenas de regras de negócio: Agora veja a situação: E em uma migração do SGBD? Todos aqueles providers de acesso a dados que utilizamos podem não servir para outro SGBD, ou seja, teríamos que reescrever boa parte do sistema somente para alterar algumas classes!

Com o desenvolvimento em multicamadas, temos uma maior flexibilidade com o nosso código: podemos escrever um código, somente para teste, por exemplo, que não implicará em retrabalho na interface de usuário.

Este mesmo código poderá ser utilizado com várias interfaces de usuário: Interface Web, Desktop, Webservice, Serviço, entre outras, que pode ou não ter intervenção do usuário.

Veja, por exemplo, os artigos sobre o Controle de Acesso em ASP.NET: a interface de cadastro foi feita separadamente da camada de persistência e regras de negócio. Interface de cadastro esta que foi construída em ASP.NET, e no final da série de artigos utilizamos a mesma classe, sem alterações, em uma aplicação Windows Forms sem traumas.

Isto é proporcionado pelo alto reaproveitamento de código que é inerente a esta abordagem de desenvolvimento.

Com isso, caso tenhamos que dar manutenção em uma regra de negócio, esta regra é alterada nesta camada e ela é aplicada nos sistemas, sendo que todas as interfaces que implementam-a já sentirão os efeitos da alteração.

Ou seja, a manutenção ficou bem mais simples.

Então, concluíndo, caso você tenha que planejar um sistema todo do zero, opte pelo multicamadas. Não caia na tentação de fazer tudo na tela, baseado no clique-clique, com componentes data-aware, a não ser que seja estritamente necessário (Relatórios, alguém?).

O ganho de tempo lá na frente, quando o sistema crescer e demandar novas necessidades, vai compensar bastante.

Um abraço!

Leia o restante deste post...

terça-feira, 19 de maio de 2009

Review: Videokê RAF Electronics VMP 300D

A algum tempo atrás, presenteei minha mãe (na verdade, serve para a família toda) com um aparelho de videokê, da RAF Electronics, modelo VMP 300D.

Ao invés de comprar um aparelho simples de DVD com função de karaokê, preferi este aparelho, cujo fabricante já tem boa reputação no ramo, ou seja, um “videokê de verdade”.

Vamos a algumas fotos e as minhas impressões, após o break:

1. Embalagem

Tanto a caixa quanto as embalagens internas, que protegem o conteúdo são bem feitos, bem apresentáveis e cumprem bem a sua função.

2. Painel Frontal

Apresenta os comandos básicos para a operação do aparelho: botões para controle de reprodução de DVD/CD/MIDI-DVD (o formato de videokê), entre outros, além de controles para a programação de músicas e controle do microfone.

O display apresenta as informações básicas, tais como número da música em execução, capítulo e tempo do DVD, e entre outras informações.

Os controles do microfone são básicos: Controle de eco (para os dois microfones) e controle individual de volume. O som dos microfones são mixados com a saída de áudio do aparelho, independente da função sendo executada.

2. Conexões

Possui saída de áudio 5.1 analógicas, além de saídas digitais SPDIF coaxial e óptica, que poderão ser conectadas a um home theater. Isso além do áudio estéreo (2 canais).

Na parte de vídeo, possui saídas de vídeo composto, S-Video e Video-Componente, com a resolução de 480p (480 linhas em varredura progressiva).

Também possui entradas para integrar o aparelho a outros dispositivos, tais como suporte a amplificadores específicos para karaokê: o microfone é conectado a este amplificador, e este ao videokê que transmite algumas informações para a função de pontuação funcionar, por exemplo.

3. Controle Remoto

Nos aparelhos de hoje é praticamente impossível se virar sem o controle remoto, e no VMP 300D não é diferente. As funções mais avançadas, como setup, pesquisa de músicas através da tela, mudança de tonalidade, velocidade da música, entre outros controles são acessados via controle remoto.

4. Mídias suportadas

O formato nativo é o MIDI-Karaokê, que consiste em diversas músicas armazenadas em formato MIDI e compactadas em um único arquivo.

Veja a estrutura de diretórios do DVD:

As pastas AUDIO_TS e VIDEO_TS são as padrões do DVD: Enquanto o aparelho está carregado com um disco e tocando as músicas do videokê, o vídeo na pasta VIDEO_TS é reproduzido enquanto a música é tocada.

Na pasta hk2 há as fontes de tela, aquelas que passam de acordo com a melodia da música.

E na pasta midi0, neste DVD que adquiri contém um único arquivo de 76 MiB, que contém as músicas do videokê.

Uma curiosidade minha é saber como este DVD é autorado. Quais os programas que são utilizados para fazer a autoração compatível com o formato do aparelho.

Sabe quanto custa um DVD desses? O pacote mais completo, com 5526 músicas, custa a “irrisória” quantia de R$ 4126,00 (fonte: Mariokê). Isso mesmo, você não leu errado: mais de QUATRO MIL lulinhas em UM DVD. Quase 1/4 do valor de muitos carros por aí. Enquanto o aparelho em si, me saiu em torno de R$ 650,00.

No pacote básico, o que vem com o aparelho, vem um DVD de 600 músicas nacionais. O disco que veio com o meu me custou em torno de R$ 900,00, com 1500 músicas nacionais.

Além de seu formato nativo, ele também reproduz músicas de karaokê no formato CD+G, além dos DVD’s de karaokê que normalmente são vendidos nas lojas (tipo o Multiokê).

Fora da parte de karaokê, ele reproduz DVD-Video, VCD, CD-Audio, MP3 e JPEG (armazenados tanto em CD – R/RW quanto em DVD).

Ficou faltando ler DivX… tenho um outro aparelho de DVD da Gradiente que suporta DivX/XviD, e cumpre muito bem esta função.

5. Microfone

A qualidade do microfone que acompanha o VMP 300D é muito boa, e ele contém um dispositivo supressor de microfonia: quando aproximei ele das caixas de som, não emitiu NENHUM barulho referente a microfonia.

6. Interface na Tela

Na tela inicial, quando um disco de karaokê está carregado, mostra um “prompt” para selecionarmos a música desejada, via controle remoto.

Caso não tenha a mão uma lista impressa (que poderá ser baixada do site www.videoke.com.br), é possível pesquisar na tela pela música desejada, com filtros por idioma, cantor, título e ordenação por título ou cantor.

Mesmo assim, eu acho a lista impressa mais rápida para consultar :-)

Tela de setup (configurações) do VMP 300D, onde é configurado algumas opções do karaokê.

E a já conhecida tela de execução da música, com o controle de tom ativado.

 

E para encerrar, a tela inicial sem disco carregado.

Enfim, eu gostei muito do aparelho, pois é simples de operar e cumpre muito bem a sua função de videokê, além de ter suporte a outros formatos. A única coisa que não gostei é do preço dos discos.

Existe um outro modelo, mais avançado, o DVD-8380s, que possui uma entrada para pendrive e grava as músicas sendo cantadas, que inclusive já vi em casas de karaokê.

As especificações técnicas do bicho poderão ser obtidas clicando-se aqui.

Um abraço!

Leia o restante deste post...

sábado, 16 de maio de 2009

A atualização de sistemas é sempre um trauma?

Quando atualizamos um sistema de médio a grande porte ficamos com calafrios. Tanto nós desenvolvedores/analistas quanto o usuário.

Ficamos atentos para qualquer problema que possa ocorrer, afinal, existem bugs que só conseguiremos descobrir após exaustivas operações em produção, e que passam desapercebidos durante os testes.

Quando acabamos de atualizar e o sistema funciona de boa, não gerando um downtime muito elevado para efetuar correções é um alívio.

A parte ruim fica quando problemas começam a aparecer e o usuário joga a culpa NA ATUALIZAÇÃO, principalmente quando ela não é culpada.

O usuário alega que ocorreram problemas em uma parte do sistema, porém a parte em questão não teve NENHUMA alteração em seu código. Isto é para deixar qualquer um de orelhas em pé.

Aí, como  bom desenvolvedor e você tem que manter a calma e fidelizar o cliente, corre atrás de uma solução para um problema que você sabe que não há onde procurar, pelo menos de sua parte.

Sim, você não construiu o sistema sozinho.

Ele se comunica com uma aplicação externa e que também foi atualizada, e esta aplicação externa não está sob nosso controle.

E explicar pela enésima vez para o usuário que “esse ponto da aplicação se comunica com uma entidade externa, que também foi atualizada, o problema pode estar vindo de lá já que a nossa aplicação não teve alterações nessa parte” acaba “torrando” a nossa paciência.

Mas ele insiste que a nossa aplicação está com algum problema.

Aí quando quem fez a aplicação externa conserta o que fez, tudo volta para a calmaria.

Mas você, o usuário, seu chefe, e outras pessoas ficam com esse trauma, de que SEMPRE numa atualização conjunta de sistemas a culpa cai em cima de você primeiro, principalmente quando se está bem próximo.

Um abraço!

Leia o restante deste post...

quarta-feira, 13 de maio de 2009

Criando List<> dinamicamente a partir de Select, com Reflection

Finalizando a série Reflection na Prática: Uso na Classe de Conexão, mostro a vocês como criar um List<> de uma classe que implementa uma tabela do banco de dados a partir de um comando Select.

Usamos List<> geralmente para poder iterar com várias instâncias de um objeto, ou para popular uma lista (grids, etc), e sendo assim fica mais simples de trabalhar os dados em uma aplicação.

Vamos ver agora o método CreateList() da classe Conexão:

   1: protected object CreateList(Type contentType, Type ListType, string isql, bool isqlHaveParams)
   2: {
   3:     object list = Activator.CreateInstance(ListType);
   4:     DataTable dt = getTable(isql, isqlHaveParams);
   5:     foreach (DataRow r in dt.Rows)
   6:     {
   7:         object item = Activator.CreateInstance(contentType);
   8:         foreach (DataColumn dc in dt.Columns)
   9:         {
  10:             FieldInfo fiItens = contentType.GetField("_" + dc.ColumnName.ToUpper(), BindingFlags.NonPublic | BindingFlags.Instance);
  11:             if (r[dc.ColumnName] != DBNull.Value)
  12:             {
  13:                 fiItens.SetValue(item, ConverterDB2Obj(r[dc.ColumnName], fiItens.FieldType));
  14:             }
  15:         }
  16:         ListType.InvokeMember("Add", BindingFlags.InvokeMethod, null, list, new object[] { item });
  17:     }
  18:     return list;
  19: }

Este método é o mais curto de todos os outros mostrados, porém ele tem um conceito a mais: criação de objetos em tempo de execução.

Este método recebe como parâmetros o tipo base de cada item da lista, o tipo da lista em si, a instrução SQL e um indicador de parametrização desta instrução SQL.

A classe de cada tipo da lista deve ter as suas variáveis privadas nomeadas segundo a convenção do método Select(), e os campos informados na instrução select sm “isql” são os que serão atribuídos em cada propriedade de cada item do list.

Primeiramente, criamos uma instância do List<> que iremos retornar, porém não podemos fazer isso de forma hardcoded, pois como este método é genérico, serve para List<> de qualquer tipo.

Para contornar isso, criaremos este objeto em tempo de execução, e para isso utilizamos o método Activator.CreateInstance(), do namespace System.Runtime.Remoting, sendo que a classe Activator serve exatamente para esta criação de objetos em tempo de execução (runtime).

O método CreateInstance() requer como parâmetro na sobrecarga que utilizamos o tipo de objeto a ser criado, sendo o tipo no parâmetro ListType, que é o tipo do List<> que iremos criar será passado como esse parâmetro. Guardamos este objeto na variável “list”, do tipo object.

Em seguida, utilizamos o método getTable da classe Conexão, passando a instrução SQL para pegar os dados e guardamos no DataTable “dt”.

Com um laço foreach, percorremos cada registro do DataTable.

Dentro deste laço, criamos, utilizando novamente o método Activator.CreateInstance() uma instância do item da lista, cuja classe está no parâmetro “contentType”.

Aqui um parêntese: O que aconteceria se criássemos esta instância FORA do laço foreach, hein? ;-)

Agora faremos um outro laço foreach, agora para iterar sobre as colunas deste registro que estamos trabalhando. Guardamos na variável fiItens, do tipo FieldInfo, as informações sobre a variável privada associada àquele campo, com o método GetField() da variável “contentType”.

Se o campo não estiver nulo, atribuiremos este valor na propriedade utilizando o método SetValue() do FieldInfo “fiItens”, que recebe como parâmetro o item que instanciamos acima e o valor com uma rotina de conversão aplicada (ver os outros artigos desta série para entender melhor).

Atribuídos todos os campos, chamaremos o método Add() do List<> de uma forma diferente: Através do método InvokeMember da classe Type, que no nosso caso é representado pela variável “ListType”.

Ele recebe como parâmetros o nome do método, no nosso caso Add, o Binding Flag, que no nosso caso é BindingFlags.InvokeMethod, o binder padrão, que pode ser null, o objeto a sofrer a execução do método e um array de object que representa a lista de parâmetros do método a ser executado.

No nosso caso, criamos um array de object com apenas um elemento, cujo valor é a variável item, que é o item da lista que iremos inserir.

Iterados todos os registros, saímos do primeiro laço e retornamos o List<> na forma de object.

Veja como utilizar este método:

   1: private List<TTpFormaContato> ListaGenerica()
   2: {
   3:     List<TTpFormaContato> l = new List<TTpFormaContato>();
   4:     return (List<TTpFormaContato>)CreateList(this.GetType(), l.GetType(), _SearchSQL, CountSQLParams() > 0);
   5: }
   6:  
   7: public static List<TTpFormaContato> ListarTodos()
   8: {
   9:     TTpFormaContato fc = new TTpFormaContato();
  10:     fc._SearchSQL = "select * from TP_FORMA_CONTATO";
  11:     fc.ClearSQLParams();
  12:     return fc.ListaGenerica();
  13: }

Este trecho foi retirado do Simple PIM, o exemplo da nova Classe de Conexão, e de início criamos um objeto List<nome da classe> para poder usar seu método GetType() no método CreateList().

Para utilizar efetivamente o list retornado, fazemos um typecast para o tipo base desejado (o que instanciamos acima).

Enfim, chegamos ao final da série Reflection na Prática: Uso na Classe de Conexão e vimos como o Reflection pode fazer a gente economizar código :-)

Um abraço!

Leia o restante deste post...

segunda-feira, 11 de maio de 2009

Nova campanha do Norton 2009 (Symantec). E sem FUD!

logo-symantec

Ouvindo esses dias o Estádio 97, quando o Narigudo Benjamin Back deu o testemunhal da Symantec, notei que ele falava algumas palavras diferentes.

Depois do post aqui no NeoMatrix Tech e no blog do Chris Benseler, fiquei conhecendo um documento chamado “Norton Living Report”, em que são apresentadas várias estatísticas sobre o comportamento das pessoas perante a Internet.

Este documento contém várias estatísticas interessantes, que inclusive são inspiração para um futuro post na categoria Relacionamentos do NeoMatrix Light, como por exemplo, um dos itens é intitulado “A tecnologia pode comprar amor?”.

O link acima, que aponta para um site em flash, contém uma apresentação e um link para o download do documento em formato PDF. Vale a leitura.

E a nova campanha da Symantec fala justamente sobre estas estatísticas, para aí então sugerir a compra do Norton Internet Security, sem a apelação ao FUD em relação às ferramentas gratuítas da campanha anterior.

Agora sim, esta campanha do Norton Internet Security foi uma bola dentro, gostei de ouvir essa nova propaganda.

Até merece o link para o produto: Norton Internet Security 2009.

Mas… eu ainda fico com as minhas soluções gratuitas e que estão me atendendo muitíssimo bem }-]

Um abraço!

Leia o restante deste post...

sábado, 9 de maio de 2009

Atribuindo da Classe para a Interface de Usuário via Reflection

Em mais um artigo da série Reflection na Prática: Uso na Classe de Conexão, desta vez abordo os métodos BindToUI e BindFromUI, mostrando como fazer a atribuição das propriedades de uma classe para os componentes da interface de usuário e vice-versa.

Trabalharemos mais neste método os componentes que recebem um único valor, tais como textboxes, checkboxes, dropdownlists, por aí.

Mas espera ae… o DropDownList recebe vários valores! Sim, mas não estou falando da lista em si, e sim do valor atualmente selecionado :P (e isto vale para os outros __list também!)

Vamos agora atribuir as propriedades da classe para a interface de usuário, ou seja, o método BindToUI da classe Conexão:

   1: public void BindToUI(Page UI, Type type, ArrayList ExcludeFromBind)
   2: {
   3:     Type t = this.GetType();
   4:     foreach (FieldInfo c in type.GetFields(BindingFlags.Instance | BindingFlags.NonPublic))
   5:     {
   6:         if (ExcludeFromBind.Contains(c.Name))
   7:         {
   8:             continue;
   9:         }
  10:         if (c == null)
  11:         {
  12:             continue;
  13:         }
  14:         if (c.Name == null)
  15:         {
  16:             continue;
  17:         }
  18:  
  19:         //Retira o prefixo do nome do componente -> ele DEVE ter 3 letras, e o ID do controle deve ter mais que 3 letras
  20:         string PropertyPattern = (c.Name.Length < 3) ? "" : c.Name.Substring(3, c.Name.Length - 3);
  21:         PropertyPattern = PropertyPattern.Replace(t.Name, "");
  22:         if (PropertyPattern.Contains("_"))
  23:         {
  24:             PropertyPattern = PropertyPattern.Substring(0, PropertyPattern.IndexOf("_"));
  25:         }
  26:  
  27:         PropertyInfo pi = t.GetProperty(PropertyPattern);
  28:         if (pi != null)
  29:         {
  30:             if (pi.GetValue(this, null) == null)
  31:             {
  32:                 continue;
  33:             }
  34:  
  35:             int IndexProp = -1;
  36:             HasIndexIdentifier(c.Name, out IndexProp);
  37:  
  38:             if (c.FieldType.FullName.Equals("System.Web.UI.WebControls.TextBox"))
  39:             {
  40:                 int idx = 0;
  41:                 string formatinfo = "";
  42:                 if (ContainFormatInfo(pi.Name, out idx, out formatinfo))
  43:                 {
  44:                     if (!pi.PropertyType.IsArray)
  45:                     {
  46:                         (c.GetValue(UI) as TextBox).Text = String.Format(formatinfo, pi.GetValue(this, null));
  47:                     }
  48:                     else
  49:                     {
  50:                         object[] arrVal = (object[])pi.GetValue(this, null);
  51:                         (c.GetValue(UI) as TextBox).Text = String.Format(formatinfo, arrVal[IndexProp]);
  52:                     }
  53:                 }
  54:                 else
  55:                 {
  56:                     if (!pi.PropertyType.IsArray)
  57:                     {
  58:                         (c.GetValue(UI) as TextBox).Text = pi.GetValue(this, null).ToString();
  59:                     }
  60:                     else
  61:                     {
  62:                         object[] arrVal = (object[])pi.GetValue(this, null);
  63:                         (c.GetValue(UI) as TextBox).Text = arrVal[IndexProp].ToString();
  64:                     }
  65:                 }
  66:             }
  67:             if (c.FieldType.FullName.Equals("System.Web.UI.WebControls.DropDownList"))
  68:             {
  69:                 if (!pi.PropertyType.IsArray)
  70:                 {
  71:                     (c.GetValue(UI) as DropDownList).SelectedValue = pi.GetValue(this, null).ToString(); ;
  72:                 }
  73:                 else
  74:                 {
  75:                     object[] arrVal = (object[])pi.GetValue(this, null);
  76:                     (c.GetValue(UI) as DropDownList).SelectedValue = arrVal[IndexProp].ToString();
  77:                 }
  78:             }
  79:  
  80:  
  81:             if (c.FieldType.FullName.Equals("System.Web.UI.WebControls.RadioButton"))
  82:             {
  83:                 if (pi.PropertyType.Name.Equals("System.Int16") || pi.PropertyType.Name.Equals("System.Int32") || pi.PropertyType.Name.Equals("System.Int64"))
  84:                 {
  85:                     if (!pi.PropertyType.IsArray)
  86:                     {
  87:                         (c.GetValue(UI) as RadioButton).Checked = ((int)pi.GetValue(this, null) > 0) ? true : false;
  88:                     }
  89:                     else
  90:                     {
  91:                         object[] arrVal = (object[])pi.GetValue(this, null);
  92:                         (c.GetValue(UI) as RadioButton).Checked = ((int)arrVal[IndexProp] > 0) ? true : false;
  93:                     }
  94:                 }
  95:                 if (pi.PropertyType.Name.Equals("System.Boolean"))
  96:                 {
  97:                     if (!pi.PropertyType.IsArray)
  98:                     {
  99:                         (c.GetValue(UI) as RadioButton).Checked = (bool)pi.GetValue(this, null);
 100:                     }
 101:                     else
 102:                     {
 103:                         object[] arrVal = (object[])pi.GetValue(this, null);
 104:                         (c.GetValue(UI) as RadioButton).Checked = (bool)arrVal[IndexProp];
 105:                     }
 106:                 }
 107:                 if (pi.PropertyType.Name.Equals("System.String"))
 108:                 {
 109:                     if (!pi.PropertyType.IsArray)
 110:                     {
 111:                         (c.GetValue(UI) as RadioButton).Checked = (pi.GetValue(this, null).ToString().ToUpper().Equals("SIM") || pi.GetValue(this, null).ToString().ToUpper().Equals("S"));
 112:                     }
 113:                     else
 114:                     {
 115:                         object[] arrVal = (object[])pi.GetValue(this, null);
 116:                         (c.GetValue(UI) as RadioButton).Checked = ((arrVal[IndexProp].ToString().ToUpper().Equals("SIM") || arrVal[IndexProp].ToString().ToUpper().Equals("S")));
 117:                     }
 118:                 }
 119:             }
 120:             if (c.FieldType.FullName.Equals("System.Web.UI.WebControls.Label"))
 121:             {
 122:                 string formatinfo = "";
 123:                 int idx = 0;
 124:                 if (ContainFormatInfo(pi.Name, out idx, out formatinfo))
 125:                 {
 126:                     if (!pi.PropertyType.IsArray)
 127:                     {
 128:                         (c.GetValue(UI) as Label).Text = String.Format(formatinfo, pi.GetValue(this, null));
 129:                     }
 130:                     else
 131:                     {
 132:                         object[] arrVal = (object[])pi.GetValue(this, null);
 133:                         (c.GetValue(UI) as Label).Text = String.Format(formatinfo, arrVal[IndexProp]);
 134:                     }
 135:                 }
 136:                 else
 137:                 {
 138:                     if (!pi.PropertyType.IsArray)
 139:                     {
 140:                         (c.GetValue(UI) as Label).Text = pi.GetValue(this, null).ToString();
 141:                     }
 142:                     else
 143:                     {
 144:                         object[] arrVal = (object[])pi.GetValue(this, null);
 145:                         (c.GetValue(UI) as Label).Text = arrVal[IndexProp].ToString();
 146:                     }
 147:                 }
 148:             }
 149:             if (c.FieldType.FullName.Equals("System.Web.UI.WebControls.CheckBox"))
 150:             {
 151:                 if (pi.PropertyType.Name.Equals("System.Int16") || pi.PropertyType.Name.Equals("System.Int32") || pi.PropertyType.Name.Equals("System.Int64"))
 152:                 {
 153:                     if (!pi.PropertyType.IsArray)
 154:                     {
 155:                         (c.GetValue(UI) as CheckBox).Checked = ((int)pi.GetValue(this, null) > 0) ? true : false;
 156:                     }
 157:                     else
 158:                     {
 159:                         object[] arrVal = (object[])pi.GetValue(this, null);
 160:                         (c.GetValue(UI) as CheckBox).Checked = ((int)arrVal[IndexProp] > 0) ? true : false;
 161:                     }
 162:                 }
 163:                 if (pi.PropertyType.Name.Equals("Boolean"))
 164:                 {
 165:                     if (!pi.PropertyType.IsArray)
 166:                     {
 167:                         (c.GetValue(UI) as CheckBox).Checked = (bool)pi.GetValue(this, null);
 168:                     }
 169:                     else
 170:                     {
 171:                         object[] arrVal = (object[])pi.GetValue(this, null);
 172:                         (c.GetValue(UI) as CheckBox).Checked = (bool)arrVal[IndexProp];
 173:                     }
 174:                 }
 175:                 if (pi.PropertyType.Name.Equals("System.String"))
 176:                 {
 177:                     if (!pi.PropertyType.IsArray)
 178:                     {
 179:                         (c.GetValue(UI) as CheckBox).Checked = (pi.GetValue(this, null).ToString().ToUpper().Equals("SIM") || pi.GetValue(this, null).ToString().ToUpper().Equals("S"));
 180:                     }
 181:                     else
 182:                     {
 183:                         object[] arrVal = (object[])pi.GetValue(this, null);
 184:                         (c.GetValue(UI) as CheckBox).Checked = ((arrVal[IndexProp].ToString().ToUpper().Equals("SIM") || arrVal[IndexProp].ToString().ToUpper().Equals("S")));
 185:                     }
 186:                 }
 187:             }
 188:             if (c.FieldType.FullName.Equals("System.Web.UI.WebControls.CheckBoxList"))
 189:             {
 190:                 if (!pi.PropertyType.IsArray)
 191:                 {
 192:                     (c.GetValue(UI) as CheckBoxList).SelectedValue = pi.GetValue(this, null).ToString();
 193:                 }
 194:                 else
 195:                 {
 196:                     object[] arrVal = (object[])pi.GetValue(this, null);
 197:                     (c.GetValue(UI) as CheckBoxList).SelectedValue = arrVal[IndexProp].ToString();
 198:                 }
 199:             }
 200:             if (c.FieldType.FullName.Equals("System.Web.UI.WebControls.RadioButtonList"))
 201:             {
 202:                 if (!pi.PropertyType.IsArray)
 203:                 {
 204:                     (c.GetValue(UI) as RadioButtonList).SelectedValue = pi.GetValue(this, null).ToString();
 205:                 }
 206:                 else
 207:                 {
 208:                     object[] arrVal = (object[])pi.GetValue(this, null);
 209:                     (c.GetValue(UI) as RadioButtonList).SelectedValue = arrVal[IndexProp].ToString();
 210:                 }
 211:             }
 212:             if (c.FieldType.FullName.Equals("System.Web.UI.WebControls.GridView"))
 213:             {
 214:                 if (!pi.PropertyType.IsArray)
 215:                 {
 216:                     (c.GetValue(UI) as GridView).DataSource = pi.GetValue(this, null);
 217:                     (c.GetValue(UI) as GridView).DataBind();
 218:                 }
 219:                 else
 220:                 {
 221:                     object[] arrVal = (object[])pi.GetValue(this, null);
 222:                     (c.GetValue(UI) as GridView).DataSource = arrVal[IndexProp];
 223:                     (c.GetValue(UI) as GridView).DataBind();
 224:                 }
 225:             }
 226:  
 227:  
 228:             if (c.FieldType.FullName.Equals("System.Web.UI.HtmlControls.HtmlInputHidden"))
 229:             {
 230:                 string formatinfo = "";
 231:                 int idx = 0;
 232:                 if (ContainFormatInfo(pi.Name, out idx, out formatinfo))
 233:                 {
 234:                     if (!pi.PropertyType.IsArray)
 235:                     {
 236:                         (c.GetValue(UI) as HtmlInputHidden).Value = String.Format(formatinfo, pi.GetValue(this, null));
 237:                     }
 238:                     else
 239:                     {
 240:                         object[] arrVal = (object[])pi.GetValue(this, null);
 241:                         (c.GetValue(UI) as HtmlInputHidden).Value = String.Format(formatinfo, arrVal[IndexProp]);
 242:                     }
 243:                 }
 244:                 else
 245:                 {
 246:                     if (!pi.PropertyType.IsArray)
 247:                     {
 248:                         (c.GetValue(UI) as HtmlInputHidden).Value = pi.GetValue(this, null).ToString();
 249:                     }
 250:                     else
 251:                     {
 252:                         object[] arrVal = (object[])pi.GetValue(this, null);
 253:                         (c.GetValue(UI) as HtmlInputHidden).Value = arrVal[IndexProp].ToString();
 254:                     }
 255:                 }
 256:             }
 257:         }
 258:     }
 259: }

Sim, ele é um tanto longo, mas cada if trabalha da mesma maneira, por isso, quando chegar na parte de explicar a atribuição em si irei falar apenas sobre o primeiro componente, ou seja, de como atribuir o objeto em um TextBox; os outros serão análogos a este.

Como lembrete, soma-se ao lembrete do post anterior as convenções para nomearmos os componentes da interface de usuário: Prefixo de três (3) letras + Nome da Classe + Nome da Propriedade, todos estes sensíveis ao caso.

Por exemplo, temos uma classe chamada TFuncionario e uma propriedade chamada Nome será atribuída a um textbox. Seu nome deve ficar assim: tbxTFuncionarioNome.

O método pede como parâmetros o objeto Page que terá seus componentes atribuídos, as informações de seu tipo (método GetType() do objeto Page), e um ArrayList com os nomes de cada objeto que não será atribuído caso haja correspondência dele na classe.

Inicialmente, pego as informações de tipo do próprio objeto que vou atribuir e guardo na variável “t”.

Em seguida, faço uma iteração através de um laço foreach em todas as variáveis privadas ou protegidas da página que terá os valores dos componentes modificados. O método GetFields() da classe Type retorna uma coleção de objetos FieldInfo, que por sua vez correspondem às propriedades da classe referenciada pela variável “type” (segundo parâmetro do método BindToUI()). Este médodo pede como parâmetro os BindingFlags, sendo que colocamos o BindingFlags.Instance, já que queremos as variáveis de instância e BindingFlags.NonPublic, já que todos os componentes de uma página Web são declarados como protected.

Com cada item a ser iterado guardado na variável “c” declarada no foreach, verificamos se o mesmo está dentro do ArrayList ExcludeFromBind através de seu nome. Se estiver, passamos para a próxima iteração. Passamos para a próxima iteração caso o objeto seja nulo ou a propriedade Name for nula também.

Em seguida, isolamos o nome da propriedade da classe do nome do componente. Retiramos o prefixo, o nome da classe, e se ele for sucedido de underline (_) mais um número, isolamos isso também. Guardamos o resultado na variável “PropertyPattern”.

Em seguida, instanciamos um objeto do tipo PropertyInfo, que é análogo ao FieldInfo, só que neste caso iremos trabalhar sobre Propriedades e não sobre campos, ou seja, as variáveis de uma classe que possuem métodos get() e/ou set(). Para isso, inicializamos a variável “pi” utilizando o método GetProperty() da classe Type (a variável “t”) passando como parâmetro o nome da propriedade que iremos atribuir em seu correspondente na UI.

Se a propriedade for nula e seu valor, que pegamos através do método GetValue() de PropertyInfo, que pede como parâmetros o objeto a ser verificado (ponteiro this) e o índice (caso a propriedade seja indexada), também for nulo, passamos para a próxima iteração do foreach.

Criamos uma variável inteira chamada IndexProp, que denota se a nossa propriedade em questão é indexada: Se seu valor for –1, significa que não é indexada, caso contrário, denota o próprio índice.

Este índice é buscado através do método privado de Conexão HasIndexIndentifier, que recebe como parâmetros o nome do componente e devolve como saída o índice.

Agora a brincadeira da atribuição começa. Vou destacar aqui como atribuímos para um TextBox, que é o componente mais recorrente em uma interface de usuário:

   1: if (c.FieldType.FullName.Equals("System.Web.UI.WebControls.TextBox"))
   2: {
   3:     int idx = 0;
   4:     string formatinfo = "";
   5:     if (ContainFormatInfo(pi.Name, out idx, out formatinfo))
   6:     {
   7:         if (!pi.PropertyType.IsArray)
   8:         {
   9:             (c.GetValue(UI) as TextBox).Text = String.Format(formatinfo, pi.GetValue(this, null));
  10:         }
  11:         else
  12:         {
  13:             object[] arrVal = (object[])pi.GetValue(this, null);
  14:             (c.GetValue(UI) as TextBox).Text = String.Format(formatinfo, arrVal[IndexProp]);
  15:         }
  16:     }
  17:     else
  18:     {
  19:         if (!pi.PropertyType.IsArray)
  20:         {
  21:             (c.GetValue(UI) as TextBox).Text = pi.GetValue(this, null).ToString();
  22:         }
  23:         else
  24:         {
  25:             object[] arrVal = (object[])pi.GetValue(this, null);
  26:             (c.GetValue(UI) as TextBox).Text = arrVal[IndexProp].ToString();
  27:         }
  28:     }
  29: }

Se o tipo do componente da iteração do foreach for do tipo System.Web.UI.WebControls.TextBox (um TextBox), verificamos primeiro se ele possui informações para a formatação de seu conteúdo, através do método ContainFormatInfo() da classe Conexao. Ele verifica a coleção _FormatProperties, e pede como parâmetros o nome da propriedade; e devolve como parâmetros de saída o índice do item a ser formatado e a string de formatação.

Se a propriedade em questão não é do tipo array (indexada), é feito um cast do componente da iteração atual do foreach para TextBox, que estará no método GetValue() nossa variável “c”) e atribuímos na propriedade Text o valor da propriedade correspondente no objeto, utilizando o método GetValue do objeto “pi”.

Caso a propriedade seja indexada, primeiro pegamos os valores para um array de object, para em seguida atribuir deste array somente o valor do índice que armazenamos anteriormente em IndexProp.

E se fomos formatar a propriedade para exibí-la, no passo anterior fazemos a atribuição através de um comando String.Format.

Para os outros componentes, o método é análogo.

O método BindFromUI() faz a operação inversa, tendo a mesma lógica do BindToUI(), porém ele faz uma troca de tipos, como veremos na transcrição do código a seguir:

   1: public void BindFromUI(Page UI, Type type, ArrayList ExcludeFromBind)
   2: {
   3:     Type t = this.GetType();
   4:     foreach (FieldInfo c in type.GetFields(BindingFlags.Instance | BindingFlags.NonPublic))
   5:     {
   6:         if (ExcludeFromBind.Contains(c.Name))
   7:         {
   8:             continue;
   9:         }
  10:         if (c == null)
  11:         {
  12:             continue;
  13:         }
  14:         if (c.Name == null)
  15:         {
  16:             continue;
  17:         }
  18:  
  19:         //Retira o prefixo do nome do componente -> ele DEVE ter 3 letras, e o ID do controle deve ter mais que 3 letras
  20:         string PropertyPattern = (c.Name.Length < 3) ? "" : c.Name.Substring(3, c.Name.Length - 3);
  21:         PropertyPattern = PropertyPattern.Replace(t.Name, "");
  22:         if (PropertyPattern.Contains("_"))
  23:         {
  24:             PropertyPattern = PropertyPattern.Substring(0, PropertyPattern.IndexOf("_"));
  25:         }
  26:  
  27:  
  28:         PropertyInfo pi = t.GetProperty(PropertyPattern);
  29:         if (pi != null)
  30:         {
  31:             if (pi.GetSetMethod() == null)
  32:             {
  33:                 continue;
  34:             }
  35:             int IndexProp = -1;
  36:             HasIndexIdentifier(c.Name, out IndexProp);
  37:  
  38:             if (c.FieldType.FullName.Equals("System.Web.UI.WebControls.TextBox"))
  39:             {
  40:                 if ((c.GetValue(UI) as TextBox).Text.Trim().Equals(""))
  41:                 {
  42:                     pi.SetValue(this, null, null);
  43:                 }
  44:                 else
  45:                 {
  46:                     pi.SetValue(this, Convert.ChangeType((c.GetValue(UI) as TextBox).Text, pi.PropertyType.Name.Equals("Nullable`1") ? System.Nullable.GetUnderlyingType(pi.PropertyType) : pi.PropertyType), null);
  47:                 }
  48:             }
  49:  
  50:             if (c.FieldType.FullName.Equals("System.Web.UI.WebControls.DropDownList"))
  51:             {
  52:                 if ((c.GetValue(UI) as DropDownList).SelectedValue.Trim().Equals(""))
  53:                 {
  54:                     pi.SetValue(this, null, null);
  55:                 }
  56:                 else
  57:                 {
  58:                     pi.SetValue(this, Convert.ChangeType((c.GetValue(UI) as DropDownList).SelectedValue, pi.PropertyType.Name.Equals("Nullable`1") ? System.Nullable.GetUnderlyingType(pi.PropertyType) : pi.PropertyType), null);
  59:                 }
  60:             }
  61:             if (c.FieldType.FullName.Equals("System.Web.UI.WebControls.RadioButton"))
  62:             {
  63:                 if (pi.PropertyType.Name.Equals("System.Int16") || pi.PropertyType.Name.Equals("System.Int32") || pi.PropertyType.Name.Equals("System.Int64"))
  64:                 {
  65:                     pi.SetValue(this, ((c.GetValue(UI) as RadioButton).Checked ? 1 : 0), null);
  66:                 }
  67:                 if (pi.PropertyType.Name.Equals("Boolean"))
  68:                 {
  69:                     pi.SetValue(this, (c.GetValue(UI) as RadioButton).Checked, null);
  70:                 }
  71:                 if (pi.PropertyType.Name.Equals("System.String"))
  72:                 {
  73:                     pi.SetValue(this, ((c.GetValue(UI) as RadioButton).Checked ? "S" : "N"), null);
  74:                 }
  75:             }
  76:             if (c.FieldType.FullName.Equals("System.Web.UI.WebControls.Label"))
  77:             {
  78:                 pi.SetValue(this, Convert.ChangeType((c.GetValue(UI) as Label).Text, pi.PropertyType.Name.Equals("Nullable`1") ? System.Nullable.GetUnderlyingType(pi.PropertyType) : pi.PropertyType), null);
  79:             }
  80:  
  81:             if (c.FieldType.FullName.Equals("System.Web.UI.WebControls.CheckBox"))
  82:             {
  83:                 if (pi.PropertyType.Name.Equals("System.Int16") || pi.PropertyType.Name.Equals("System.Int32") || pi.PropertyType.Name.Equals("System.Int64"))
  84:                 {
  85:                     pi.SetValue(this, ((c.GetValue(UI) as CheckBox).Checked ? 1 : 0), null);
  86:                 }
  87:                 if (pi.PropertyType.Name.Equals("Boolean"))
  88:                 {
  89:                     pi.SetValue(this, (c.GetValue(UI) as CheckBox).Checked, null);
  90:                 }
  91:                 if (pi.PropertyType.Name.Equals("System.String"))
  92:                 {
  93:                     pi.SetValue(this, ((c.GetValue(UI) as CheckBox).Checked ? "S" : "N"), null);
  94:                 }
  95:             }
  96:             if (c.FieldType.FullName.Equals("System.Web.UI.WebControls.CheckBoxList"))
  97:             {
  98:                 if ((c.GetValue(UI) as CheckBoxList).SelectedValue.Trim().Equals(""))
  99:                 {
 100:                     pi.SetValue(this, null, null);
 101:                 }
 102:                 else
 103:                 {
 104:                     pi.SetValue(this, Convert.ChangeType((c.GetValue(UI) as CheckBoxList).SelectedValue, pi.PropertyType.Name.Equals("Nullable`1") ? System.Nullable.GetUnderlyingType(pi.PropertyType) : pi.PropertyType), null);
 105:                 }
 106:             }
 107:             if (c.FieldType.FullName.Equals("System.Web.UI.WebControls.RadioButtonList"))
 108:             {
 109:                 if ((c.GetValue(UI) as RadioButtonList).SelectedValue.Trim().Equals(""))
 110:                 {
 111:                     pi.SetValue(this, null, null);
 112:                 }
 113:                 else
 114:                 {
 115:                     pi.SetValue(this, Convert.ChangeType((c.GetValue(UI) as RadioButtonList).SelectedValue, pi.PropertyType.Name.Equals("Nullable`1") ? System.Nullable.GetUnderlyingType(pi.PropertyType) : pi.PropertyType), null);
 116:                 }
 117:             }
 118:             if (c.FieldType.FullName.Equals("System.Web.UI.HtmlControls.HtmlInputHidden"))
 119:             {
 120:                 if ((c.GetValue(UI) as HtmlInputHidden).Value.Trim().Equals(""))
 121:                 {
 122:                     pi.SetValue(this, null, null);
 123:                 }
 124:                 else
 125:                 {
 126:                     pi.SetValue(this, Convert.ChangeType((c.GetValue(UI) as HtmlInputHidden).Value, pi.PropertyType.Name.Equals("Nullable`1") ? System.Nullable.GetUnderlyingType(pi.PropertyType) : pi.PropertyType), null);
 127:                 }
 128:             }
 129:         }
 130:     }
 131: }

Se fomos atribuir a propriedade Text de um TextBox em uma propriedade inteira, teremos um erro na execução do programa. Para isso, no momento da atribuição utilizo o método Convert.ChangeType, que pede como parâmetros o valor e o tipo de destino, que no nosso caso é o tipo da propriedade a ser atribuída.

Para pegar o tipo, primeiro verificamos se a propriedade é do tipo nulável, pois caso afirmativo deveremos pegar o tipo encapsulado ao invés do tipo real. Utilizando o método System.Nullable.GetUnderlyingType() conseguimos fazer isso.

A lógica deste método é análoga ao BindToUI(), o que dispensa maiores comentários a respeito deste código.

Foi trabalhoso no início, mas depois poupou um trabalho…

Um abraço!

Leia o restante deste post...

  © Blogger templates ProBlogger Template by Ourblogtemplates.com 2008 - Editado e configurado por Leonel F.

Voltar ao TOPO