Entendendo o ciclo de vida de um Form (Windows Forms)

Neste post iremos aprender como é o ciclo de vida de um Form na plataforma descktop, ou seja Windows Forms, trabalharemos com delegates, EventHandler, objetos e eventos da classe System.ComponetModel, veremos em que momento são disparados eventos em tempo de vida de um Form como Closed, Closing, Activated, e Deactivated.

Uma breve explicação sobre o que é um “delegate”

Essencialmente um delegate é um objeto com segurança de tipo, ou seja, ele aponta para um método ou possivelmente uma lista de métodos, na aplicação, e que pode ser chamado no futuro, especificadamente um objeto delegate mantem três informações importantes:

O endereço do método no qual ele faz a chamada.
Os argumentos, se houver deste método.
O valor de retorno, se houver deste método.

Observação: Os delegates na plataforma .NET pode apontar para métodos estáticos e instancias.

Um delegate em .NET possui a capacidade de chamar método de maneira sincronizada ou assíncrona. Este fato simplifica e muito as tarefas de programação, já que podemos chamar um método de uma cadeia de execução dentro de nossa aplicação (Thread = Cadeia). Breve estarei publicando um post neste blog abrangendo mais a fundo o termo delegate e thread.

Criando a Aplicação para ver o ciclo de vida do Form

Se você programou interfaces de usuário utilizando o kit de ferramentas GUI, como Java Swing, Mac OS-X, ou API bruta Win32, você esta ciente que tipos “tipo janelas” possuem uma quantidade de eventos que disparam durante seu tempo de vida. O mesmo acontece com Windows Form. Como você viu a vida útil de um formulário começa quando o construtor de tipo é chamando antes de ser passado ao método Application.Run().  Assim que o objeto é alocado na Heap gerenciado, o framework dispara o evento Load. Dentro de um manipulador de evento Load, você é livre para configurar a aparência e funcionalidade do Form, preparar quaisquer controles filhos contidos (como ListBox, Treeviews e qualquer outro), ou simplesmente alocar recursos utilizados durante a operação Form, (conexões de banco, proxys para objetos remotos como Client-Server).

Uma vez disparado o evento Load, o próximo evento a ser disparado é o Activated (Ativado), esse evento será ativado quando o formulário receber o foco com a janela ativa na área de trabalho. A parte contraria digamos assim desse evento é o Deactivate (Desativado) que disparara varias vezes pelo tempo de vida de um Form qualquer, assim que o usuário navegar entre os aplicativos ativos. Suponha que o usuário escolheu fechar o formulário em questão, dois disparos em eventos focados em fechar: Closing e Closed. O evento Closing é disparado primeiro e é um lugar ideal para mostrar ao usuário final uma mensagem muito odiada (mas util): Voce tem certeza que deseja fechar este aplicativo. Esse passo adaptável é extremamente útil para assegurar que o usuário tenha uma chance de salvar quaisquer dados focados em aplicativo, antes de terminar o programa.

O evento Closing funciona como um delegado CancelEventHandler definido no namespace System.ComponetModel. Se você ajustar a propriedade CancelEventArgs.Cancel para true, você evitara que a janela seja destruída e a instruirá para retornar para a operação normal. Se você ajustar o CancelEventArgs.Cancel para false, o evento Closed disparará, o aplicativos Windows Form descarregara o AppDomain e p processo terminara. Para solidificar a sequencia de eventos que tomam lugar durante o tempo de vida do formulário, suponha que você tenha um novo projeto Windows Form chamando FormLifeTime e tenha renomeado o formulário inicial para MainWindow.cs (Através do Solution Explorer) agora dentro do seu construtor de formulário manipule o evento Load,

Activated
Deactivate
Closing
Closed

Observação: Para gerar automático o evento do delegado correto basta pressionar TAB duas vezes depois digitar +=

public MainWindow()
 {
 InitializeComponent();
// Delegados apontados para os Eventos do Formulario
 Closing += new CancelEventHandler(MainWindow_FormClosing);
 Load += new EventHandler(MainWindow_Load);
 Closed += new EventHandler(MainWindow_FormClosed);
 Activated += new EventHandler(MainWindow_Activated);
 Deactivate += new EventHandler(MainWindow_Deactivate);
 }

Dentro dos manipuladores de eventos Load, Closed, Activated, Deactivated, você estará atualizando o valor de uma nova variável membro string de nível de Form, que acaba de ser interceptada. Assim note que dentro do manipulador de evento Closed, você mostrara o valor dessa string dentro de uma caixa de mensagem:

// Evento ao carregar formulario
private void MainWindow_Load(object sender, EventArgs e)
{
lifeTimeInfo += ">>> Carregando \n";
}

// Evento quando o formulario é ativo
private void MainWindow_Activated(object sender, EventArgs e)
{
lifeTimeInfo += ">>> Ativado \n";
}

// Evento quando o formulario é desativado
private void MainWindow_Deactivate(object sender, EventArgs e)
{
lifeTimeInfo += ">>> Desativado \n";
}

// Evento quando o formulario é fechado
private void MainWindow_FormClosed(object sender, EventArgs e)
{
lifeTimeInfo += ">>> Fechado \n";
MessageBox.Show(lifeTimeInfo);
}

Dentro do manipulador de evento Closing, você induzira o usuário para assegurar que ele ou ela terminem o aplicativo utilizando o CancelEventArgs de chagada. No código seguinte, note que o método MessageBox.Show() retornará um tipo DialogResult, que contem um valor que representa qual o botão oi selecionado pelo usuário final. Dessa forma, produziremos  uma caixa de mensagem que mostrara Yes (Sim) e No (Não)  então, estamos interessados em descobri r se o valor de retorno de Show() será DialogResult.No.

// Evento quando o formulario esta sendo fechado ele é chamando antes do evento Closed
private void MainWindow_FormClosing(object sender, CancelEventArgs e)
{
lifeTimeInfo += "Fechando \n";
DialogResult dr = MessageBox.Show(this, "Você deseja realmente fechar esta janela", "Evento Fechando (Closing) deste Form", MessageBoxButtons.YesNo, MessageBoxIcon.Information);

// Qual dos Botoes foi clicado ?
if (dr == DialogResult.No)
e.Cancel = true;
else
e.Cancel = false;
}

Agora rode o aplicativo e mova o formulário para fora de foco algumas vezes (não dispare os eventos Activated e Deactivated). Uma vez desligado o aplicativo você vera uma caixa de mensagem que se parece como a figura a baixo:

Espero que tenham entendido os eventos em tempo de vida de um Form ou seja quando ele esta ativo na area de trabalho do usuario, varias coisas podem acontecer ao ativar, inativar, fechar um form, minimizar etc.

Abraços.
Até o próximo post.

Documentando seu Código Fonte em C# (Csharp) no Visual Studio 2008

Este post terá a finalidade de mostrar como documentar funções, métodos, atributos de uma classe em nosso dia-a-dia de desenvolvimento de software, utilizando os recursos do Visual Studio 2008. Quando desejar documentar seus tipos C# no Visual Studio 2008, seu primeiro passo é utilizar a nova notação de comentário de código com três barras “///”. Uma vez que um comentário da documentação tenha sido declarado, você tem liberdade para utilizar quaisquer elementos XML bem formados, inclusive o conjunto recomendado mostrado a baixo:

Elementos Pre-Definidos de Documento XML  e suas descrições

<c> – Indica que o texto a seguir deve ser uma “fonte de código” especificada.
<code> -Indica que varias linhas devem ser marcadas como código.
<exemple> – Cria um exemplo de código para o item que esta sendo descrito.
<exception> – Documenta quais exceções uma determinada classe pode gerar.
<list> – Insere uma lista ou tabela ao arquivo de documentação.
<param> – Descreve um determinando parâmetro.
<paramref> – Associa uma terminada Tag XML com um parâmetro especificado.
<permission> – Documenta os limites de segurança para um determinado membro.
<remarks> – Constrói uma descrição para um determinado membro.
<returns> – Documenta o valor de retorno do membro.
<see> – Faz referencia cruzada aos itens do documento.
<seealso> – Constrói uma seção “See Also” ou “Veja Também” em uma descrição.
<summary> – Documenta o “Resumo Executivo” para um determinado membro.
<values> – Documenta uma determinada propriedade.

Exemplo sem passagem de parâmetro e sem retorno

/// &amp;lt;summary&amp;gt;
/// Abre a Conexao com o banco de dados ou exibe o erro caso a base esteja
/// inconsistente
/// &amp;lt;/summary&amp;gt;
private static void abreConexao()
{
    try
    {
       conn.Open(); //Abre a conexão com BD
    }
    catch (Exception e)
    {
       throw new Exception(&amp;quot;Erro ao abrir a conexão: &amp;quot; + e.Message);
    }
}

Exemplo com passagem de parâmetros e com retorno do membro

/// &amp;lt;summary&amp;gt;
/// Executa uma query SELECT considerando os parâmetros (SqlParameter)
/// &amp;lt;/summary&amp;gt;
/// &amp;lt;param name=&amp;quot;query&amp;quot;&amp;gt;Query a ser executado no banco de dados&amp;lt;/param&amp;gt;
/// &amp;lt;param name=&amp;quot;parameters&amp;quot;&amp;gt;Parâmetros da query (Ex. &amp;quot;@cod, @num, @nome&amp;quot;) etc.&amp;lt;/param&amp;gt;
/// &amp;lt;returns&amp;gt;Retorna o DataSet da query executada&amp;lt;/returns&amp;gt;
public static DataSet seleciona(string query, params SqlParameter[] parameters)
{
    try
    {
        DataSet ds = new DataSet();
        abreConexao();

        SqlCommand cmd = new SqlCommand(query, conn);
        foreach (SqlParameter param in parameters)
        cmd.Parameters.Add(param);
        SqlDataAdapter da = new SqlDataAdapter(cmd);
        da.Fill(ds); //Preenche DataSet
        cmd.Parameters.Clear();
        return ds;  //Retorna o DataSet já contendo os dados
    }
    catch (Exception e)
    {
        throw new Exception(&amp;quot;Erro ao selecionar query &amp;quot; + query + &amp;quot;\n&amp;quot; + e.Message);
    }
    finally
    {
        fechaConexao();
    }
}

Bom esse post foi bem simples, com a finalidade de mostrar os recursos disponíveis pelo Visual Studio 2008 para documentação de código, para quem é desenvolvedor, vale uma dica, se atente em documentar pela tabela acima mostrada neste post, fica mais organizado e profissional.

Abraços até a próxima.

Entendendo e utilizando construtores de classes em C# (CSharp)

1º O papel do construtor padrão

Cada classe em C# é fornecida com um construtor padrão gratuito, que pode ser redefinido se for necessário. Por definição, um construtor padrão nunca aceita argumentos. Além de alocar o novo objeto na memoria, o construtor padrão garante que todos os dados de campos configurados, para um calor padrão adequado. Se não estiver satisfeito com estas atribuições padrão, pode redefinir o construtor padrão de acordo com suas necessidades. Para ilustrar veja a classe abaixo:

class Carro
{
    public string Nome;
    public int VelocidadeCorrente;

    public Carro()
    {
        Nome = &amp;amp;quot;GOLF GTI 1.8&amp;amp;quot;;
        VelocidadeCorrente = &amp;amp;quot;60&amp;amp;quot;;
    }
}

Neste caso estamos forçando todos os objetos Carro a começar sua vida com o nome “GOLF GTI 1.8”, com a velocidade corrente de 60 km. Assim consegue criar um objeto Carro configurado para os seguintes valores padrão:

static void Main(string[] args)
{
    // Chamando o construtor padrao
    Carro CarroA = new Carro();

    // Imprimi a velocidade corrente de 60 km/h
    Console.Write(CarroA.VelocidadeCorrente);
}

2º Definindo construtores padrão

Tipicamente as classes definem construtores adicionais além do padrão. Ao fazer isso, você oferece ao usuário do objeto uma maneira simples e consistente para inicializar o estado de um objeto diretamente no momento da criação. Considere a seguinte atualização da classe “Carro” que agora ira suportar um total de três construtores de classe:

class Carro
{
    public string Nome;
    public int VelocidadeCorrente;

    // Construtor padrao personalizado
    public Carro()
    {
        Nome = &amp;amp;quot;GOLF GTI 1.8&amp;amp;quot;;
        VelocidadeCorrente = &amp;amp;quot;60&amp;amp;quot;;
    }

    // Aqui a VelocidadeCorrente recebera por padrao (zero)
    public Carro(string vNome)
    {
        Nome = vNome;
    }

    // Deixar que o chamandor configure o 'estado' completo do objeto Carro
    public Carro(string vNome, string vVelocidadeCorrente)
    {
        Nome = vNome;
        VelocidadeCorrente = vVelocidadeCorrente;
    }
}

Tenha em mente que o que diferencia um construtor do outro (aos olhos do compilador C#) é o numero e o tipo de argumentos do construtor. Portanto, o tipo “Carro” sobrecarregou o construtor para fornecer diversas maneiras de criar o objeto no momento da declaração. Seja qual for o caso, agora pode criar objetos “Carro” utilizando qualquer um dos construtores públicos. Por exemplo:

// Criar um carro Escort XR3
static void Main(string[] args)
{
    Carro CarroA = new Carro(&amp;amp;quot;ESCORT XR3&amp;amp;quot;);
}

// Criar um carro Escort XR3 com velocidade corrente de 90 km/h
static void Main(string[] args)
{
    Carro CarroA = new Carro(&amp;amp;quot;ESCORT XR3&amp;amp;quot;, &amp;amp;quot;90&amp;amp;quot;);
}

3º Recusando o construtor padrão

No entanto, assim que define um construtor personalizado, o construtor padrão é silenciosamente removido da classe e não esta mais disponível! Pense desta forma: se não definir um construtor personalizado, o compilador C# fornecera um padrão para permitir que o usuário do objeto aloque uma instancia de seu tipo com dados de campo para valores padrão corretos. Entretanto quando define um construtor exclusivo, o compilador supõe que lidou com as coisas a sua maneira.

Portanto, se deseja permitir que o usuário do objeto, crie uma instancia de seu tipo com o construtor padrão, bem como seu construtor personalizado, você deve, explicitamente, redefinir o construtor padrão. Para isso, compreenda que uma grande maioria dos casos, a implementação do construtor padrão de uma classe é intencionalmente vazia, já que tudo o que precisa é a capacidade é criar um objeto com valores padrão. Considere a seguinte atualização da classe “Carro”:

class Carro
{
    public int Intencidade;

    public void Aceleracao()
    {
        for (int i = 0; i &amp;amp;lt;= Intencidade; i++)
        {
            Console.Write(&amp;amp;quot;Yahoooooo Haaaaaewwwwww&amp;amp;quot;);
        }
    }

    // Recusar o construtor padrao
    public Carro()
    {

    }

    // Nosso construtor padrao agora!
    public Carro(int vIntencidade)
    {
        this.Intencidade = vIntencidade;
    }
}

Bom, finalizando esse foi mais um post sobre Construtores de Classe em C# (Csharp), espero que tenham gostado, pois lendo ele parece ser uma coisa ate simples, mas no dia-a-dia de um desenvolvedor de sistemas, nos deparamos como modificar um objeto a nosso favor em fim.

Ate à próxima!