/************************************************************************************* Extended WPF Toolkit Copyright (C) 2007-2013 Xceed Software Inc. This program is provided to you under the terms of the Microsoft Public License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license For more features, controls, and fast professional support, pick up the Plus Edition at http://xceed.com/wpf_toolkit Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids ***********************************************************************************/ using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Windows.Controls; using System.Windows; using System.Windows.Controls.Primitives; using System.ComponentModel; using System.Windows.Input; using System.Windows.Media; namespace Xceed.Wpf.Toolkit { [TemplatePart( Name = PART_LowerRange, Type = typeof( RepeatButton ) )] [TemplatePart( Name = PART_HigherRange, Type = typeof( RepeatButton ) )] [TemplatePart( Name = PART_HigherSlider, Type = typeof( Slider ) )] [TemplatePart( Name = PART_LowerSlider, Type = typeof( Slider ) )] [TemplatePart( Name = PART_Track, Type = typeof( Track ) )] public class RangeSlider : Control { #region Members private const String PART_LowerRange = "PART_LowerRange"; private const String PART_Range = "PART_Range"; private const String PART_HigherRange = "PART_HigherRange"; private const String PART_HigherSlider = "PART_HigherSlider"; private const String PART_LowerSlider = "PART_LowerSlider"; private const String PART_Track = "PART_Track"; private RepeatButton _lowerRange; private RepeatButton _higherRange; private Slider _lowerSlider; private Slider _higherSlider; private Track _lowerTrack; private Track _higherTrack; private double _deferredUpdateValue; #endregion Members #region Constructors static RangeSlider() { DefaultStyleKeyProperty.OverrideMetadata( typeof( RangeSlider ), new FrameworkPropertyMetadata( typeof( RangeSlider ) ) ); } public RangeSlider() { this.SizeChanged += this.RangeSlider_SizeChanged; } #endregion Constructors #region Properties #region HigherRangeBackground /// /// # TODODOC /// Get/Set the Brush for the Range between higher/maximum values. (Brush) /// public static readonly DependencyProperty HigherRangeBackgroundProperty = DependencyProperty.Register( "HigherRangeBackground", typeof( Brush ), typeof( RangeSlider ) ); public Brush HigherRangeBackground { get { return (Brush)GetValue( RangeSlider.HigherRangeBackgroundProperty ); } set { SetValue( RangeSlider.HigherRangeBackgroundProperty, value ); } } #endregion HigherRangeBackground #region HigherRangeStyle /// /// # TODODOC /// Get/Set the Style for the Range between Higher/Maximum values. (Style) /// public static readonly DependencyProperty HigherRangeStyleProperty = DependencyProperty.Register( "HigherRangeStyle", typeof( Style ), typeof( RangeSlider ) , new FrameworkPropertyMetadata( null ) ); public Style HigherRangeStyle { get { return (Style)this.GetValue( RangeSlider.HigherRangeStyleProperty ); } set { this.SetValue( RangeSlider.HigherRangeStyleProperty, value ); } } #endregion HigherRangeStyle #region HigherRangeWidth /// /// # TODODOC /// /// HigherRangeWidth property is a readonly property, used to calculate the percentage of the HigherRange within the entire min/max range. /// /// private static readonly DependencyPropertyKey HigherRangeWidthPropertyKey = DependencyProperty.RegisterAttachedReadOnly( "HigherRangeWidth", typeof( double ) , typeof( RangeSlider ), new PropertyMetadata( 0d ) ); public static readonly DependencyProperty HigherRangeWidthProperty = HigherRangeWidthPropertyKey.DependencyProperty; public double HigherRangeWidth { get { return (double)GetValue( RangeSlider.HigherRangeWidthProperty ); } private set { SetValue( RangeSlider.HigherRangeWidthPropertyKey, value ); } } #endregion HigherRangeWidth #region HigherThumbBackground /// /// # TODODOC /// Get/Set the Brush for the HigherValue thumb back of the icons [active state]. (Brush) /// public static readonly DependencyProperty HigherThumbBackgroundProperty = DependencyProperty.Register( "HigherThumbBackground", typeof( Brush ), typeof( RangeSlider ) ); public Brush HigherThumbBackground { get { return (Brush)GetValue( RangeSlider.HigherThumbBackgroundProperty ); } set { SetValue( RangeSlider.HigherThumbBackgroundProperty, value ); } } #endregion HigherThumbBackground #region HigherValue /// /// # TODODOC /// /// HigherValue property represents the higher value within the selected range. /// public static readonly DependencyProperty HigherValueProperty = DependencyProperty.Register( "HigherValue", typeof( double ), typeof( RangeSlider ) , new FrameworkPropertyMetadata( 0d, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, RangeSlider.OnHigherValueChanged, RangeSlider.OnCoerceHigherValueChanged ) ); public double HigherValue { get { return (double)GetValue( RangeSlider.HigherValueProperty ); } set { SetValue( RangeSlider.HigherValueProperty, value ); } } private static object OnCoerceHigherValueChanged( DependencyObject d, object basevalue ) { var rangeSlider = (RangeSlider)d; if( (rangeSlider == null) || !rangeSlider.IsLoaded) return basevalue; var min = Math.Min( rangeSlider.Minimum, rangeSlider.Maximum ); var max = Math.Max( rangeSlider.Minimum, rangeSlider.Maximum ); var higherValue = Math.Max( rangeSlider.Minimum, Math.Min( rangeSlider.Maximum, (double)basevalue ) ); higherValue = Math.Max( rangeSlider.LowerValue, ( double)basevalue ); return higherValue; } private static void OnHigherValueChanged( DependencyObject sender, DependencyPropertyChangedEventArgs args ) { RangeSlider rangeSlider = sender as RangeSlider; if( rangeSlider != null ) { rangeSlider.OnHigherValueChanged( (double)args.OldValue, (double)args.NewValue ); } } protected virtual void OnHigherValueChanged( double oldValue, double newValue ) { this.AdjustView(); RoutedEventArgs args = new RoutedEventArgs(); args.RoutedEvent = RangeSlider.HigherValueChangedEvent; this.RaiseEvent( args ); } #endregion HigherValue #region IsDeferredUpdateValues /// /// # TODODOC /// /// Gets/Sets if the LowerValue and HigherValue should be updated only on mouse up. /// public static readonly DependencyProperty IsDeferredUpdateValuesProperty = DependencyProperty.Register( "IsDeferredUpdateValues", typeof( bool ), typeof( RangeSlider ) , new FrameworkPropertyMetadata( false ) ); public bool IsDeferredUpdateValues { get { return (bool)GetValue( RangeSlider.IsDeferredUpdateValuesProperty ); } set { SetValue( RangeSlider.IsDeferredUpdateValuesProperty, value ); } } #endregion IsDeferredUpdateValues #region LowerRangeBackground /// /// # TODODOC /// Get/Set the Brush for the Range between minimum/lower values . (Brush) /// public static readonly DependencyProperty LowerRangeBackgroundProperty = DependencyProperty.Register( "LowerRangeBackground", typeof( Brush ), typeof( RangeSlider ) ); public Brush LowerRangeBackground { get { return (Brush)GetValue( RangeSlider.LowerRangeBackgroundProperty ); } set { SetValue( RangeSlider.LowerRangeBackgroundProperty, value ); } } #endregion LowerRangeBackground #region LowerRangeStyle /// /// # TODODOC /// Get/Set the Style for the Range between Minimum/Lower values. (Style) /// public static readonly DependencyProperty LowerRangeStyleProperty = DependencyProperty.Register( "LowerRangeStyle", typeof( Style ), typeof( RangeSlider ) , new FrameworkPropertyMetadata( null ) ); public Style LowerRangeStyle { get { return (Style)this.GetValue( RangeSlider.LowerRangeStyleProperty ); } set { this.SetValue( RangeSlider.LowerRangeStyleProperty, value ); } } #endregion LowerRangeStyle #region LowerRangeWidth /// /// # TODODOC /// /// LowerRangeWidth property is a readonly property, used to calculate the percentage of the LowerRange, within the entire min/max range. /// /// private static DependencyPropertyKey LowerRangeWidthPropertyKey = DependencyProperty.RegisterAttachedReadOnly( "LowerRangeWidth", typeof( double ) , typeof( RangeSlider ), new PropertyMetadata( 0d ) ); public static readonly DependencyProperty LowerRangeWidthProperty = LowerRangeWidthPropertyKey.DependencyProperty; public double LowerRangeWidth { get { return (double)GetValue( RangeSlider.LowerRangeWidthProperty ); } private set { SetValue( RangeSlider.LowerRangeWidthPropertyKey, value ); } } #endregion LowerRangeWidth #region LowerThumbBackground /// /// # TODODOC /// Get/Set the Brush for the LowerValue thumb back of the icons [active state]. (Brush) /// public static readonly DependencyProperty LowerThumbBackgroundProperty = DependencyProperty.Register( "LowerThumbBackground", typeof( Brush ), typeof( RangeSlider ) ); public Brush LowerThumbBackground { get { return (Brush)GetValue( RangeSlider.LowerThumbBackgroundProperty ); } set { SetValue( RangeSlider.LowerThumbBackgroundProperty, value ); } } #endregion LowerThumbBackground #region LowerValue /// /// # TODODOC /// LowerValue property represents the lower value within the selected range. /// public static readonly DependencyProperty LowerValueProperty = DependencyProperty.Register( "LowerValue", typeof( double ), typeof( RangeSlider ) , new FrameworkPropertyMetadata( 0d, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, RangeSlider.OnLowerValueChanged, RangeSlider.OnCoerceLowerValueChanged ) ); public double LowerValue { get { return (double)GetValue( RangeSlider.LowerValueProperty ); } set { SetValue( RangeSlider.LowerValueProperty, value ); } } private static object OnCoerceLowerValueChanged( DependencyObject d, object basevalue ) { var rangeSlider = (RangeSlider)d; if( (rangeSlider == null) || !rangeSlider.IsLoaded ) return basevalue; var min = Math.Min( rangeSlider.Minimum, rangeSlider.Maximum ); var max = Math.Max( rangeSlider.Minimum, rangeSlider.Maximum ); var lowerValue = Math.Max( rangeSlider.Minimum, Math.Min( rangeSlider.Maximum, (double)basevalue ) ); lowerValue = Math.Min( (double)basevalue, rangeSlider.HigherValue ); return lowerValue; } private static void OnLowerValueChanged( DependencyObject sender, DependencyPropertyChangedEventArgs args ) { RangeSlider rangeSlider = sender as RangeSlider; if( rangeSlider != null ) { rangeSlider.OnLowerValueChanged( (double)args.OldValue, (double)args.NewValue ); } } protected virtual void OnLowerValueChanged( double oldValue, double newValue ) { this.AdjustView(); RoutedEventArgs args = new RoutedEventArgs(); args.RoutedEvent = RangeSlider.LowerValueChangedEvent; this.RaiseEvent( args ); } #endregion LowerValue #region Maximum /// /// # TODODOC /// Maximum property represents the maximum value, which can be selected, in a range. /// public static readonly DependencyProperty MaximumProperty = DependencyProperty.Register( "Maximum", typeof( double ), typeof( RangeSlider ) , new FrameworkPropertyMetadata( RangeSlider.OnMaximumChanged ) ); public double Maximum { get { return (double)GetValue( RangeSlider.MaximumProperty ); } set { SetValue( RangeSlider.MaximumProperty, value ); } } private static void OnMaximumChanged( DependencyObject sender, DependencyPropertyChangedEventArgs args ) { RangeSlider rangeSlider = sender as RangeSlider; if( rangeSlider != null ) { rangeSlider.OnMaximumChanged( (double)args.OldValue, (double)args.NewValue ); } } protected virtual void OnMaximumChanged( double oldValue, double newValue ) { this.AdjustView(); } #endregion Maximum #region Minimum /// /// //#TODODOC /// Minimum property represents the minimum value, which can be selected, in a range. /// public static readonly DependencyProperty MinimumProperty = DependencyProperty.Register( "Minimum", typeof( double ), typeof( RangeSlider ) , new FrameworkPropertyMetadata( RangeSlider.OnMinimumChanged ) ); public double Minimum { get { return (double)GetValue( RangeSlider.MinimumProperty ); } set { SetValue( RangeSlider.MinimumProperty, value ); } } private static void OnMinimumChanged( DependencyObject sender, DependencyPropertyChangedEventArgs args ) { RangeSlider rangeSlider = sender as RangeSlider; if( rangeSlider != null ) { rangeSlider.OnMinimumChanged( (double)args.OldValue, (double)args.NewValue ); } } protected virtual void OnMinimumChanged( double oldValue, double newValue ) { // adjust the range width this.AdjustView(); } #endregion Minimum #region Orientation /// /// # TODODOC /// Get/Set the RangeSlider orientation. /// public static readonly DependencyProperty OrientationProperty = DependencyProperty.Register( "Orientation", typeof( Orientation ), typeof( RangeSlider ), new FrameworkPropertyMetadata( Orientation.Horizontal, RangeSlider.OnOrientationChanged ) ); public Orientation Orientation { get { return (Orientation)GetValue( RangeSlider.OrientationProperty ); } set { SetValue( RangeSlider.OrientationProperty, value ); } } private static void OnOrientationChanged( DependencyObject sender, DependencyPropertyChangedEventArgs e ) { RangeSlider rangeSlider = sender as RangeSlider; if( rangeSlider != null ) { rangeSlider.OnOrientationChanged( (Orientation)e.OldValue, (Orientation)e.NewValue ); } } protected virtual void OnOrientationChanged( Orientation oldValue, Orientation newValue ) { } #endregion //Orientation #region RangeBackground /// /// # TODODOC /// Get/Set the Brush for the Range between lower/higher values [active state]. (Brush) /// public static readonly DependencyProperty RangeBackgroundProperty = DependencyProperty.Register( "RangeBackground", typeof( Brush ), typeof( RangeSlider ) ); public Brush RangeBackground { get { return (Brush)GetValue( RangeSlider.RangeBackgroundProperty ); } set { SetValue( RangeSlider.RangeBackgroundProperty, value ); } } #endregion RangeBackground #region RangeStyle /// /// # TODODOC /// Get/Set the Style for the Range between Lower/Higher values. (Style) /// public static readonly DependencyProperty RangeStyleProperty = DependencyProperty.Register( "RangeStyle", typeof( Style ), typeof( RangeSlider ) , new FrameworkPropertyMetadata( null ) ); public Style RangeStyle { get { return (Style)this.GetValue( RangeSlider.RangeStyleProperty ); } set { this.SetValue( RangeSlider.RangeStyleProperty, value ); } } #endregion RangeStyle #region RangeWidth /// /// # TODODOC /// /// RangeWidth property is a readonly property, used to calculate the percentage of the range within the entire min/max range. /// private static readonly DependencyPropertyKey RangeWidthPropertyKey = DependencyProperty.RegisterAttachedReadOnly( "RangeWidth", typeof( double ) , typeof( RangeSlider ), new PropertyMetadata( 0d ) ); public static readonly DependencyProperty RangeWidthProperty = RangeWidthPropertyKey.DependencyProperty; public double RangeWidth { get { return (double)GetValue( RangeSlider.RangeWidthProperty ); } private set { SetValue( RangeSlider.RangeWidthPropertyKey, value ); } } #endregion RangeWidth #region Step /// /// # TODODOC /// /// Step property is used to identify the RangeSlider's size of individual move, while clicking on the LowerRange, HigherRange, not while scrolling the thumbs. /// private static readonly DependencyProperty StepProperty = DependencyProperty.Register( "Step", typeof( double ), typeof( RangeSlider ) , new PropertyMetadata( 1.0, null, RangeSlider.CoerceStep ) ); public double Step { get { return (double)GetValue( RangeSlider.StepProperty ); } set { SetValue( RangeSlider.StepProperty, value ); } } private static object CoerceStep( DependencyObject sender, object value ) { RangeSlider rangeSlider = sender as RangeSlider; double newValue = (double)value; return Math.Max( 0.01, newValue ); } #endregion #endregion Properties #region Override public override void OnApplyTemplate() { base.OnApplyTemplate(); if( _lowerRange != null ) { _lowerRange.Click -= new RoutedEventHandler( this.LowerRange_Click ); } _lowerRange = this.Template.FindName( PART_LowerRange, this ) as RepeatButton; if( _lowerRange != null ) { _lowerRange.Click += new RoutedEventHandler( this.LowerRange_Click ); } if( _higherRange != null ) { _higherRange.Click -= new RoutedEventHandler( this.HigherRange_Click ); } _higherRange = this.Template.FindName( PART_HigherRange, this ) as RepeatButton; if( _higherRange != null ) { _higherRange.Click += new RoutedEventHandler( this.HigherRange_Click ); } if( _lowerSlider != null ) { _lowerSlider.Loaded -= this.Slider_Loaded; _lowerSlider.ValueChanged -= LowerSlider_ValueChanged; if( _lowerTrack != null ) { _lowerTrack.Thumb.DragCompleted -= this.LowerSlider_DragCompleted; } } _lowerSlider = this.Template.FindName( PART_LowerSlider, this ) as Slider; if( _lowerSlider != null ) { _lowerSlider.Loaded += this.Slider_Loaded; _lowerSlider.ValueChanged += LowerSlider_ValueChanged; _lowerSlider.ApplyTemplate(); _lowerTrack = _lowerSlider.Template.FindName( PART_Track, _lowerSlider ) as Track; if( _lowerTrack != null ) { _lowerTrack.Thumb.DragCompleted += this.LowerSlider_DragCompleted; } } if( _higherSlider != null ) { _higherSlider.Loaded -= this.Slider_Loaded; _higherSlider.ValueChanged -= HigherSlider_ValueChanged; if( _higherTrack != null ) { _higherTrack.Thumb.DragCompleted -= this.HigherSlider_DragCompleted; } } _higherSlider = this.Template.FindName( PART_HigherSlider, this ) as Slider; if( _higherSlider != null ) { _higherSlider.Loaded += this.Slider_Loaded; _higherSlider.ValueChanged += HigherSlider_ValueChanged; _higherSlider.ApplyTemplate(); _higherTrack = _higherSlider.Template.FindName( PART_Track, _higherSlider ) as Track; if( _higherTrack != null ) { _higherTrack.Thumb.DragCompleted += this.HigherSlider_DragCompleted; } } } public override string ToString() { return this.LowerValue.ToString() + "-" + this.HigherValue.ToString(); } #endregion Override #region Methods internal static double GetThumbWidth( Slider slider ) { if( slider != null ) { var track = (Track)slider.Template.FindName( "PART_Track", slider ); if( track != null ) { var thumb = track.Thumb; return thumb.ActualWidth; } } return 0d; } internal static double GetThumbHeight( Slider slider ) { if( slider != null ) { var track = (Track)slider.Template.FindName( "PART_Track", slider ); if( track != null ) { var thumb = track.Thumb; return thumb.ActualHeight; } } return 0d; } private void AdjustView() { //Coerce values to make them consistent. var cv = this.GetCoercedValues(); double actualWidth = 0; double lowerSliderThumbWidth = 0d; double higherSliderThumbWidth = 0d; if( this.Orientation == Orientation.Horizontal ) { actualWidth = this.ActualWidth; lowerSliderThumbWidth = RangeSlider.GetThumbWidth( _lowerSlider ); higherSliderThumbWidth = RangeSlider.GetThumbWidth( _higherSlider ); } else if( this.Orientation == Orientation.Vertical ) { actualWidth = this.ActualHeight; lowerSliderThumbWidth = RangeSlider.GetThumbHeight( _lowerSlider ); higherSliderThumbWidth = RangeSlider.GetThumbHeight( _higherSlider ); } actualWidth -= (lowerSliderThumbWidth + higherSliderThumbWidth); this.SetLowerSliderValues( cv.LowerValue, cv.Minimum, cv.Maximum ); this.SetHigherSliderValues( cv.HigherValue, cv.Minimum, cv.Maximum ); double entireRange = cv.Maximum - cv.Minimum; if( entireRange > 0 ) { this.HigherRangeWidth = (actualWidth * (cv.Maximum - cv.HigherValue)) / entireRange; this.RangeWidth = (actualWidth * (cv.HigherValue - cv.LowerValue)) / entireRange; this.LowerRangeWidth = (actualWidth * (cv.LowerValue - cv.Minimum)) / entireRange; } else { this.HigherRangeWidth = 0d; this.RangeWidth = 0d; this.LowerRangeWidth = actualWidth; } } private void SetSlidersMargins() { if( (_lowerSlider != null) && (_higherSlider != null) ) { if( this.Orientation == Orientation.Horizontal ) { double lowerSliderThumbWidth = RangeSlider.GetThumbWidth( _lowerSlider ); double higherSliderThumbWidth = RangeSlider.GetThumbWidth( _higherSlider ); _higherSlider.Margin = new Thickness( lowerSliderThumbWidth, 0d, 0d, 0d ); _lowerSlider.Margin = new Thickness( 0d, 0d, higherSliderThumbWidth, 0d ); } else { double lowerSliderThumbHeight = RangeSlider.GetThumbHeight( _lowerSlider ); double higherSliderThumbHeight = RangeSlider.GetThumbHeight( _higherSlider ); _higherSlider.Margin = new Thickness( 0d, 0d, 0d, lowerSliderThumbHeight ); _lowerSlider.Margin = new Thickness( 0d, higherSliderThumbHeight, 0d, 0d ); } } } private CoercedValues GetCoercedValues() { CoercedValues cv = new CoercedValues(); cv.Minimum = Math.Min( this.Minimum, this.Maximum ); cv.Maximum = Math.Max( cv.Minimum, this.Maximum ); cv.LowerValue = Math.Max( cv.Minimum, Math.Min( cv.Maximum, this.LowerValue ) ); cv.HigherValue = Math.Max( cv.Minimum, Math.Min( cv.Maximum, this.HigherValue ) ); cv.HigherValue = Math.Max( cv.LowerValue, cv.HigherValue ); return cv; } private void SetLowerSliderValues( double value, double? minimum, double? maximum ) { this.SetSliderValues( _lowerSlider, this.LowerSlider_ValueChanged, value, minimum, maximum ); } private void SetHigherSliderValues( double value, double? minimum, double? maximum ) { this.SetSliderValues( _higherSlider, this.HigherSlider_ValueChanged, value, minimum, maximum ); } private void SetSliderValues( Slider slider, RoutedPropertyChangedEventHandler handler, double value, double? minimum, double? maximum ) { if( slider != null ) { slider.ValueChanged -= handler; slider.Value = value; if( minimum != null ) { slider.Minimum = minimum.Value; } if( maximum != null ) { slider.Maximum = maximum.Value; } slider.ValueChanged += handler; } } private void UpdateHigherValue( double value ) { CoercedValues cv = this.GetCoercedValues(); double newValue = Math.Max( cv.Minimum, Math.Min( cv.Maximum, value ) ); newValue = Math.Max( newValue, cv.LowerValue ); this.SetHigherSliderValues( newValue, null, null ); this.HigherValue = newValue; } private void UpdateLowerValue( double value ) { CoercedValues cv = this.GetCoercedValues(); double newValue = Math.Max( cv.Minimum, Math.Min( cv.Maximum, value ) ); newValue = Math.Min( newValue, cv.HigherValue ); this.SetLowerSliderValues( newValue, null, null ); this.LowerValue = newValue; } #endregion #region Events public static readonly RoutedEvent LowerValueChangedEvent = EventManager.RegisterRoutedEvent( "LowerValueChanged", RoutingStrategy.Bubble, typeof( RoutedEventHandler ), typeof( RangeSlider ) ); public event RoutedEventHandler LowerValueChanged { add { AddHandler( RangeSlider.LowerValueChangedEvent, value ); } remove { RemoveHandler( RangeSlider.LowerValueChangedEvent, value ); } } public static readonly RoutedEvent HigherValueChangedEvent = EventManager.RegisterRoutedEvent( "HigherValueChanged", RoutingStrategy.Bubble, typeof( RoutedEventHandler ), typeof( RangeSlider ) ); public event RoutedEventHandler HigherValueChanged { add { AddHandler( RangeSlider.HigherValueChangedEvent, value ); } remove { RemoveHandler( RangeSlider.HigherValueChangedEvent, value ); } } #endregion //Events #region Events Handlers private void LowerRange_Click( object sender, RoutedEventArgs e ) { CoercedValues cv = this.GetCoercedValues(); //When Maximum is not greater than Minimum, the //slider display is in an inconsistant state. Don't //consider any operation from the user if( cv.Minimum < cv.Maximum ) { double newValue = cv.LowerValue - this.Step; this.LowerValue = Math.Min( cv.Maximum, Math.Max( cv.Minimum, newValue ) ); } } private void HigherRange_Click( object sender, RoutedEventArgs e ) { CoercedValues cv = this.GetCoercedValues(); //When Maximum is not greater than Minimum, the //slider display is in an inconsistant state. Don't //consider any operation from the user if( cv.Minimum < cv.Maximum ) { double newValue = cv.HigherValue + this.Step; this.HigherValue = Math.Min( cv.Maximum, Math.Max( cv.Minimum, newValue ) ); } } private void RangeSlider_SizeChanged( object sender, SizeChangedEventArgs e ) { this.AdjustView(); } private void Slider_Loaded( object sender, RoutedEventArgs e ) { this.SetSlidersMargins(); this.AdjustView(); } private void LowerSlider_ValueChanged( object sender, RoutedPropertyChangedEventArgs e ) { if( _lowerSlider.IsLoaded ) { if( !this.IsDeferredUpdateValues ) { this.UpdateLowerValue( e.NewValue ); } else { _deferredUpdateValue = e.NewValue; } } } private void HigherSlider_ValueChanged( object sender, RoutedPropertyChangedEventArgs e ) { if( _higherSlider.IsLoaded ) { if( !this.IsDeferredUpdateValues ) { this.UpdateHigherValue( e.NewValue ); } else { _deferredUpdateValue = e.NewValue; } } } private void HigherSlider_DragCompleted( object sender, DragCompletedEventArgs e ) { if( this.IsDeferredUpdateValues ) { this.UpdateHigherValue( _deferredUpdateValue ); } } private void LowerSlider_DragCompleted( object sender, DragCompletedEventArgs e ) { if( this.IsDeferredUpdateValues ) { this.UpdateLowerValue( _deferredUpdateValue ); } } #endregion Events Handlers private struct CoercedValues { public double Minimum; public double Maximum; public double LowerValue; public double HigherValue; } } }