A resposta a esta pergunta está em como funcionam os controles C #
Os controles no Windows Forms são vinculados a um thread específico e não são seguros para thread. Portanto, se você estiver chamando o método de um controle de um thread diferente, você deve usar um dos métodos invoke do controle para empacotar a chamada para o thread adequado. Esta propriedade pode ser usada para determinar se você deve chamar um método invoke, o que pode ser útil se você não souber qual thread possui um controle.
De Control.InvokeRequired
Efetivamente, o que Invoke faz é garantir que o código que você está chamando ocorra no encadeamento em que o controle "vive", evitando efetivamente exceções de encadeamento cruzado.
De uma perspectiva histórica, em .Net 1.1, isso era realmente permitido. O que significava é que você poderia tentar e executar o código no thread "GUI" de qualquer thread em segundo plano e isso funcionaria na maioria das vezes. Às vezes, isso apenas faria com que seu aplicativo fechasse porque você estava interrompendo efetivamente o thread da GUI enquanto ele fazia outra coisa. Esta é a exceção Cross Threaded - imagine tentar atualizar um TextBox enquanto a GUI está pintando outra coisa.
- Qual ação tem prioridade?
- É mesmo possível que ambos aconteçam ao mesmo tempo?
- O que acontece com todos os outros comandos de que a GUI precisa para ser executada?
Na verdade, você está interrompendo uma fila, o que pode ter muitas consequências imprevistas. Invoke é efetivamente a maneira "educada" de colocar o que você deseja fazer na fila, e essa regra foi aplicada a partir do .Net 2.0 por meio de uma InvalidOperationException lançada .
Para entender o que realmente está acontecendo nos bastidores e o que se entende por "Thread da GUI", é útil entender o que é um Message Pump ou Message Loop.
Na verdade, isso já foi respondido na pergunta " O que é uma bomba de mensagem " e é uma leitura recomendada para entender o mecanismo real que você está conectando ao interagir com os controles.
Outras leituras que você pode achar úteis incluem:
O que há com Begin Invoke
Uma das regras principais da programação de GUI do Windows é que apenas o thread que criou um controle pode acessar e / ou modificar seu conteúdo (exceto para algumas exceções documentadas). Tente fazer isso a partir de qualquer outro thread e você obterá um comportamento imprevisível que varia de impasse a exceções a uma interface do usuário parcialmente atualizada. A maneira certa de atualizar um controle de outro encadeamento é postar uma mensagem apropriada na fila de mensagens do aplicativo. Quando a bomba de mensagem começar a executar aquela mensagem, o controle será atualizado, no mesmo thread que o criou (lembre-se, a bomba de mensagem roda no thread principal).
e, para uma visão geral mais pesada do código com uma amostra representativa:
Operações Cruzadas Inválidas
// the canonical form (C# consumer)
public delegate void ControlStringConsumer(Control control, string text); // defines a delegate type
public void SetText(Control control, string text) {
if (control.InvokeRequired) {
control.Invoke(new ControlStringConsumer(SetText), new object[]{control, text}); // invoking itself
} else {
control.Text=text; // the "functional part", executing only on the main thread
}
}
Depois de apreciar InvokeRequired, você pode considerar o uso de um método de extensão para encerrar essas chamadas. Isso é habilmente abordado na questão Stack Overflow, Limpando o código cheio de invocação necessária .
Há também um outro relato do que aconteceu historicamente que pode ser de interesse.