c# - tutorial - wpf vs windows forms
Cambiar el cursor en WPF a veces funciona, a veces no funciona (4)
¿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.
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.
Puede usar un activador de datos (con un modelo de vista) en el botón para habilitar un cursor de espera.
<Button x:Name="NextButton"
Content="Go"
Command="{Binding GoCommand }">
<Button.Style>
<Style TargetType="{x:Type Button}">
<Setter Property="Cursor" Value="Arrow"/>
<Style.Triggers>
<DataTrigger Binding="{Binding Path=IsWorking}" Value="True">
<Setter Property="Cursor" Value="Wait"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
Aquí está el código del modelo de vista:
public class MainViewModel : ViewModelBase
{
// most code removed for this example
public MainViewModel()
{
GoCommand = new DelegateCommand<object>(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;
});
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 declaración antes del final de la instrucción.
Actualizar
Para evitar que el cursor parpadee, puede hacer:
public class OverrideCursor : IDisposable
{
static Stack<Cursor> s_Stack = new Stack<Cursor>();
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;
}
}