Cambiar el cursor en WPF a veces funciona, a veces no funciona

En varios de mis controles de usuario, cambio el cursor usando

this.Cursor = Cursors.Wait; 

cuando hago clic en algo

Ahora quiero hacer lo mismo en una página de WPF con un clic de botón. Cuando sobrevuelvo mi botón, el cursor cambia a una mano, pero cuando hago clic en él, no cambia al cursor de espera. Me pregunto si esto tiene algo que ver con el hecho de que es un botón, o porque esta es una página y no un control de usuario. Esto parece un comportamiento extraño.

¿Necesita que el cursor sea un cursor de “espera” solo cuando haya terminado esa página / control de usuario en particular? Si no, sugeriría usar Mouse.OverrideCursor :

 Mouse.OverrideCursor = Cursors.Wait; try { // do stuff } finally { Mouse.OverrideCursor = null; } 

Esto anula el cursor de su aplicación en lugar de solo una parte de su UI, por lo que el problema que está describiendo desaparece.

Una forma de hacerlo en nuestra aplicación es usar IDisposable y luego using(){} bloques using(){} para asegurar que el cursor se reinicie cuando termine.

 public class OverrideCursor : IDisposable { public OverrideCursor(Cursor changeToCursor) { Mouse.OverrideCursor = changeToCursor; } #region IDisposable Members public void Dispose() { Mouse.OverrideCursor = null; } #endregion } 

y luego en tu código:

 using (OverrideCursor cursor = new OverrideCursor(Cursors.Wait)) { // Do work... } 

La anulación finalizará cuando: se llegue al final de la instrucción using o; si se lanza una excepción y el control deja el bloque de statement antes del final de la instrucción.

Actualizar

Para evitar que el cursor parpadee, puede hacer:

 public class OverrideCursor : IDisposable { static Stack s_Stack = new Stack(); public OverrideCursor(Cursor changeToCursor) { s_Stack.Push(changeToCursor); if (Mouse.OverrideCursor != changeToCursor) Mouse.OverrideCursor = changeToCursor; } public void Dispose() { s_Stack.Pop(); Cursor cursor = s_Stack.Count > 0 ? s_Stack.Peek() : null; if (cursor != Mouse.OverrideCursor) Mouse.OverrideCursor = cursor; } } 

Puede usar un activador de datos (con un modelo de vista) en el botón para habilitar un cursor de espera.

  

Aquí está el código del modelo de vista:

 public class MainViewModel : ViewModelBase { // most code removed for this example public MainViewModel() { GoCommand = new DelegateCommand(OnGoCommand, CanGoCommand); } // flag used by data binding trigger private bool _isWorking = false; public bool IsWorking { get { return _isWorking; } set { _isWorking = value; OnPropertyChanged("IsWorking"); } } // button click event gets processed here public ICommand GoCommand { get; private set; } private void OnGoCommand(object obj) { if ( _selectedCustomer != null ) { // wait cursor ON IsWorking = true; _ds = OrdersManager.LoadToDataSet(_selectedCustomer.ID); OnPropertyChanged("GridData"); // wait cursor off IsWorking = false; } } } 

Si su aplicación utiliza elementos de sincronización y está jugueteando con el cursor del mouse, es probable que desee hacerlo solo en el hilo de interfaz de usuario principal. Puede usar el hilo Dispatcher de la aplicación para eso:

 Application.Current.Dispatcher.Invoke(() => { // The check is required to prevent cursor flickering if (Mouse.OverrideCursor != cursor) Mouse.OverrideCursor = cursor; });