Иногда меняет курсор в WPF, иногда

В нескольких моих usercontrols я меняю курсор, используя

this.Cursor = Cursors.Wait;

когда я нажимаю на что-то.

Теперь я хочу сделать то же самое на странице WPF при нажатии кнопки. Когда я наводил курсор на мою кнопку, курсор меняется на руку, но когда я нажимаю на нее, она не изменяется на курсор ожидания. Интересно, связано ли это с тем, что это кнопка, или потому что это страница, а не пользовательский контроль? Это похоже на странное поведение.

Ответ 1

Вам нужен курсор, чтобы быть "ожидающим" курсором, только когда он над этой конкретной страницей /usercontrol? Если нет, я бы предложил использовать Mouse.OverrideCursor:

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

Это переопределяет курсор для вашего приложения, а не только для части его пользовательского интерфейса, поэтому проблема, которую вы описываете, уходит.

Ответ 2

Один из способов сделать это в нашем приложении - использовать IDisposable, а затем с блоками using(){}, чтобы гарантировать, что курсор reset по завершении.

public class OverrideCursor : IDisposable
{

  public OverrideCursor(Cursor changeToCursor)
  {
    Mouse.OverrideCursor = changeToCursor;
  }

  #region IDisposable Members

  public void Dispose()
  {
    Mouse.OverrideCursor = null;
  }

  #endregion
}

а затем в вашем коде:

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

Завершение завершится, когда либо: конец используемого оператора будет достигнут, либо; если исключение выбрано, и управление оставляет блок оператора до конца инструкции.

Обновление

Чтобы предотвратить мерцание курсора, вы можете:

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;
  }

}

Ответ 3

Вы можете использовать триггер данных (с моделью просмотра) на кнопке, чтобы включить курсор ожидания.

<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>

Вот код из модели вида:

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;
      }
   }
}

Ответ 4

Если ваше приложение использует материал async и вы играете с курсором мыши, вы, вероятно, захотите сделать это только в основном потоке пользовательского интерфейса. Вы можете использовать поток приложения Dispatcher для этого:

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