Windows Forms – atualizando o formulário de dentro de uma Thread

É relativamente comum termos uma aplicação que precise usar uma ou mais threads para realizar algum processo demorado onde o usuário não precise ficar esperando, mas às vezes é necessário também que esta thread faça algum tipo de interação com a tela, talvez atualizando alguma informação, barra de progresso, enfim, mostrar ao usuário que algo está acontecendo.

Uma tarefa relativamente simples, mas que pode causar um certo transtorno justamente por ser uma thread. Veja a aplicação abaixo em Windows Forms:

image

É uma tela bem simples, com um botão e uma barra de progresso. Agora vamos imaginar que este form tenha o código abaixo, que cria uma thread que atualiza a progressBar1:

   1: public partial class Form1 : Form

   2: {

   3:     private bool threadAtiva = false;

   4:  

   5:     public Form1()

   6:     {

   7:         InitializeComponent();

   8:     }

   9:  

  10:     private void btnIniciar_Click(object sender, EventArgs e)

  11:     {

  12:         

  13:         Thread processo = new Thread(new ThreadStart(ExecutaThread));

  14:         processo.Start();

  15:  

  16:         progressBar1.Maximum = 100;

  17:         progressBar1.Value = 0;

  18:  

  19:         threadAtiva = true;

  20:     }

  21:  

  22:     void ExecutaThread()

  23:     {

  24:         while (threadAtiva)

  25:         {

  26:             if (progressBar1.Value > 99)

  27:             {

  28:                 threadAtiva = false;

  29:                 return;

  30:             }

  31:             progressBar1.Value++;

  32:             progressBar1.Refresh();

  33:         }

  34:     }

  35: }


O código acima está correto, mas ao executar e clicar no botão iniciar, aparece o seguinte erro:

image

O erro acontece porquê a janela da aplicacação (UI) está executando em uma thread e agora nós temos outra thread executando o nosso processo e tentando atualizar a tela. Então como resolver isto ?

Simplesmente usando um Invoker:

   1: void ExecutaThread()

   2:        {

   3:            while (threadAtiva)

   4:            {

   5:                if (progressBar1.Value > 99)

   6:                {

   7:                    threadAtiva = false;

   8:                    return;

   9:                }

  10:                this.Invoke(new MethodInvoker(delegate()

  11:                {

  12:                    progressBar1.Value++;

  13:                    progressBar1.Refresh();

  14:                }));

  15:            }

  16:        }

Agora estamos atualizando a tela ou seja, o progressBar1 usando um Invoker que está sendo executando sob a thread principal, ou seja, o formulário. Neste exemplo eu usei o MethodInvoker() com um método anônimo, mas você poderia ter criado um método e chamado sem problemas e com isto você pode ter várias thread rodando e atualizando a interface do usuário.

É isto aí pessoal, espero que dica seja útil para vocês.

Um abraço e até a próxima.

Carlos dos Santos.

2 Comments


  1. Carlos, bom dia!

    Como ficaria o código de exemplo se a chamada fosse efetua a um método? Por exemplo: atualizaProgressBar().
    Se o método recebesse dois parâmetros, como ficaria? Por exemplo: atualizaProgressBar(int valor, bool refresh).

    Desde já agradeço,
    Alexandre Brandão
    abrandao.net@bol.com.br

    Reply

  2. Alexandre,

    Neste caso a maneira mais simples é usar uma classe como parâmetro:
    namespace ConsoleApplication24
    {
    class Program
    {
    static void Main(string[] args)
    {

    Parametro _parametro = new Parametro();
    _parametro.valor = 10;
    _parametro.refresh = true;

    Thread _thread = new Thread(new ParameterizedThreadStart(ExecutaThread));
    _thread.Start(_parametro);
    }

    static void ExecutaThread(object parametro)
    {
    Parametro par = (Parametro)parametro;

    }
    }

    public class Parametro
    {
    public int valor;
    public bool refresh;
    }
    }

    []s,
    Carlos.

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *

Anti-spam: complete the taskWordPress CAPTCHA


This blog is kept spam free by WP-SpamFree.