Answered by:

making the slider slide with one click anywhere on the slider?

Question

If the user clicks (mouse down) on the slider somewhere the thumb is moved to the location of the click immediately

when the user clicked on the slider and he moves the mouse, the thumb is sliding with the cursor...

1.Apparently there is a property called "IsMoveToPointEnabled" that if set to True causes the RepeatButton behaviour of the Slider to disappear and the thumb immediately moves to the point where clicked.

2.This is the default behaviour of the slider if you click on the thumb anyway but unfortunately if you click not on the thumb (thus using the IsMoveToPointEnabled) you cannot move the thumb after the first click without clicking on the thumb again.

Answers

To make this work, you need to dig into the template of the slider and get a reference to it's thumb. Once you have that, you can set a MouseEnter handler on the thumb. Anytime the thumb is moved in response to a click on the track, it will be moved under the mouse. This will conveniently raise the MouseEnter event while the left mouse button is already down.

In your MouseEnter handler, you just need to check whether the left mouse button is down. If so, is the mouse already captured? If so, then the thumb already has capture and you're golden. If not, then the thumb was moved under the mouse so you need to raise a new MouseLeftButtonDown event on the thumb so that it captures the mouse.

> I used it in a subclass of slider so I added the part in the constructor into the OnInitialized(...) method

Even better! A portable solution.

One suggestion... since you're now within the control, I would move the code from OnInitialized to OnApplyTemplate. Then you don't need to call ApplyTemplate directly. OnApplyTemplate will be called when the control template is applied and anytime it gets re-applied (if the template changes).

Last edit... I promise.

Code Block

publicclassMySlider : Slider

{

privateThumb _thumb = null;

publicoverridevoid OnApplyTemplate()

{

base.OnApplyTemplate();

if (_thumb != null)

{

_thumb.MouseEnter -= thumb_MouseEnter;

}

_thumb = (GetTemplateChild("PART_Track") asTrack).Thumb;

if (_thumb != null)

{

_thumb.MouseEnter += thumb_MouseEnter;

}

}

privatevoid thumb_MouseEnter(object sender, MouseEventArgs e)

{

if (e.LeftButton == MouseButtonState.Pressed)

{

// the left button is pressed on mouse enter

// so the thumb must have been moved under the mouse

// in response to a click on the track.

// Generate a MouseLeftButtonDown event.

MouseButtonEventArgs args = newMouseButtonEventArgs(

e.MouseDevice, e.Timestamp,

MouseButton.Left);

args.RoutedEvent = MouseLeftButtonDownEvent;

(sender

asThumb).RaiseEvent(args);

}

}

}

Thinking about it more, the check for Capture is probably superfluous. If the mouse is already captured, it's not possible for the MouseEnter to fire. So really you'd just need to check the state of the left mouse button.

To make this work, you need to dig into the template of the slider and get a reference to it's thumb. Once you have that, you can set a MouseEnter handler on the thumb. Anytime the thumb is moved in response to a click on the track, it will be moved under the mouse. This will conveniently raise the MouseEnter event while the left mouse button is already down.

In your MouseEnter handler, you just need to check whether the left mouse button is down. If so, is the mouse already captured? If so, then the thumb already has capture and you're golden. If not, then the thumb was moved under the mouse so you need to raise a new MouseLeftButtonDown event on the thumb so that it captures the mouse.

> I used it in a subclass of slider so I added the part in the constructor into the OnInitialized(...) method

Even better! A portable solution.

One suggestion... since you're now within the control, I would move the code from OnInitialized to OnApplyTemplate. Then you don't need to call ApplyTemplate directly. OnApplyTemplate will be called when the control template is applied and anytime it gets re-applied (if the template changes).

Last edit... I promise.

Code Block

publicclassMySlider : Slider

{

privateThumb _thumb = null;

publicoverridevoid OnApplyTemplate()

{

base.OnApplyTemplate();

if (_thumb != null)

{

_thumb.MouseEnter -= thumb_MouseEnter;

}

_thumb = (GetTemplateChild("PART_Track") asTrack).Thumb;

if (_thumb != null)

{

_thumb.MouseEnter += thumb_MouseEnter;

}

}

privatevoid thumb_MouseEnter(object sender, MouseEventArgs e)

{

if (e.LeftButton == MouseButtonState.Pressed)

{

// the left button is pressed on mouse enter

// so the thumb must have been moved under the mouse

// in response to a click on the track.

// Generate a MouseLeftButtonDown event.

MouseButtonEventArgs args = newMouseButtonEventArgs(

e.MouseDevice, e.Timestamp,

MouseButton.Left);

args.RoutedEvent = MouseLeftButtonDownEvent;

(sender

asThumb).RaiseEvent(args);

}

}

}

Thinking about it more, the check for Capture is probably superfluous. If the mouse is already captured, it's not possible for the MouseEnter to fire. So really you'd just need to check the state of the left mouse button.

Thinking about it more, the check for Capture is probably superfluous. If the mouse is already captured, it's not possible for the MouseEnter to fire. So really you'd just need to check the state of the left mouse button.

indeed

Dr. WPF wrote:

One suggestion... since you're now within the control, I would move the code from OnInitialized to OnApplyTemplate. Then you don't need to call ApplyTemplate directly. OnApplyTemplate will be called when the control template is applied and anytime it gets re-applied (if the template changes).

How could this work without using a mouse. With a custom touch screen I have a point on the screen, I have access to the slider element and now I want to move the slider to the point on the screen. The problem seems to be the MouseDevice. I cannot create my custom mousedevice.

I also ran into this problem when developing a touch screen application. Dr. WPF's solution doesn't work well if you have a very skinny Thumb and have snap to ticks enabled with relatively sparse ticks. For example, say you have a horizontal
Slider with Ticks placed 100 pixels apart and a Thumb with a 1 pixel width. If you click a few pixels to the right of a Tick and drag right, the thumb will not follow the mouse.

This isn't as elegant as Dr. WPF's solution because it banks on the fact that the Slider class internally does the SnapToTick call in its PreviewMouseLeftButtonDown handler, which I discovered via .NET Reflector.

I really wish WPF had a built-in suite of Controls designed entirely for touch screens and the imprecision/parallax issues that entails, especially on big touch screens. I feel like I have to re-invent the wheel with this stuff.