I\'ve slider that its value is bind to some property, and the property updates it all the time. While dragging the [thumb on] slider I want to stop this update value of slider f
I had the same issue so I made a simple slider extension as the next best thing. Adds two events to the slider:
ThumbDragStarted ThumbDragCompleted
public class SliderWithDraggingEvents : Slider
{
public delegate void ThumbDragStartedHandler(object sender, DragStartedEventArgs e);
public event ThumbDragStartedHandler ThumbDragStarted;
public delegate void ThumbDragCompletedHandler(object sender, DragCompletedEventArgs e);
public event ThumbDragCompletedHandler ThumbDragCompleted;
protected override void OnThumbDragStarted(DragStartedEventArgs e)
{
if (ThumbDragStarted != null) ThumbDragStarted(this, e);
base.OnThumbDragStarted(e);
}
protected override void OnThumbDragCompleted(DragCompletedEventArgs e)
{
if (ThumbDragCompleted != null) ThumbDragCompleted(this, e);
base.OnThumbDragCompleted(e);
}
}
Neither of the answers worked for me - the first one wouldn't slide, and the second still updated a bound value during sliding (which is what the question was asking - I think). I ended up sub-classing Slider to include a dependency property for a second bound value (Value2, for want of a better name), which does not get updated whilst the Slider is being dragged. All other value updates are reflected, and the value is also updated once the drag completes. There are probably some gaping holes in this class, but it is seems to be working fine for my purposes.
public class SliderNoDragUpdates : Slider
{
public static readonly DependencyProperty Value2Property =
DependencyProperty.RegisterAttached(
"Value2",
typeof(double),
typeof(SliderNoDragUpdates),
new FrameworkPropertyMetadata(0D, new PropertyChangedCallback(OnValue2Changed), new CoerceValueCallback(CoerceValue2))
{
BindsTwoWayByDefault = true,
});
private static object CoerceValue2(DependencyObject d, object value)
{
SliderNoDragUpdates c = (SliderNoDragUpdates)d;
double v = (double)value;
if (v < c.Minimum) v = c.Minimum;
if (v > c.Maximum) v = c.Maximum;
return v;
}
private static void OnValue2Changed(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
d.CoerceValue(Value2Property);
}
public double Value2
{
get { return (double)this.GetValue(Value2Property); }
set
{
if (value != Value2)
this.SetValue(Value2Property, value);
if (value != Value)
this.SetValue(ValueProperty, value);
}
}
private bool _dragging = false;
protected override void OnThumbDragStarted(System.Windows.Controls.Primitives.DragStartedEventArgs e)
{
_dragging = true;
base.OnThumbDragStarted(e);
}
protected override void OnThumbDragCompleted(System.Windows.Controls.Primitives.DragCompletedEventArgs e)
{
_dragging = false;
Value2 = Value;
base.OnThumbDragCompleted(e);
}
protected override void OnValueChanged(double oldValue, double newValue)
{
if (!_dragging)
Value2 = Value;
base.OnValueChanged(oldValue, newValue);
}
}
To use it, instantiate a SliderNoDragUpdates in place of a normal Slider, and bind to Value2 instead of Value (or, indeed - bind to both, so that you can see the value update in a cheap-to-update field, whilst waiting for the drag to complete before starting your expensive operation).
<Window x:Class="slidertest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:slidertest"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="40"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<local:SliderNoDragUpdates Value="{Binding slider_value}" Value2="{Binding slider_value2}" Minimum="0" Maximum="100" VerticalAlignment="Center"/>
<Viewbox Grid.Row="1">
<StackPanel Orientation="Horizontal">
<TextBox FontWeight="Bold" FontFamily="Arial" FontSize="25" Text="{Binding slider_value}"/>
<TextBox FontWeight="Bold" FontFamily="Arial" FontSize="25" Text="{Binding slider_value2}"/>
</StackPanel>
</Viewbox>
</Grid>
Added a flag to indicate dragging and only send out value changed events when the slider is being dragged.
public class CustomSlider:Slider
{
public bool IsDragging { get; protected set; }
protected override void OnThumbDragCompleted(System.Windows.Controls.Primitives.DragCompletedEventArgs e)
{
IsDragging = false;
base.OnThumbDragCompleted(e);
}
protected override void OnThumbDragStarted(System.Windows.Controls.Primitives.DragStartedEventArgs e)
{
IsDragging = true;
base.OnThumbDragStarted(e);
}
protected override void OnValueChanged(double oldValue, double newValue)
{
if (!IsDragging)
{
base.OnValueChanged(oldValue, newValue);
}
}
}
Hi this solution works for me. Just override Slider class and bind to FinalValue in xaml.
public class ExSlider : Slider
{
public double FinalValue
{
get { return (double)GetValue(FinalValueProperty); }
set { SetValue(FinalValueProperty, value); }
}
public static readonly DependencyProperty FinalValueProperty =
DependencyProperty.Register(
"FinalValue", typeof(double), typeof(ExSlider),
new FrameworkPropertyMetadata(0d,
FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
protected override void OnThumbDragCompleted(DragCompletedEventArgs e)
{
base.OnThumbDragCompleted(e);
FinalValue = Value;
}
}
The template for Slider includes a Thumb, which raises the ThumbDragDelta event as the mouse is moved. Slider will always update the bound value immediately when it receives a ThumbDragDelta event.
The trick is to stop this event. The easiest way is to subclass Slider:
public class SliderIgnoreDelta : Slider
{
protected override void OnThumbDragDelta(DragDeltaEventArgs e)
{
// Do nothing
}
}
This slider will not update the value until the thumb drag completes.
Another solution is to intercept the ThumbDragDelta event on the Thumb. If you happen to be re-templating the Slider anyway, this might be a better solution. For example if you already have an EventBlocker class coded up that sets Handled true on the given RoutedEvent, you could put this in your template:
<Track.Thumb>
<Thumb my:EventBlocker.EventToBlock="{x:Static Thumb.DragDeltaEvent}" />
</Track.Thumb>
But for most cases you'll probably want to go with my first solution.