System.Collections.Generic.HashSet

Bem, felizmente o time da BCL (Base Class Library) trabalha em um tipo de coleção chamado (temporariamente) de HashSet, que é uma coleção de elementos únicos, ou seja, sem a possibilidade de incluir elementos repetidos. Essa coleção tem seu próprio método Add que retorna um valor booleano indicando se o item foi ou não adicionado.

Enquanto não temos disponível essa coleção, podemos optar pelo uso da PowerCollections.Set, criada pela Wintellect.

Alterando a seção connectionstring do Web.Config

Muitas pessoas perguntam-me como podem estar alterando ou adicionando novas entradas dentro da seção connectionstrings do Web.Config. Basicamente você apenas precisa importar o namespace System.Web.Configuration, abrir o arquivo Web.Config onde estão as connectionstrings e alterá-las ou adicionar uma nova connectionstring. Um exemplo é algo como:

Configuration webConfig = WebConfigurationManager.OpenWebConfiguration(“~”);
ConnectionStringsSection dbConnString = webConfig.ConnectionStrings;

//Alterando
dbConnString.ConnectionStrings[“DBOrders”].ConnectionString = “TUA NOVA CONNSTRING AQUI”;

//Adicionando
dbConnString.ConnectionStrings.Add(
    new ConnectionStringSettings(“MDBTest”, “MDB ConnString”, “System.Data.OleDb”));

webConfig.Save();

Gerador de Formulários

Depois que li o último post do Alexandre Tarifa, eu lembrei de um software que um aluno meu mostrou na última aula.

Trata-se de um software chamado MM.NET (Mere Mortals .NET). Além de um nome legal, este software parece-me mágico. Existem muitas funcionalidades bem interessantes (como Templates dentro do VS.NET para Windows e Web, mapeadores, etc) e alguns detalhes que o diferem dos demais.

Eis aqui alguns videos que mostram o uso deste software.

.NET Framework 3.0

Pois é, foi o que o Soma disse neste post. Decidiram mudar o nome do novo Framework de desenvolvimento da Microsoft que terá WCF, WPF, WF entre outros, i.e. WinFX, para .NET Framework 3.0.

Apesar de gostar do nome WinFX, acredito que .NET Framework 3.0 soa melhor para quem acompanhar as versões do .NET desde seu início.

Criando um DebuggerVisualizer

A arquitetura do debugger está dividida em duas partes:

  • O debugger side corre dentro do debugger do Visual Studio .NET, podendo ser criado e exibido uma interface para seu visualizador.
  • O debuggee side corre dentro do processo que o Visual Studio .NET está depurando.

O objeto que você está querendo visualizar (uma String ou Image, por exemplo) existe dentro do processo debuggee. Logo, o debuggee side deve mandar os dados para o debugger side que, por sua vez, exibe o objeto para que o desenvolvedor possa depurar. Essa visualização é criada por nós que, ainda nesse artigo, veremos como criá-la.

O debugger side recebe o objeto que será visualizado através de um object provider, o qual implementa uma interface chamada IVisualizerObjectProvider. O debuggee side envia o objeto através de um object source, o qual deriva de uma classe chamada VisualizerObjectSource. O object provider também devolve o objeto para o object source, permitindo assim, além de exibir o objeto, editá-lo no visualizador (se assim desejar) e devolvê-lo para a aplicação. Essa comunicação é efetuada através de um objeto Stream.

Para criarmos este visualizador, primeiramente precisamos marcar a classe como sendo uma classe de DebuggerVisualizer e, para isso, é fornecido um atributo chamado DebuggerVisualizer (usado a nível de assembly ou classe) para definí-la como um visualizador. Além disso, a classe deverá obrigatoriamente herdar de uma classe abstrata chamada DialogDebuggerVisualizer e implementar o método chamado Show para customizar a visualização.

O atributo DebuggerVisualizer, contido dentro do Namespace System.Diagnostics, fornece mais alguns parâmetros para a configuração do visualizador. O primeiro parâmetro é tipo, ou seja, a classe derivada DialogDebuggerVisualizer que é o nosso visualizador efetivamente; já o segundo especifica o tipo de objeto que fará a comunicação entre o debugger side e o debuggee side e, se não informado, um default será utilizado. O restante, chamado de “Named Parameters”, você deve especificar o tipo de objeto que o visualizador irá trabalhar (uma String ou Image, por exemplo) e no outro, é o nome que aparecerá dentro do Visual Studio .NET 2005, para permitir visualização. Para ilustrar, veremos abaixo o código que cria o visualizador:

using System;
using Microsoft.VisualStudio.DebuggerVisualizers;
using System.Windows.Forms;
using System.Drawing;
using System.Diagnostics;

[
    assembly: DebuggerVisualizer(typeof(DebugTools.ImageVisualizer),
    typeof(VisualizerObjectSource),
    Target = typeof(System.Drawing.Image),
    Description = "Image Visualizer")
]
namespace DebugTools
{
    public class ImageVisualizer : DialogDebuggerVisualizer
    {
        protected override void Show(IDialogVisualizerService windowService, 
            IVisualizerObjectProvider objectProvider)
        {
            Image data = (Image)objectProvider.GetObject();

            using(ImageVisualizerForm f = new ImageVisualizerForm())
            {
                f.Image = data;
                windowService.ShowDialog(f);
            }
        }
    }
}

Note que foi criado um formulário chamado ImageVisualizerForm. Este formulário é encarregado de receber a imagem e exibí-la. Não há segredos nele, ou seja, apenas foi criada uma propriedade chamada Image que recebe a imagem vinda do object provider. O primeiro parâmetro do método Show, chamado windowService do tipo IDialogVisualizerService, fornece métodos para que o visualizador possa estar exibindo formulários, controles e janelas de diálogo.

Se você quiser que o seu visualizador edite o objeto e o devolva para a aplicação, terá que sobrescrever os métodos TransferData ou CreateReplacementObject da classe VisualizerObjectSource.

Deploy

Para que possamos utilizar o visualizador dentro do Visual Studio .NET 2005 teremos que compilar o projeto e, com a DLL gerada, colocá-la dentro do diretório <Diretorio VS.NET>Common7PackagesDebuggerVisualizers. Quando abrir o Visual Studio, já terá acesso ao visualizador, assim como é mostrado através da imagem abaixo:

Figura 1DebuggerVisualizer em funcionamento.

De String para Double

Em algumas situações, temos um determinado valor (moeda) em uma String e queremos traze-lo de volta para uma váriavel do tipo Double. Neste caso, muitos utilizam os métodos fornecidos pela classe String para manipular o valor e, depois que o(s) caracter(es) de moeda forem retirados, convertem o número que ficou para Double.

Mas para efetuar isso, há uma forma mais fácil, que é utilizando um dos overloads do método estático chamado Parse, qual se encontra dentro da estrutura Double. Um exemplo disso, é mostrado aqui:

using System.Globalization;
//….
double valor = 1256.44;
string valorString = valor.ToString(“C2”);
double novoDouble = Double.Parse(valorString, NumberStyles.Currency);

Imagem da Web em um PictureBox

Um amigo me perguntou algo interessante. Justamente por isso, resolvi postar aqui para ajudar outras pessoas: como recuperar em um controle PictureBox do Windows Forms a imagem que está em um local da Web acessível somente via HTTP. Pois bem, o .NET Framework fornece uma classe chamada WebClient que fornece algumas métodos para trabalharmos com envio e recebimento de dados através de uma URI. Para atender a necessidade dele, basta fazermos:

        Imports System.IO
        Imports System.Net

        ‘…..

        Dim ms As MemoryStream
        Try
            Dim url As String = “http://www.projetando.net/Images/Logo.gif
            Dim webClient As New WebClient
            Dim buffer As Byte() = webClient.DownloadData(url)
            ms = New MemoryStream(buffer)
            PictureBox1.Image = Image.FromStream(ms)
        Catch ex As Exception
            MessageBox.Show(ex.Message)
        Finally
            If Not IsNothing(ms) Then
                ms.Close()
            End If
        End Try

Através do método DownloadData recuperarmos a imagem e atribuímos a um buffer. Este, por sua vez, carregamos em um MemoryStream e passamos para o método compartilhado/estático da classe Image que retorna a imagem já para o controle PictureBox.

ErrorProvider

Ontem um aluno me fez um questionamento quando estava explicando sobre o controle ErrorProvider do Windows Forms. A questão é quando utilizamos o evento Validating de algum controle, como por exemplo, o TextBox, para validarmos um determinado valor, se esta condição não for atendida e, tentarmos fechar o formulário, a validação é disparada e, sendo assim, até que ela não seja atendida, o formulário não será fechado, pois o evento Validating do(s) controle(s) são disparados antes do fechamento definitivo do formulário. O código abaixo ilustra isso:

    Private Sub TextBox1_Validating(ByVal sender As Object, _
        ByVal e As System.ComponentModel.CancelEventArgs) Handles TextBox1.Validating

        If Me.TextBox1.Text = String.Empty Then
            Me.ErrorProvider1.SetError(Me.TextBox1, “Digite algo..”)
            e.Cancel = True
        End If
    End Sub

    Private Sub TextBox1_Validated(ByVal sender As Object, _
        ByVal e As System.EventArgs) Handles TextBox1.Validated

        Me.ErrorProvider1.SetError(Me.TextBox1, String.Empty)
   
End Sub

Só que o problema, como já vimos, se tentarmos fechar o formulário e o TextBox ainda estiver vazio, a validação é feita e, a propriedade Cancel é definida como True, cancelando assim a finalização do processo e o fechamento do formulário. A solução neste caso é sobrescrever o método OnClosing do Form e definir o Cancel do argumento como False, forçando assim o fechamento do formulário. Logo, precisamos apenas adicionar o seguinte trecho de código:

    Protected Overrides Sub OnClosing(ByVal e As System.ComponentModel.CancelEventArgs)
        e.Cancel = False
    End Sub

Criando uma Seção de Configuração

A finalidade deste artigo é demonstrar como fazer isso na versão 2.0 do .NET Framework. Em primeiro lugar, devemos fazer referência à DLL System.Configuration.dll no projeto. Feito isso, já passamos a ter acesso as classes específicas para isso, que estão contidas dentro deste namespace. Em segundo lugar, devemos criar uma classe que herde diretamente da classe ConfigurationSection, qual fornece as funcionalidades básicas e representa uma seção de um arquivo de configuração.

Já com a classe pronta, devemos neste momento definir as propriedades (a nível de classe) e atributos (a nível de arquivo de configuração) que essa seção terá. Através do atributo ConfigurationPropertyAttribute, marcamos as propriedades da classe que serão representadas no arquivo de configuração. É no construtor deste mesmo atributo que informaremos o nome do atributo que deverá ser definido/mapeado no arquivo de configuração. Para ilustrar o cenário, vamos criar uma seção de configuração para um serviço qualquer, chamado de ServiceConfig, onde devemos definir o path e o valor do timeout.

using System.Configuration;

public class ServiceConfig : ConfigurationSection
{
    [ConfigurationProperty("path", DefaultValue = "", IsRequired = true)]
    public string Path
    {
        get
        {
            return (string)base["path"];
        }
    }

    [
        ConfigurationProperty("timeout", DefaultValue = 50, IsRequired = false), 
        IntegerValidator(MinValue = 30)
    ]
    public int Timeout
    {
        get
        {
            return (int)base["timeout"];
        }
    }
}

Antes de seguirmos em frente, temos ainda que analisar algo importante no código acima. Repare que no atributo ConfigurationPropertyAttribute ainda temos mais algumas opções, tais como DefaultValue e IsRequired. Essa opções trabalham em conjunto, ou seja, se a propriedade IsRequired está definida como False, ou seja, o desenvolvedor não é obrigado definir este atributo no arquivo de configuração, podemos ter um valor padrão para este atributo através da propriedade DefaultValue, que é passada automaticamente para a aplicação.

Validação

Outro ponto bem interessante é a questão da validação dos atributos. Podemos validar os valores que o desenvolvedor colocar nos arquivos XML de configuração através de alguns atributos de validação, com finalidades de validações diferentes. Esses atributos herdam de uma classe base chamada ConfigurationValidatorAttribute. A validação é efetuada quando aplicamos estes atributos às propriedades da classe que representa a seção. No exemplo acima, utilizamos o atributo IntegerValidator, onde podemos definir um valor mínimo e máximo.

Como dissemos acima, os atributos de validação são vários e podem ser acessados através deste endereço. Depois de entender como criamos a classe, chega a hora de analisar como fica a configuração no arquivo *.config, já fazendo o uso desta nova seção. A solução aqui é registrar a nova seção dentro de configSettings para que a mesma possa funcionar. Para registrá-la é extremamente simples, onde devemos informar o nome e o tipo:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <section name="ServiceConfig" type="ConfigTest.ServiceConfig, ConfigTest" />
  </configSections>

  <ServiceConfig path="C:Temp" timeout="34" />
</configuration>

Depois da nova seção registrada, criamos e atribuimos os devidos valores da mesma. Vale lembrar que a validação efetuada pela atributo IntegerValidator será somente feita em runtime e, uma Exception será atirada na sua aplicação caso os valores não atendam os critérios. E para finalizar, abaixo é mostrado como recuperamos os valores do arquivo de configuração, fazendo o uso da classe que criamos anteriormente:

static void Main(string[] args)
{
    ServiceConfig srv =
        System.Configuration.ConfigurationManager.GetSection("ServiceConfig") as ServiceConfig;

    if (srv != null)
    {
        Console.WriteLine(srv.Path);
        Console.WriteLine(srv.Timeout.ToString());
    }
}