views:

272

answers:

2

I have IsMoveToPointEnabled on for my Slider, so when I click anywhere on the component the selector moves to my mouse. The problem is if I have this option on and click and hold the mouse down to drag the selector the selector doesn't move. Anyone know how to fix this?

+1  A: 

See this link for a possible solution:

http://social.msdn.microsoft.com/forums/en-US/wpf/thread/e1318ef4-c76c-4267-9031-3bb7a0db502b

Wallstreet Programmer
I couldn't seem to get it to work. How do I pass the event on to the native control of the component?
Kirk
You don't pass the event. In the appropriate eventhandler(s) you calculate and set the position of the slider.
Wallstreet Programmer
Shoot, is there any way to have the native code handle that computation?
Kirk
+3  A: 

The simplest way is to subclass Slider:

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

In which case your XAML would be:

<my:CustomSlider IsMoveToPointEnabled="True" />

For a more versatile solution that doesn't subclass Slider you can do it with an attached property:

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

You would use this attached property on Slider along with the IsMoveToPointEnabled property:

<Slider IsMoveToPointEnabled="True" my:SliderTools.MoveToPointOnDrag="True" ... />

Both of these solutions work by converting PreviewMouseMove events into equivalent PreviewMouseLeftButtonDown events whenever the left button is down.

Note that the attached property does not remove the event handler when the property is set to false. I wrote it this way for simplicity since you almost never would need to remove such a handler. I recommend you stick with this simple solution, but if you want you can modify the PropertyChangedCallback to remove the handler when NewValue is false.

Ray Burns
Thanks Ray! I think I almost have it working. I'm having an issue with type casting in the mouse move function in SliderTools. Here's my error: Unable to cast object of type 'System.Windows.Input.MouseButtonEventHandler' to type 'System.Windows.Input.MouseEventHandler'. Any thoughts on how to fix it?
Kirk
Sorry about that. For the routed event technique I needed to pass in a MouseButtonEventArgs instead of a MouseEventArgs because the MouseEventArgs actually checks its event type. I've made the necessary change and tested the resulting code. It seems to do exactly what you want. Enjoy!
Ray Burns