segunda-feira, 27 de agosto de 2007

Classe ReadOnlyCollection

Recentemente tive um problema que outros já podem ter tido.

Tinha uma classe com uma coleção (List<>) private que queria disponibilizar, mas queria que quem utilizasse a classe pudesse apenas ler o conteúdo da lista, sem alterá-la. Se eu simplesmente colocasse uma propriedade pública com a lista, ia permitir que alguém adicionasse ou removesse elementos dela.

Entre outras soluções que pensei para isso, descobri uma classe que ajuda bastante. A ReadOnlyCollection. Ela é na verdade um Wrapper para uma coleção. Vamos supor que você tem uma lista de string na sua classe:

private List _linhas;

Para publicá-la como somente leitura , use :

public ReadOnlyCollection Linhas
{
get { return new ReadOnlyCollection (_linhas); }
}

Vale lembrar que esse método não duplica o conteúdo da lista. Como a classe é apenas um wrapper, qualquer alteração no conteúdo da lista será refletida no objeto ReadOnlyCollection já criado.

Classe ControlPaint

Uma classe interessante para quem está trabalhando com controles Owner Draw, ou seja, desenhando na mão o conteúdo do controle, é a ControlPaint.

Ela possui métodos para facilitar o desenho de controles, como o método DrawBorder3D (Acho que não preciso dizer que esse método desenha uma borda em 3D) e métodos para desenhar botões, checkboxes etc.

sexta-feira, 17 de agosto de 2007

Breakpoints Avançados

O tradicional Breakpoint, usado para interromper a execução do sistema e permitir a depuração do sistema possui algumas opções que podem ajudar bastante.

Você já teve que depurar algum loop e ficar apertando F10 até chegar na iteração que está dando problema? Você pode configurar o breakpoint para interromper a execução somente na n-ésima vez que passar por ele. Para isso, clique com o botão direito em um breakpoint existente (Clique na bolinha vermelha) e vá em "Hit Count...". Existem algumas opções para parada, uma pra parar quando o número de passados pelo breakpoint atingir um determinado valor ou for múltiplo de um determinado número , por exemplo.

Outra opção interessante é "Condition..." , acessada do mesmo popup menu, que permite que estabeleça um condição para que o Breakpoint pare. Você pode, por exemplo, fazer com que o breakpoint pare quando um totalizador atingir determinado valor, colocando uma expressão como "total > 100". A idéia é que se a expressão que você colocar for True, o Breakpoint será interrompido.

terça-feira, 14 de agosto de 2007

Uma outra forma de TypeCasting.

Provavelmente você já fez um TypeCasting, como o da linha abaixo:

DataSet ds = (DataSet) dataGridView1.DataSource;

Na forma acima, se o valor que está sendo convertido, no caso o dataGridView1.DataSource, for nulo ou não for um DataSet, será gerado um erro. Você teria que fazer um tratamento antes de efetuar o cast, usando o operador is para verificar se é realmente do tipo esperado:

if (dataGridView1.DataSource != null && dataGridView1.DataSource is DataSet)
{
DataSet ds = (DataSet) dataGridView1.DataSource;
}

Uma outra forma é fazer o cast com o operador as. Com esse operador, se o valor convertido for nulo ou não for do tipo esperado, será retornado nulo. Com isso, o código acima poderia ser escrito assim:

DataSet ds = dataGridView1 as DataSet;
if (ds != null)
...

Além disso, por não usar parenteses, pode deixar a sintaxe um pouco mais limpa, como no exemplo abaixo:

DataTable tbl = ((DataSet) dataGridView1.DataSource).Tables[0];

poderia ser representada com um conjunto de parênteses a menos usando o as :

DataTable tbl = (dataGridView1.DataSource as DataSet).Tables[0];

segunda-feira, 13 de agosto de 2007

Combo Box Somente Leitura

Quem programa em windows já deve ter se deparado com um situação onde precisava colocar uma ComboBox em modo somente leitura. No .Net não existe a propriedade ReadOnly na ComboBox. Creio que isso seja uma limitação do próprio windows, pois acontecia a mesma coisa no Delphi.

Uma solução normalmente adotada é deixar a combo desabilitada, o que não é muito bom, pois dessa forma o usuário não consegue navegar no controle com o Tab nem selecionar um texto para copiar.

Uma sugestão seria ao invés de desabilitar a combo , trocá-la por uma TextBox ReadOnly enquanto o usuário não puder alterar o valor. Quando habilitar o campo novamente para o usuário, retorna a ComboBox.

É , eu sei, é uma gambiarra, mas o resultado final é melhor (pelo menos para o usuário) do que simplesmente desabilitar.

segunda-feira, 6 de agosto de 2007

Escondendo uma TabPage de um TabControl

Se você desenvolve em Windows Forms, já deve ter passado por alguma situação onde era necessário esconder algumas páginas de um controles TabControl de acordo com a situação. O problema é que o TabControl não possui um método que permita apenas esconder as páginas. Será necessário removê-la no controle:

TabControl1.TabPages.Remove(tabPage1);

e para adicioná-la novamente :

TabControl1.TabPages.Add(tabPage1);

sexta-feira, 3 de agosto de 2007

BitConverter

Outra classe interessante que descobri recentemente foi a BitConverter. Quem já teve que trabalhar com classes Stream , para gravar ou ler um arquivo, por exemplo, já deve ter notado que os métodos para gravar e ler os dados trabalham com Array de byte. A classe BitConverter serve para converter valores primitivos, como int e boolean, de e para byte[].
Para converter um valor qualquer para byte[], use o método BitConverter.GetBytes(valor), e para o caminho contrário, use os métodos específicos, como BitConverter.ToInt32(byteArray).

Já se você tiver uma string e precisar converter de e para um array de byte, pode usar a classe Encoding. Aí vai depender se a string está em ASCII, UTF8, Unicode etc. Para converter de string para byte[], use Encoding.UTF8.GetBytes("String"), e para o caminho inverso, use Encoding.UTF8.GetString(byteArray). É só substituir o UTF8 pelo encoding apropriado.