Como eu Rendimento para o segmento de interface do usuário para atualizar a interface do usuário ao fazer o processamento em lote em um aplicativo WinForm?

StackOverflow https://stackoverflow.com/questions/106036

  •  01-07-2019
  •  | 
  •  

Pergunta

Eu tenho um WinForms aplicativo escrito em C # com .NET 3.5. Corre-se um processo em lote demorado. Eu quero que o aplicativo para atualizar o status do que o processo em lote está fazendo. Qual é a melhor maneira de atualizar a interface do usuário?

Foi útil?

Solução

Os sons BackgroundWorker como o objeto que deseja.

Outras dicas

A maneira rápida e suja está usando Application.DoEvents() Mas isto pode causar problemas com os acontecimentos de ordem são manipulados. Portanto, não é recomendado

O problema é provavelmente não que você tem que produzir para o segmento ui, mas que você fazer o processamento no segmento ui impedindo-o de manipulação de mensagens. Você pode usar o componente BackgroundWorker para fazer o processamento em lote em um segmento diferente, sem bloquear o segmento interface do usuário.

Execute o processo demorado em uma discussão de fundo. A classe de trabalho de fundo é uma maneira fácil de fazer isso - ele fornece suporte simples para o envio de atualizações de progresso e eventos de conclusão para que os manipuladores de eventos são chamados no thread correto para você. Isso mantém o código limpo e conciso.

Para exibir as atualizações, barras de progresso ou texto barra de estado são dois dos mais comuns se aproxima.

A principal coisa a lembrar é que se você está fazendo as coisas em uma discussão de fundo, você deve mudar para o segmento interface do usuário, a fim de controles do Windows Update etc.

Para reforçar o que as pessoas estão dizendo sobre DoEvents, aqui está uma descrição do que pode acontecer.

Digamos que você tenha alguma forma com dados sobre ele e seu evento de longa duração está salvando-o para o banco de dados ou gerar um relatório com base nele. Você começar a poupar ou gerar o relatório e, em seguida, periodicamente, você chamar DoEvents para que a tela continua pintando.

Infelizmente, a tela não é apenas a pintura, ele irá também reagem às ações do usuário. Isso ocorre porque DoEvents pára o que está fazendo agora para processar todas as mensagens do Windows à espera de ser processado por seu aplicativo WinForms. Essas mensagens incluem pedidos para redesenhar, bem como qualquer digitação do usuário, clicando, etc.

Assim, por exemplo, enquanto você está salvando os dados, o usuário pode fazer coisas como fazer o aplicativo mostrará uma caixa de diálogo modal que é completamente alheios à tarefa de longa duração (por exemplo Ajuda-> Sobre). Agora você está reagindo a novas ações do usuário dentro o já em execução tarefa longa em execução. DoEvents voltará quando todos os eventos que estavam à espera quando você chamou de terminar, e depois a sua tarefa de longa duração vai continuar.

E se o usuário não fechar o diálogo modal? Sua tarefa longa duração espera para sempre, até que este diálogo é fechada. Se você está comprometendo-se a um banco de dados e segurando uma transação, agora você está segurando uma transação aberta enquanto o usuário está tendo um café. Ou seus tempos de transação e você perder o seu trabalho persistência, ou a transação não tempo fora e você potencialmente impasse outros usuários do DB.

O que está acontecendo aqui é que Application.DoEvents faz sua reentrada código. Veja a definição wikipedia aqui . Observe alguns pontos do topo do artigo, que para o código para ser reentrante,-lo:

  • Ser titular não estático (ou global) dados não-constante.
  • Deve funcionar apenas nos dados fornecidos a ele pelo chamador.
  • não deve contar com bloqueios para recursos únicos.
  • Não deve chamar programas de computador não-reentrantes ou rotinas.

É muito improvável que a longa execução de código em um aplicativo WinForms está trabalhando apenas em dados passados ??para o método pelo chamador, não detém dados estáticos, mantém nenhum bloqueio, e apenas chamadas de outros métodos de reentrada.

Como muitas pessoas aqui estão dizendo, DoEvents pode levar a algumas situações muito estranhas no código. Os erros que podem levar à pode ser muito difícil de diagnosticar, e o usuário não é susceptível de lhe dizer "Oh, isso pode ter acontecido porque eu clicado esse botão não relacionado, enquanto eu estava esperando por ele para salvar".

Use o componente backgroundworker para executar o seu processamento em lote em um segmento separado, Este, então, não impacto sobre o segmento.

Quero reafirmar o que meus comentadores anteriores observou: DoEvents Evitar por favor () sempre que possível, como este é quase sempre uma forma de "hack" e provoca pesadelos de manutenção

.

Se você vai a estrada BackgroundWorker (que eu sugiro), você vai ter que lidar com chamadas cruzadas-threading para a interface do usuário, se você quiser chamar quaisquer métodos ou propriedades de controles, como estes são thread-afim e deve ser chamado apenas do segmento foram criados por diante. Use Control.Invoke () e / ou Control.BeginInvoke () conforme o caso.

Se você estiver executando em um segmento de segundo plano / trabalhador, você pode chamar Control.Invoke em um de seus controles de interface do usuário para executar um delegado no segmento.

Control.Invoke é síncrona (espera até que o delegado retornos). Se você não quiser esperar você usa .BeginInvoke() para a fila apenas o comando.

O returnvalue de .BeginInvoke() permite verificar se o método concluído ou esperar até que ele completou.

Use Backgroundworker, e se você também está tentando atualizar o segmento GUI por manipular o evento ProgressChanged (como, por um ProgressBar), certifique-se também WorkerReportsProgress=true set, ou o fio que está relatando o progresso vai morrer pela primeira vez, tenta chamar ReportProgress ...

uma exceção é lançada, mas você não pode vê-lo a menos que você tem 'quando jogado' ativada e a saída vai apenas mostrar que o segmento saiu.

Application.DoEvents () ou possivelmente executar o lote em um segmento separado?

DoEvents () era o que eu estava procurando, mas eu também votou-se as respostas BackgroundWorker porque que parece uma boa solução que vou investigar um pouco mais.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top