Alguém pode explicar esta declaração escrita neste link
Invoke(Delegate):
Executa o delegado especificado no thread que possui o identificador de janela subjacente do controle.
Alguém pode explicar o que isso significa (especialmente o ousado)? Não sou capaz de entender claramente
Respostas:
A resposta a esta pergunta está em como funcionam os controles C #
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.
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
e, para uma visão geral mais pesada do código com uma amostra representativa:
Operações Cruzadas Inválidas
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.
fonte
Um controle ou objeto de janela no Windows Forms é apenas um invólucro em torno de uma janela Win32 identificada por um identificador (às vezes chamado de HWND). A maioria das coisas que você faz com o controle eventualmente resultará em uma chamada de API do Win32 que usa esse identificador. O identificador pertence ao segmento que o criou (normalmente o segmento principal) e não deve ser manipulado por outro segmento. Se, por algum motivo, você precisar fazer algo com o controle de outro encadeamento, pode usar
Invoke
para pedir ao encadeamento principal para fazer isso em seu nome.Por exemplo, se você deseja alterar o texto de um rótulo de um thread de trabalho, pode fazer algo assim:
fonte
this.Invoke(() => this.Enabled = true);
O que quer quethis
se refira está certamente no tópico atual, certo?Se você deseja modificar um controle, isso deve ser feito no thread em que o controle foi criado. Este
Invoke
método permite executar métodos no thread associado (o thread que possui o identificador de janela subjacente do controle).No exemplo abaixo, thread1 lança uma exceção porque SetText1 está tentando modificar textBox1.Text de outro thread. Mas no thread2, a ação em SetText2 é executada no thread em que o TextBox foi criado
fonte
fonte
Em termos práticos, isso significa que o delegado tem garantia de ser invocado no encadeamento principal. Isso é importante porque, no caso de controles do Windows, se você não atualizar suas propriedades no thread principal, não verá a alteração ou o controle gerará uma exceção.
O padrão é:
fonte
this.Invoke(delegate)
certifique-se de que você está chamando o delegado do argumento parathis.Invoke()
no thread principal / thread criado.Posso dizer que uma regra Thumb não acessa os controles do formulário, exceto a partir do thread principal.
Pode ser que as seguintes linhas façam sentido para usar Invoke ()
Há situações em que você cria um thread Threadpool (isto é, thread de trabalho), ele será executado no thread principal. Ele não criará um novo thread porque o thread principal está disponível para processar instruções adicionais. Portanto, primeiro investigue se o thread em execução atual é o thread principal usando
this.InvokeRequired
se retorna true, o código atual está sendo executado no thread de trabalho, então chame this.Invoke (d, new object [] {text});caso contrário, atualize diretamente o controle da IU (aqui você tem a garantia de que está executando o código no thread principal).
fonte
Isso significa que o delegado será executado no thread de interface do usuário, mesmo se você chamar esse método de um trabalhador em segundo plano ou thread de pool de threads. Os elementos da IU têm afinidade de thread - eles só gostam de falar diretamente com uma thread: a IU thread. O thread da IU é definido como o thread que criou a instância de controle e, portanto, está associado ao identificador da janela. Mas tudo isso é um detalhe de implementação.
O ponto principal é: você chamaria esse método de um thread de trabalho para que pudesse acessar a IU (para alterar o valor em um rótulo, etc) - já que você não tem permissão para fazer isso a partir de qualquer outro thread que não seja o thread de IU.
fonte
Delegado são essencialmente em linha
Action
's ouFunc<T>
. Você pode declarar um delegado fora do escopo de um método que você está executando ou usando umalambda
expressão (=>
); porque você executa o delegado dentro de um método, você o executa no encadeamento que está sendo executado para a janela / aplicativo atual, que está em negrito.Exemplo lambda
fonte
Isso significa que o delegado que você passa é executado no thread que criou o objeto Control (que é o thread de IU).
Você precisa chamar este método quando seu aplicativo é multi-threaded e você deseja fazer alguma operação de IU a partir de um thread diferente do UI thread, porque se você apenas tentar chamar um método em um Control de um thread diferente, você obterá um System.InvalidOperationException.
fonte