Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WPF: Slider with an event that triggers after a user drags

Tags:

wpf

xaml

slider

I am currently making an MP3 player in WPF, and I want to make a slider that will allow the user to seek to a particular position in an MP3 by sliding the slider to the left or right.

I have tried using the ValueChanged event but that triggers every time it's value is changed, so if you drag it across, the event will fire multiple times, I want the event to only fire when the user has finished dragging the slider and Then get the new value.

How can I achieve this?


[Update]

I have found this post on MSDN which basically discusses the same thing, and they came up with two "solutions"; either subclassing the Slider or invoking a DispatcherTimer in the ValueChanged event that invokes the action after a timespan.

Can you come up with anything better then the two mentioned above?

like image 841
Andreas Grech Avatar asked Apr 06 '09 22:04

Andreas Grech


4 Answers

Besides using the Thumb.DragCompleted event you can also use both ValueChanged and Thumb.DragStarted, this way you don’t lose functionality when the user modifies the value by pressing the arrow keys or by clicking on the slider bar.

Xaml:

<Slider ValueChanged="Slider_ValueChanged"
    Thumb.DragStarted="Slider_DragStarted"
    Thumb.DragCompleted="Slider_DragCompleted"/>

Code behind:

private bool dragStarted = false;

private void Slider_DragCompleted(object sender, DragCompletedEventArgs e)
{
    DoWork(((Slider)sender).Value);
    this.dragStarted = false;
}

private void Slider_DragStarted(object sender, DragStartedEventArgs e)
{
    this.dragStarted = true;
}

private void Slider_ValueChanged(
    object sender,
    RoutedPropertyChangedEventArgs<double> e)
{
    if (!dragStarted)
        DoWork(e.NewValue);
}
like image 71
Alan Avatar answered Nov 15 '22 05:11

Alan


You can use the thumb's 'DragCompleted' event for this. Unfortunately, this is only fired when dragging, so you'll need to handle other clicks and key presses separately. If you only want it to be draggable, you could disable these means of moving the slider by setting LargeChange to 0 and Focusable to false.

Example:

<Slider Thumb.DragCompleted="MySlider_DragCompleted" />
like image 23
YotaXP Avatar answered Nov 15 '22 06:11

YotaXP


<Slider PreviewMouseUp="MySlider_DragCompleted" />

works for me.

The value you want is the value after a mousup event, either on clicks on the side or after a drag of the handle.

Since MouseUp doesn't tunnel down (it is handeled before it can), you have to use PreviewMouseUp.

like image 20
Peter Avatar answered Nov 15 '22 06:11

Peter


Another MVVM-friendly solution (I was not happy with answers)

View:

<Slider Maximum="100" Value="{Binding SomeValue}"/>

ViewModel:

public class SomeViewModel : INotifyPropertyChanged
{
    private readonly object _someValueLock = new object();
    private int _someValue;
    public int SomeValue
    {
        get { return _someValue; }
        set
        {
            _someValue = value;
            OnPropertyChanged();
            lock (_someValueLock)
                Monitor.PulseAll(_someValueLock);
            Task.Run(() =>
            {
                lock (_someValueLock)
                    if (!Monitor.Wait(_someValueLock, 1000))
                    {
                        // do something here
                    }
            });
        }
    }
}

It's delayed (by 1000 ms in given example) operation. New task is created for every change done by slider (either by mouse or keyboard). Before starting task it signals (by using Monitor.PulseAll, perhaps even Monitor.Pulse would be enough) to running already tasks (if any) to stop. Do something part will only occurs when Monitor.Wait don't get signal within timeout.

Why this solution? I don't like spawning behavior or having unnecessary event handling in the View. All code is in one place, no extra events needed, ViewModel has choice to either react on each value change or at the end of user operation (which adds tons of flexibility, especially when using binding).

like image 8
Sinatr Avatar answered Nov 15 '22 07:11

Sinatr