Atualizações WinForm sobre tarefas de longa execução
-
21-09-2019 - |
Pergunta
Você tem uma boa solução para manter um 'por favor, aguarde' winform 'pintado' enquanto um aplicativo está executando uma tarefa de longa execução?
Eu tentei usar o form.Refresh () em cada etapa, mas existem algumas consultas longas que ocorrem, o que significa que isso não é frequente o suficiente.
Basicamente, isso Então pergunta Mas, em C# no Excel através do Vsto (em vez de Python).
Solução
Aqui está um bom exemplo com código em C#.
É para telas de respingos especificamente, no entanto, é um processo quase idêntico (talvez menos parte da opacidade chamativa) criar uma janela de espera.
A principal informação é que você precisará de um encadeamento separado. Isso pode complicar as coisas, no entanto, o artigo fornece uma boa cobertura/exemplo de como fazê -lo corretamente.
Outras dicas
Como Statichippo mencionou, eu usaria a classe BackgroundWorker. Seu objetivo é simplificar o multi-threading e permitir que um thread de trabalhador consumisse o processamento que consome tempo sem travar a GUI.
Aqui está uma citação de Msdn:
A classe BackgroundWorker permite executar uma operação em um encadeamento separado e dedicado. Operações demoradas, como downloads e transações de banco de dados, podem fazer com que a interface do usuário (UI) pareça que parou de responder enquanto estiver em execução. Quando você deseja uma interface do usuário responsiva e se depara com longos atrasos associados a essas operações, a classe BackgroundWorker fornece uma solução conveniente.
Aqui está um bom tutorial sobre como usar a classe BackgroundWorker nos formulários do Windows: Implementando multi-threading em winforms usando a classe BackgroundWorker
Existem maneiras mais complicadas de implementar multi-threading em c# para cenários complexos, mas para a maioria dos cenários simples, o trabalho de fundo funciona muito bem (pelo menos para mim).
Aqui estão alguns links que retirei do Google no C# Multi Threading:
MSDN Threading
Introdução ao multithreading em C#
Outra opção é usar um delegado assíncrono para mostrar o formulário em um encadeamento Threadpool.
Os threads no Threadpool são recomendados para threads de vida mais curtos que não duram toda a duração do aplicativo. Como isso é para exibir uma janela de vida curta, aguarde, o Threadpool é uma opção razoável.
O delegado de ação (.NET 2.0+) é usado junto com o método BegininVoke () para executar automaticamente o código delegado em um encadeamento Threadpool.
Algumas notas:
- É importante usar o Control.BegininVoke para qualquer chamada GUI da Cross Thread, como fechar o formulário Aguarde em ClosePleasewait ().
- Também o
m_pleaseWaitForm.ShowDialog();
Na verdade, inicia um novo loop de mensagem no novo thread. É isso que mantém o formulário de espera por favor. - Como um encadeamento ThreadPool é usado, este thread é automaticamente um encadeamento em segundo plano e será encerrado se o aplicativo principal for fechado.
- Além de correr em outro tópico, não há nada de especial no Form2. Você pode colocar quaisquer controles infantis, como caixas de imagem, etiquetas etc.
(MethodInvoker)delegate { ... }
é apenas uma maneira .NET 2.0 de executar o código em um delegado embutido.
O exemplo abaixo pode ser adicionado a um projeto WinForms contendo o formulário1: o formulário principal e o formulário 2: o formulário de espera.
private Form2 m_pleaseWaitForm = null;
private void Form1_Shown(object sender, EventArgs e)
{
// This code could also be placed in eg. a button click event handler.
Action<Rectangle> a = new Action<Rectangle>(ShowPleaseWait);
a.BeginInvoke(this.Bounds, null, null);
// Do your long running tasks
ClosePleaseWait();
}
private void ShowPleaseWait(Rectangle bounds)
{
// This method runs on the new thread.
m_pleaseWaitForm = new Form2();
m_pleaseWaitForm.TopMost = true;
m_pleaseWaitForm.Location = new Point(bounds.Left + bounds.Width / 2 - m_pleaseWaitForm.Width / 2, bounds.Top + bounds.Height / 2 - m_pleaseWaitForm.Height / 2);
m_pleaseWaitForm.ShowDialog();
}
private void ClosePleaseWait()
{
m_pleaseWaitForm.BeginInvoke((MethodInvoker)delegate { m_pleaseWaitForm.Close(); });
}
Use um trabalho de fundo