OK, então eu criei um método assíncrono estático. Isso desativou o controle que inicia a ação e altera o cursor do aplicativo. Ele executa a ação como uma tarefa e aguarda o término. O controle retorna ao chamador enquanto aguarda. Portanto, o aplicativo permanece responsivo, mesmo enquanto o ícone ocupado gira.
async public static void LengthyOperation(Control control, Action action)
{
try
{
control.Enabled = false;
Application.UseWaitCursor = true;
Task doWork = new Task(() => action(), TaskCreationOptions.LongRunning);
Log.Info("Task Start");
doWork.Start();
Log.Info("Before Await");
await doWork;
Log.Info("After await");
}
finally
{
Log.Info("Finally");
Application.UseWaitCursor = false;
control.Enabled = true;
}
Aqui está o código do formulário principal
private void btnSleep_Click(object sender, EventArgs e)
{
var control = sender as Control;
if (control != null)
{
Log.Info("Launching lengthy operation...");
CursorWait.LengthyOperation(control, () => DummyAction());
Log.Info("...Lengthy operation launched.");
}
}
private void DummyAction()
{
try
{
var _log = NLog.LogManager.GetLogger("TmpLogger");
_log.Info("Action - Sleep");
TimeSpan sleep = new TimeSpan(0, 0, 16);
Thread.Sleep(sleep);
_log.Info("Action - Wakeup");
}
finally
{
}
}
Eu tive que usar um logger separado para a ação fictícia (estou usando o Nlog) e meu logger principal está gravando na interface do usuário (uma caixa de rich text). Não consegui exibir o cursor ocupado apenas quando estava sobre um contêiner específico no formulário (mas não tentei muito.) Todos os controles têm uma propriedade UseWaitCursor, mas parece não ter efeito nos controles Eu tentei (talvez porque eles não estavam no topo?)
Aqui está o log principal, que mostra as coisas acontecendo na ordem que esperamos:
16:51:33.1064 Launching lengthy operation...
16:51:33.1215 Task Start
16:51:33.1215 Before Await
16:51:33.1215 ...Lengthy operation launched.
16:51:49.1276 After await
16:51:49.1537 Finally