WPF ListView Cursor Change

2019-06-05 05:08发布

问题:

I have a scrollable timeline that is made from list views. When my mouse is focused over the list view.

The cursor is a open hand using the code

<ControlTemplate.Triggers>
    <Trigger Property="IsMouseOver" Value="True">
        <Setter Property="Cursor" Value="openHand.cur"/>
    </Trigger>                    
</ControlTemplate.Triggers>

but I was wondering. Is there something I can do if the left mouse button is pressed over the list view. if it is then change the Cursor to a closed hand? Thanks in advance!

回答1:

WPF doesn't have a "IsMouseLeftButtonDown" property, but you can create your own attached property to do this, then trigger on it. This tends to be much cleaner than adding MouseLeftButtonDown event handlers to individual controls.

To do this:

  1. Create inherited attached properties for IsMouseLeftButtonDown (and for the other buttons too)
  2. Create an "Enabled" attached property to automatically set the required event handlers.
  3. Set the "Enabled" property directly on your control, or on any containing control.
  4. Use the "IsMouseLeftButtonDown" property in a Trigger or MultiTrigger

Here is how it might look:

<Window ...
        local:MouseExtensions.Enabled="true" />  <!-- Set the handlers -->
  ...
  <ControlTemplate.Triggers>
    <Trigger Property="IsMouseOver" Value="True" >
      <Setter Property="Cursor" Value="openHand.cur"/>
    </Trigger>
    <MultiTrigger>
      <MultiTrigger.Conditions>
        <Condition Property="IsMouseOver" Value="True" />
        <Condition Property="local:MouseExtensions.IsMouseLeftButtonDown" Value="True" />
      </MultiTrigger.Conditions>
      <Setter Property="Cursor" Value="closedHand.cur" />
    </MultiTrigger>
  </ControlTemplate.Triggers>

Here's how the attached property might be implemented:

public class MouseExtensions : DependencyObject
{
  // IsMouseLeftButtonDown
  public static bool GetIsMouseLeftButtonDown(DependencyObject obj) { return (bool)obj.GetValue(IsMouseLeftButtonDownProperty); }
  public static void SetIsMouseLeftButtonDown(DependencyObject obj, bool value) { obj.SetValue(IsMouseLeftButtonDownProperty, value); }
  public static readonly DependencyProperty IsMouseLeftButtonDownProperty = DependencyProperty.RegisterAttached("IsMouseLeftButtonDown", typeof(bool), typeof(MouseExtensions), new FrameworkPropertyMetadata
  {
    Inherits=true,
  });


  // IsMouseMiddleButtonDown
  public static bool GetIsMouseMiddleButtonDown(DependencyObject obj) { return (bool)obj.GetValue(IsMouseMiddleButtonDownProperty); }
  public static void SetIsMouseMiddleButtonDown(DependencyObject obj, bool value) { obj.SetValue(IsMouseMiddleButtonDownProperty, value); }
  public static readonly DependencyProperty IsMouseMiddleButtonDownProperty = DependencyProperty.RegisterAttached("IsMouseMiddleButtonDown", typeof(bool), typeof(MouseExtensions), new FrameworkPropertyMetadata
  {
    Inherits=true,
  });

  // IsMouseRightButtonDown
  public static bool GetIsMouseRightButtonDown(DependencyObject obj) { return (bool)obj.GetValue(IsMouseRightButtonDownProperty); }
  public static void SetIsMouseRightButtonDown(DependencyObject obj, bool value) { obj.SetValue(IsMouseRightButtonDownProperty, value); }
  public static readonly DependencyProperty IsMouseRightButtonDownProperty = DependencyProperty.RegisterAttached("IsMouseRightButtonDown", typeof(bool), typeof(MouseExtensions), new FrameworkPropertyMetadata
  {
    Inherits=true,
  });

  // Enabled
  public static bool GetEnabled(DependencyObject obj) { return (bool)obj.GetValue(EnabledProperty); }
  public static void SetEnabled(DependencyObject obj, bool value) { obj.SetValue(EnabledProperty, value); }
  public static readonly DependencyProperty EnabledProperty = DependencyProperty.RegisterAttached("Enabled", typeof(bool), typeof(MouseExtensions), new PropertyMetadata
  {
    PropertyChangedCallback = (obj, e) =>
      {
        var element = (FrameworkElement)obj;
        if((bool)e.OldValue)
        {
          element.PreviewMouseDown -= Update;
          element.PreviewMouseUp -= Update;
          element.MouseEnter -= Update;
          element.MouseLeave -= Update;
        }
        if((bool)e.NewValue)
        {
          element.PreviewMouseDown += Update;
          element.PreviewMouseUp += Update;
          element.MouseEnter += Update;
          element.MouseLeave += Update;
        }
      }
  });

  private static void Update(object sender, MouseEventArgs e)
  {
    var element = (FrameworkElement)sender;
    bool inside = e.RoutedEvent!=Mouse.MouseLeaveEvent;
    SetIsMouseLeftButtonDown(element, inside && e.LeftButton==MouseButtonState.Pressed);
    SetIsMouseMiddleButtonDown(element, inside && e.MiddleButton==MouseButtonState.Pressed);
    SetIsMouseRightButtonDown(element, inside && e.RightButton==MouseButtonState.Pressed);
  }
}

How it works: The "Enabled" PropertyChangedCallback adds the "Update" method as a handler for four mouse events. When one of these events occurs, the current mouse button state is checked and the Is___ButtonDown properties are updated on the element where "Enabled" was set to true. From there, these properties are inherited down through the logical and visual tree. However if MouseLeave is received all these properties are set to false, since no mouse events will be received again until the mouse is once again over the element that "Enabled" was set on.



标签: wpf cursor