OK, así que creé un método asíncrono estático. Eso deshabilitó el control que inicia la acción y cambia el cursor de la aplicación. Ejecuta la acción como una tarea y espera a que termine. El control vuelve a la persona que llama mientras espera. Por lo tanto, la aplicación sigue respondiendo, incluso mientras el ícono 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;
}
Aquí está el código del formulario 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
{
}
}
Tuve que usar un registrador separado para la acción ficticia (estoy usando Nlog) y mi registrador principal está escribiendo en la interfaz de usuario (un cuadro de texto enriquecido). No pude mostrar el cursor ocupado solo cuando estaba sobre un contenedor particular en el formulario (pero no lo intenté mucho). Todos los controles tienen una propiedad UseWaitCursor, pero no parece tener ningún efecto en los controles Lo intenté (¿tal vez porque no estaban arriba?)
Aquí está el registro principal, que muestra las cosas que suceden en el orden 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