滑块不会与IsMoveToPointEnabled行为一起拖动

Kir*_*met 12 c# wpf slider

我为我的Slider启用了IsMoveToPointEnabled,所以当我单击组件上的任何位置时,选择器会移动到我的鼠标.问题是如果我打开此选项并单击并按住鼠标以拖动选择器,选择器不会移动.有人知道怎么修这个东西吗?

Ray*_*rns 18

最简单的方法是子类Slider:

public class CustomSlider : Slider
{
  public override void OnPreviewMouseMove(MouseEventArgs e)
  {
    if(e.LeftButton == MouseButtonState.Pressed)
      OnPreviewMouseLeftButtonDown(e);
  }
}
Run Code Online (Sandbox Code Playgroud)

在这种情况下,您的XAML将是:

<my:CustomSlider IsMoveToPointEnabled="True" />
Run Code Online (Sandbox Code Playgroud)

对于不是Slider子类的更通用的解决方案,您可以使用附加属性来执行此操作:

public class SliderTools : DependencyObject
{
  public static bool GetMoveToPointOnDrag(DependencyObject obj) { return (bool)obj.GetValue(MoveToPointOnDragProperty); }
  public static void SetMoveToPointOnDrag(DependencyObject obj, bool value) { obj.SetValue(MoveToPointOnDragProperty, value); }
  public static readonly DependencyProperty MoveToPointOnDragProperty = DependencyProperty.RegisterAttached("MoveToPointOnDrag", typeof(bool), typeof(SliderTools), new PropertyMetadata
  {
    PropertyChangedCallback = (obj, changeEvent) =>
    {
      var slider = (Slider)obj;
      if((bool)changeEvent.NewValue)
        slider.MouseMove += (obj2, mouseEvent) =>
        {
          if(mouseEvent.LeftButton == MouseButtonState.Pressed)
            slider.RaiseEvent(new MouseButtonEventArgs(mouseEvent.MouseDevice, mouseEvent.Timestamp, MouseButton.Left)
            {
              RoutedEvent = UIElement.PreviewMouseLeftButtonDownEvent,
              Source = mouseEvent.Source,
            });
        };
    }
  });
}
Run Code Online (Sandbox Code Playgroud)

您可以在Slider上使用此附加属性以及IsMoveToPointEnabled属性:

<Slider IsMoveToPointEnabled="True" my:SliderTools.MoveToPointOnDrag="True" ... />
Run Code Online (Sandbox Code Playgroud)

这两种解决方案都可以通过在左键按下时将PreviewMouseMove事件转换为等效的PreviewMouseLeftButtonDown事件来工作.

请注意,当属性设置为false时,附加属性不会删除事件处理程序.我这样写是为了简单,因为你几乎从不需要删除这样的处理程序.我建议您坚持使用这个简单的解决方案,但是如果您愿意,可以修改PropertyChangedCallback以在NewValue为false时删除处理程序.


Tim*_*ann 7

灵感来自Ray Burns答案,我找到的最简单的方法是:

mySlider.PreviewMouseMove += (sender, args) =>
{
    if (args.LeftButton == MouseButtonState.Pressed)
    {
        mySlider.RaiseEvent(new MouseButtonEventArgs(args.MouseDevice, args.Timestamp, MouseButton.Left)
        {
            RoutedEvent = UIElement.PreviewMouseLeftButtonDownEvent,
                 Source = args.Source
        });
    }
};
Run Code Online (Sandbox Code Playgroud)

mySlider是我的Slider的名字.

此解决方案存在两个问题(本主题中的大多数其他问题):
1.如果单击并按住滑块外的鼠标,然后在滑块上移动它,则会开始拖动.
2.如果您使用滑块的自动工具提示,则使用此方法拖动时无效.

所以这是一个改进的版本,解决了这两个问题:

mySlider.MouseMove += (sender, args) =>
{
    if (args.LeftButton == MouseButtonState.Pressed && this.clickedInSlider)
    {
        var thumb = (mySlider.Template.FindName("PART_Track", mySlider) as System.Windows.Controls.Primitives.Track).Thumb;
        thumb.RaiseEvent(new MouseButtonEventArgs(args.MouseDevice, args.Timestamp, MouseButton.Left)
        {
            RoutedEvent = UIElement.MouseLeftButtonDownEvent,
                 Source = args.Source
        });
    }
};

mySlider.AddHandler(UIElement.PreviewMouseLeftButtonDownEvent, new RoutedEventHandler((sender, args) =>
{
    clickedInSlider = true;
}), true);

mySlider.AddHandler(UIElement.PreviewMouseLeftButtonUpEvent, new RoutedEventHandler((sender, args) =>
{
    clickedInSlider = false;
}), true);
Run Code Online (Sandbox Code Playgroud)

clickedInSlider是在类中定义的私有辅助变量.

通过使用clickedInSlider辅助变量我们避免1.处理PreviewMouseButtonDown事件(因为MoveToPoint = true),所以我们必须使用mySlider.AddHandler.
通过在Thumb上而不是Slider上引发事件,我们确保显示autotooltip.

  • 到目前为止,我发现最好的版本用于改进滑块.我用它来创建一个更友好的触摸滑块.我发现在子类中实现它更干净.谢谢! (2认同)