Infelizmente ao postar a última entrada desta série (Oque esta errado com este código?) não inclui um número. Assim sendo, vou atribuir o valor X para o mesmo.
Com relação ao post referido, o problema esta relacionado ao acesso de propriedades de controles da UI em uma thread diferente daquela que o componente.
Observe novamente o código abaixo:
Created with colorer-take5 library. Type 'csharp'
0: using System;
1: using System.Windows.Forms;
2: using System.Threading;
3:
4: namespace TestWinForm
5: {
6: public partial class TestCallBackFromDiferentThread : Form
7: {
8: private System.Threading.Thread workerThread;
9:
10: public TestCallBackFromDiferentThread()
11: {
12: InitializeComponent();
13: }
14:
15: private void button1_Click(object sender, EventArgs e)
16: {
17: ThreadStart ts = new ThreadStart(AddNewLine);
18: workerThread = new Thread(ts);
19: workerThread.Start();
20: }
21:
22: private void AddNewLine()
23: {
24: listBox1.Items.Add(textBox1.Text);
25: }
26: }
27: }
Nas linhas # 17 ~ 19 criamos uma thread e iniciamos a execução da mesma; esta thread chama a função AddNewLine() que por sua vez tenta incluir um item em uma listbox.
O problema (como explicado aqui) é que o acesso a controles em WinForms não são thread safe automaticamente, ou seja, se duas threads modificarem o estado de um controle simultaneamente o mesmo pode ficar em um estado inconsistente ou mesmo gerar exceções (oque seria melhor que a primeira possibilidade).
Crie uma aplicação WinForm, adicionar os controles listbox, textbox e um botão e copie o código acima para o formulário da aplicação.
Se você executar esta aplicação a partir do explorer pode lhe parecer que a mesma não possui problema nenhum; ou seja, aparentemente a mesma funcionou.
Contudo execute a mesma a partir do Visual Studio; se a opção "enable exception assistence" estiver habilitada uma exceção será gerada quando a thread tentar acessar o listbox na linha 24.
Ok, e como solucionar o problema? Simples, usando a propriedade InvokeRequerid do controle...
No método AddNewLine(), antes de incluir o item no listbox consulte a propriedade InvokeRequired; se a mesma for true então execute o método Invoke() passando um delegate que irá executar o mesmo método (AddNewLine()).
Veja no exemplo abaixo:
Created with colorer-take5 library. Type 'csharp'
using System;
using System.Windows.Forms;
using System.Threading;
namespace TestWinForm
{
public partial class TestCallBackFromDiferentThread : Form
{
private System.Threading.Thread workerThread;
public TestCallBackFromDiferentThread()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
ThreadStart ts = new ThreadStart(AddNewLine);
workerThread = new Thread(ts);
workerThread.Start();
}
private void AddNewLine()
{
if (listBox1.InvokeRequired)
{
listbox1.Invoke(new MethodInvoker(AddNewLine));
}
else
{
listBox1.Items.Add(textBox1.Text);
}
}
}
}
Você pode encontrar mais informações (em inglês) sobre o assunto aqui.
A partir do próximo post irei iniciar uma série onde em cada post falarei sobre um aplicativo/site que uso com frequência e que acho interessante. Fique atento.
Adriano
