c# - quitar - Mostrando el cursor de espera mientras se está ejecutando backgroundworker
poner cursor en espera c# (9)
Durante el inicio de mi aplicación de Windows, tengo que hacer una llamada a un servicio web para recuperar algunos datos predeterminados para cargar en mi aplicación. Durante la carga del formulario, ejecuto un backgroundworker para recuperar estos datos. Quiero mostrar el cursor de espera hasta que se recuperen estos datos. ¿Cómo haría esto?
He intentado configurar el cursor de espera antes de llamar al trabajador de fondo para que se ejecute. Cuando reporto un progreso de 100, lo vuelvo a configurar en el cursor predeterminado. El cursor de espera aparece pero cuando muevo el mouse desaparece.
Ambiente:
- Windows 7 Pro de 64 bits
- VS2010 C # .NET 4.0
- Formularios de Windows
EDITAR: Estoy poniendo el cursor de la manera que Jay Riggs sugirió. Solo funciona si no muevo el mouse.
* * ACTUALIZACIÓN: He creado un clic de botón que hace lo siguiente: Cuando hago el clic de botón y muevo mi mouse, el cursor de espera aparece independientemente de si muevo mi mouse o no.
void BtnClick()
{
Cursor = Cursors.WaitCursor;
Thread.Sleep(8000);
Cursor = Cursors.Default;
}
Si hago lo siguiente: veo el cursor de espera y cuando muevo el mouse desaparece dentro del formulario. Si me muevo a mi barra de estado o la barra de menú, aparece el cursor de espera.
Cursor = Cursors.WaitCursor;
if (!backgroundWorker.IsBusy)
{
backGroundWorker.RunWorkerAsync();
}
void backGroundWorkerDoWork(object sender, DoWorkEventArgs e)
{
Thread.Sleep(8000);
}
void backGroundWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
Cursor = Cursors.Default;
}
Si hago lo siguiente: el cursor de espera aparece y cuando muevo el mouse todavía aparece, pero a veces parpadea y se apaga cuando se mueve en campos de texto. Aunque el cursor cambia al cursor de espera, no le impide hacer clic en nada.
if (!backgroundWorker.IsBusy)
{
backGroundWorker.RunWorkerAsync();
}
void backGroundWorkerDoWork(object sender, DoWorkEventArgs e)
{
UseWaitCursor = true;
Thread.Sleep(8000);
}
void backGroundWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
UseWaitCursor = false;
}
¿ UseWaitCursor
? (Establézcalo en verdadero cuando llame a RunWorkerAsync (), y falso cuando se llame al evento de finalización). ¿Qué estás usando para ajustar el cursor ahora?
Algo más debe estar poniendo el cursor. El siguiente código establece un cursor de espera cuando se inicia el temporizador, y luego vuelve a colocar el cursor en el valor anterior una vez que el temporizador expira. Funciona como se esperaba: el cursor de espera permanece a lo largo del intervalo. Por supuesto, mover el cursor fuera del formulario mostrará el cursor para cualquier ventana sobre la que se encuentre el cursor del mouse, pero al moverlo de nuevo a mi formulario, se muestra el cursor de espera.
public partial class MyDialog : Form
{
private Timer myTimer;
public MyDialog()
{
InitializeComponent();
myTimer = new Timer();
myTimer.Tick += new EventHandler(myTimer_Tick);
myTimer.Interval = 5000;
myTimer.Enabled = false;
}
private Cursor SaveCursor;
private void button1_Click(object sender, EventArgs e)
{
Cursor = Cursors.WaitCursor;
myTimer.Enabled = true;
}
void myTimer_Tick(object sender, EventArgs e)
{
Cursor = SaveCursor;
myTimer.Enabled = false;
}
}
Debe usar el evento RunWorkerCompleted de BGW para volver a establecer el cursor en el valor predeterminado.
EDITAR:
Configure el cursor para que espere llamando a este código antes de iniciar su BGW:
this.Cursor = Cursors.WaitCursor;
Restablezca su cursor en el evento RunWorkerCompleted de BGW mediante:
this.Cursor = Cursors.Default;
En WPF, he hecho esto configurando la propiedad Mouse.OverrideCursor
en Cursors.Wait
antes de iniciar el Backgroundworker, y luego restableciéndolo a null
en el evento RunWorkerCompleted
. Parece funcionar bastante bien hasta ahora.
public void go()
{
BackgroundWorker thread = new BackgroundWorker();
thread.DoWork += run;
thread.RunWorkerCompleted += taskCompleted;
thread.WorkerReportsProgress = true;
// Change mouse cursor to busy
Mouse.OverrideCursor = Cursors.Wait;
thread.RunWorkerAsync();
}
private void taskCompleted(object sender, RunWorkerCompletedEventArgs e)
{
// Reset mouse cursor
Mouse.OverrideCursor = null;
}
En el hilo de los foros de MS, UseWaitCursor no funciona pero Cursor = Cursors.WaitCursor hace .../ & Cursor.Current vs. this.Cursor
se confirmó que la implementación de UseWaitCursor por parte de WF perdió la oportunidad de hacer que realmente funcionara para mostrar un cursor de reloj de arena y se mostró la clase HourGlass, que se puede usar con el bloque "utilizando"
using (new HourGlass()) {
// Do something that takes time...
System.Threading.Thread.Sleep(2000);
}
Esto es lo que estoy haciendo ahora, espero esta ayuda.
private void LoadWaitCursor()
{
this.Dispatcher.Invoke((Action)(() =>
{
Mouse.OverrideCursor = Cursors.Wait;
}));
}
private void LoadDefaultCursor()
{
this.Dispatcher.Invoke((Action)(() =>
{
Mouse.OverrideCursor = null;
}));
}
La Fuente de referencia de Microsoft nos da la implementación de Control.UseWaitCursor y Control.Cursor . Si examinas Control.Cursor, verás que si UseWaitCursor está configurado como Verdadero, Control.Cursor devuelve Cursor.WaitCursor independientemente de qué cursor esté configurado en el control. Debido a este comportamiento, el valor devuelto por Control.Cursor no se puede almacenar en caché.
// DON''T DO THIS: THIS CODE WILL BREAK IF UseWaitCursor IS SET TO TRUE
// Store the original cursor
Cursor cachedCursor = this.Cursor;
// Set the cursor to a wait cursor.
this.Cursor = Cursors.WaitCursor;
// Perform some task
// Restore the original cursor
this.Cursor = cachedCursor;
Si bien lo anterior parece bastante inofensivo, puede provocar problemas si alguien configura Control.UseWaitCursor en True antes de que se ejecute. El resultado sería un cursor de espera atascado debido a los cursores Control.Cursor devolviendo los cursores.WaitCursor en la primera línea de la anterior. Un mejor método para cambiar el cursor es así:
// Change the cursor as needed
this.Cursor = Cursors.WaitCursor;
// Perform some task
// Restore the default cursor when finished.
this.Cursor = this.DefaultCursor;
Para la gran mayoría de las cosas, lo anterior debería ser suficiente para mostrar un cursor de espera cuando sea necesario. Sin embargo, si un elemento secundario de un control también modifica el cursor, el cursor establecido por el elemento secundario anulará lo establecido en el elemento primario. Es decir, si establece el cursor de una etiqueta en Cursors.IBeam en un formulario que establece su cursor en Cursors.WaitCursor, la etiqueta mostrará un IBeam mientras que el formulario mostrará el WaitCursor. Solo los controles donde Control.Cursor devuelve el mismo valor que Control.DefaultCursor mostrará el conjunto WaitCursor en el formulario en este caso. Aquí es donde entra en juego Control.UseWaitCursor. La configuración de UseWaitCursor en un formulario establece también UseWaitCursor en todos sus elementos secundarios. Siempre y cuando ninguno de los controles en el formulario esté utilizando el código roto anterior. El DataGridView es solo uno de los muchos controles que utilizaron el código roto anterior.
Pero ... ¿qué sucede si no desea un WaitCursor y desea mantener el cursor configurado externamente por un usuario de su control? En este caso, sus opciones son limitadas, debe anular la propiedad del Cursor de su control para recibir el cursor establecido por un usuario de su control O debe usar la reflexión para obtener acceso al valor del cursor interno almacenado por la clase de Control base. Entonces, y solo entonces puede usar el primer método anterior para almacenar en caché y restaurar el cursor. * Nota: debe almacenar en caché el valor del cursor interno establecido por el usuario de su control, no el resultado de base.Cursor!
No muestre un cursor de espera para esto; en su lugar, use un control en su formulario para indicar que el trabajador de fondo está ocupado haciendo algo. El cursor de espera es un indicador apropiado para el subproceso de la interfaz de usuario (ya que indica que el usuario no puede / no debe tocar nada), pero no es apropiado para que ocurra algo en el fondo.
Ya hay muchas respuestas aquí pero encontré otra solución que funcionó para mí, así que pensé que la enumero.
private void ShowWaitCursor(){
Application.UseWaitCursor = true; //keeps waitcursor even when the thread ends.
System.Windows.Forms.Cursor.Current = Cursors.WaitCursor; //Normal mode of setting waitcursor
}
private void ShowNormalCursor(){
Application.UseWaitCursor = false;
System.Windows.Forms.Cursor.Current = Cursors.Default;
}
Utilizo tanto en línea como esta y parece que funciona como espero todo el tiempo. Especialmente cuando quiero que aparezca un cursor de espera mientras se está ejecutando un trabajador. Espero que esto ayude a alguien más todavía mirando.