Wpf AvalonControls RangeSlaider内存泄漏(DependencyPropertyDescriptor…AddValueChanged)

Wpf AvalonControls RangeSlaider内存泄漏(DependencyPropertyDescriptor…AddValueChanged),wpf,memory,memory-leaks,Wpf,Memory,Memory Leaks,我一直在使用AvalonControls RangeSloider,在数据模板中使用时发现了相当多的内存泄漏。我对此进行了研究,得出以下结论: DependencyPropertyDescriptor.FromProperty(ActualWidthProperty, typeof(RangeSlider)). RemoveValueChanged(this, delegate { ReCalculateWidths(); }); 这就是说,我不明白RangeS

我一直在使用AvalonControls RangeSloider,在数据模板中使用时发现了相当多的内存泄漏。我对此进行了研究,得出以下结论:

    DependencyPropertyDescriptor.FromProperty(ActualWidthProperty, typeof(RangeSlider)).
            RemoveValueChanged(this, delegate { ReCalculateWidths(); });
这就是说,我不明白RangeSlaider类在哪里适用于RemoveValue更改,我认为这将解决此泄漏。应该注意的是,我在选项卡上使用带有DataTemplate/ItemsTemplate的控件

下面是课程(我为冗长的片段道歉)。非常感谢您的指导

{
    #region Data members
    bool internalUpdate = false;
    const double RepeatButtonMoveRatio = 0.1;//used to move the selection by x ratio when click the repeat buttons
    const double DefaultSplittersThumbWidth = 10;
    Thumb centerThumb; //the center thumb to move the range around
    Thumb leftThumb;//the left thumb that is used to expand the range selected
    Thumb rightThumb;//the right thumb that is used to expand the range selected
    RepeatButton leftButton;//the left side of the control (movable left part)
    RepeatButton rightButton;//the right side of the control (movable right part)
    StackPanel visualElementsContainer;//stackpanel to store the visual elements for this control
    #endregion

    #region properties and events

    /// <summary>
    /// The min value for the range of the range slider
    /// </summary>
    public long RangeStart
    {
        get { return (long)GetValue(RangeStartProperty); }
        set { SetValue(RangeStartProperty, value); }
    }

    /// <summary>
    /// The min value for the range of the range slider
    /// </summary>
    public static readonly DependencyProperty RangeStartProperty =
        DependencyProperty.Register("RangeStart", typeof(long), typeof(RangeSlider),
        new UIPropertyMetadata((long)0,
            delegate(DependencyObject sender, DependencyPropertyChangedEventArgs e)
            {
                RangeSlider slider = (RangeSlider)sender;
                if (!slider.internalUpdate)//check if the property is set internally
                {
                    slider.ReCalculateRanges();
                    slider.ReCalculateWidths();
                }
            }));


    /// <summary>
    /// The max value for the range of the range slider
    /// </summary>
    public long RangeStop
    {
        get { return (long)GetValue(RangeStopProperty); }
        set { SetValue(RangeStopProperty, value); }
    }

    /// <summary>
    /// The max value for the range of the range slider
    /// </summary>
    public static readonly DependencyProperty RangeStopProperty =
        DependencyProperty.Register("RangeStop", typeof(long), typeof(RangeSlider),
        new UIPropertyMetadata((long)1,
            delegate(DependencyObject sender, DependencyPropertyChangedEventArgs e)
            {
                RangeSlider slider = (RangeSlider)sender;
                if (!slider.internalUpdate)//check if the property is set internally
                {
                    slider.ReCalculateRanges();
                    slider.ReCalculateWidths();
                }
            }));


    /// <summary>
    /// The min value of the selected range of the range slider
    /// </summary>
    public long RangeStartSelected
    {
        get { return (long)GetValue(RangeStartSelectedProperty); }
        set { SetValue(RangeStartSelectedProperty, value); }
    }

    /// <summary>
    /// The min value of the selected range of the range slider
    /// </summary>
    public static readonly DependencyProperty RangeStartSelectedProperty =
        DependencyProperty.Register("RangeStartSelected", typeof(long), typeof(RangeSlider),
        new UIPropertyMetadata((long)0,
            delegate(DependencyObject sender, DependencyPropertyChangedEventArgs e)
            {
                RangeSlider slider = (RangeSlider)sender;
                if (!slider.internalUpdate)//check if the property is set internally
                {
                    slider.ReCalculateWidths();
                    slider.OnRangeSelectionChanged(new RangeSelectionChangedEventArgs(slider));
                }
            }));


    /// <summary>
    /// The max value of the selected range of the range slider
    /// </summary>
    public long RangeStopSelected
    {
        get { return (long)GetValue(RangeStopSelectedProperty); }
        set { SetValue(RangeStopSelectedProperty, value); }
    }

    /// <summary>
    /// The max value of the selected range of the range slider
    /// </summary>
    public static readonly DependencyProperty RangeStopSelectedProperty =
        DependencyProperty.Register("RangeStopSelected", typeof(long), typeof(RangeSlider),
        new UIPropertyMetadata((long)1,
            delegate(DependencyObject sender, DependencyPropertyChangedEventArgs e)
            {
                RangeSlider slider = (RangeSlider)sender;
                if (!slider.internalUpdate)//check if the property is set internally
                {
                    slider.ReCalculateWidths();
                    slider.OnRangeSelectionChanged(new RangeSelectionChangedEventArgs(slider));
                }
            }));


    /// <summary>
    /// The min range value that you can have for the range slider
    /// </summary>
    /// <exception cref="ArgumentOutOfRangeException">Thrown when MinRange is set less than 0</exception>
    public long MinRange
    {
        get { return (long)GetValue(MinRangeProperty); }
        set { SetValue(MinRangeProperty, value); }
    }

    /// <summary>
    /// The min range value that you can have for the range slider
    /// </summary>
    /// <exception cref="ArgumentOutOfRangeException">Thrown when MinRange is set less than 0</exception>
    public static readonly DependencyProperty MinRangeProperty =
        DependencyProperty.Register("MinRange", typeof(long), typeof(RangeSlider),
        new UIPropertyMetadata((long)0,
            delegate(DependencyObject sender, DependencyPropertyChangedEventArgs e)
            {
                if ((long)e.NewValue < 0)
                    throw new ArgumentOutOfRangeException("value", "value for MinRange cannot be less than 0");

                RangeSlider slider = (RangeSlider)sender;
                if (!slider.internalUpdate)//check if the property is set internally
                {
                    slider.internalUpdate = true;//set flag to signal that the properties are being set by the object itself
                    slider.RangeStopSelected = Math.Max(slider.RangeStopSelected, slider.RangeStartSelected + (long)e.NewValue);
                    slider.RangeStop = Math.Max(slider.RangeStop, slider.RangeStopSelected);
                    slider.internalUpdate = false;//set flag to signal that the properties are being set by the object itself

                    slider.ReCalculateRanges();
                    slider.ReCalculateWidths();
                }
            }));

    /// <summary>
    /// Event raised whenever the selected range is changed
    /// </summary>
    public static readonly RoutedEvent RangeSelectionChangedEvent =
        EventManager.RegisterRoutedEvent("RangeSelectionChanged",
        RoutingStrategy.Bubble, typeof(RangeSelectionChangedEventHandler), typeof(RangeSlider));

    /// <summary>
    /// Event raised whenever the selected range is changed
    /// </summary>
    public event RangeSelectionChangedEventHandler RangeSelectionChanged
    {
        add { AddHandler(RangeSelectionChangedEvent, value); }
        remove { RemoveHandler(RangeSelectionChangedEvent, value); }
    }


    #endregion

    #region Commands

    /// <summary>
    /// Command to move back the selection
    /// </summary>
    public static RoutedUICommand MoveBack =
        new RoutedUICommand("MoveBack", "MoveBack", typeof(RangeSlider),
            new InputGestureCollection(new InputGesture[] {
                new KeyGesture(Key.B, ModifierKeys.Control)
            }));

    /// <summary>
    /// Command to move forward the selection
    /// </summary>
    public static RoutedUICommand MoveForward =
        new RoutedUICommand("MoveForward", "MoveForward", typeof(RangeSlider),
            new InputGestureCollection(new InputGesture[] {
                new KeyGesture(Key.F, ModifierKeys.Control)
            }));

    /// <summary>
    /// Command to move all forward the selection
    /// </summary>
    public static RoutedUICommand MoveAllForward =
        new RoutedUICommand("MoveAllForward", "MoveAllForward", typeof(RangeSlider),
            new InputGestureCollection(new InputGesture[] {
                new KeyGesture(Key.F, ModifierKeys.Alt)
            }));

    /// <summary>
    /// Command to move all back the selection
    /// </summary>
    public static RoutedUICommand MoveAllBack =
        new RoutedUICommand("MoveAllBack", "MoveAllBack", typeof(RangeSlider),
            new InputGestureCollection(new InputGesture[] {
                new KeyGesture(Key.B, ModifierKeys.Alt)
            }));

    #endregion

    /// <summary>
    /// Default constructor
    /// </summary>
    public RangeSlider()
    {
        CommandBindings.Add(new CommandBinding(MoveBack, MoveBackHandler));
        CommandBindings.Add(new CommandBinding(MoveForward, MoveForwardHandler));
        CommandBindings.Add(new CommandBinding(MoveAllForward, MoveAllForwardHandler));
        CommandBindings.Add(new CommandBinding(MoveAllBack, MoveAllBackHandler));

        //hook to the size change event of the range slider
        DependencyPropertyDescriptor.FromProperty(ActualWidthProperty, typeof(RangeSlider)).
            AddValueChanged(this, delegate { ReCalculateWidths(); });

    }


    /// <summary>
    /// Static constructor
    /// </summary>
    static RangeSlider()
    {
        DefaultStyleKeyProperty.OverrideMetadata(
            typeof(RangeSlider), new FrameworkPropertyMetadata(typeof(RangeSlider))
            );
    }

    #region Command handlers

    void MoveAllBackHandler(object sender, ExecutedRoutedEventArgs e)
    {
        ResetSelection(true);
    }

    void MoveAllForwardHandler(object sender, ExecutedRoutedEventArgs e)
    {
        ResetSelection(false);
    }

    void MoveBackHandler(object sender, ExecutedRoutedEventArgs e)
    {
        MoveSelection(true);
    }

    void MoveForwardHandler(object sender, ExecutedRoutedEventArgs e)
    {
        MoveSelection(false);
    }
    #endregion

    #region event handlers for visual elements to drag the range
    //drag thumb from the right splitter
    private void RightThumbDragDelta(object sender, DragDeltaEventArgs e)
    {
        MoveThumb(centerThumb, rightButton, e.HorizontalChange);
        ReCalculateRangeSelected(false, true);
    }

    //drag thumb from the left splitter
    private void LeftThumbDragDelta(object sender, DragDeltaEventArgs e)
    {
        MoveThumb(leftButton, centerThumb, e.HorizontalChange);
        ReCalculateRangeSelected(true, false);
    }

    //left repeat button clicked
    private void LeftButtonClick(object sender, RoutedEventArgs e)
    {
        MoveSelection(true);
    }
    //right repeat button clicked
    private void RightButtonClick(object sender, RoutedEventArgs e)
    {

        MoveSelection(false);
    }

    //drag thumb from the middle
    private void CenterThumbDragDelta(object sender, DragDeltaEventArgs e)
    {
        MoveThumb(leftButton, rightButton, e.HorizontalChange);
        ReCalculateRangeSelected(true, true);
    }
    #endregion

    #region logic to resize range
    //resizes the left column and the right column
    private static void MoveThumb(FrameworkElement x, FrameworkElement y, double horizonalChange)
    {
        double change = 0;
        if (horizonalChange < 0) //slider went left
            change = GetChangeKeepPositive(x.Width, horizonalChange);
        else if (horizonalChange > 0) //slider went right if(horizontal change == 0 do nothing)
            change = -GetChangeKeepPositive(y.Width, -horizonalChange);

        x.Width += change;
        y.Width -= change;
    }

    //ensures that the new value (newValue param) is a valid value. returns false if not
    private static double GetChangeKeepPositive(double width, double increment)
    {
        return Math.Max(width + increment, 0) - width;
    }
    #endregion

    #region logic to calculate the range
    long movableRange = 0;
    double movableWidth = 0;

    //recalculates the movableRange. called from the RangeStop setter, RangeStart setter and MinRange setter
    private void ReCalculateRanges()
    {
        movableRange = RangeStop - RangeStart - MinRange;
    }

    //recalculates the movableWidth. called whenever the width of the control changes
    private void ReCalculateWidths()
    {

       if (leftButton != null && rightButton != null && centerThumb != null)
        {
            movableWidth = Math.Max(ActualWidth - rightThumb.ActualWidth - leftThumb.ActualWidth - centerThumb.MinWidth, 1);
            leftButton.Width = Math.Max(movableWidth * (RangeStartSelected - RangeStart) / movableRange, 0);
            rightButton.Width = Math.Max(movableWidth * (RangeStop - RangeStopSelected) / movableRange, 0);
            centerThumb.Width = Math.Max(ActualWidth - leftButton.Width - rightButton.Width - rightThumb.ActualWidth - leftThumb.ActualWidth, 0);
        }
    }

    //recalculates the rangeStartSelected called when the left thumb is moved and when the middle thumb is moved
    //recalculates the rangeStopSelected called when the right thumb is moved and when the middle thumb is moved
    private void ReCalculateRangeSelected(bool reCalculateStart, bool reCalculateStop)
    {
        internalUpdate = true;//set flag to signal that the properties are being set by the object itself
        if (reCalculateStart)
        {
            // Make sure to get exactly rangestart if thumb is at the start
            if (leftButton.Width == 0.0)
                RangeStartSelected = RangeStart;
            else
                RangeStartSelected =
                    Math.Max(RangeStart, (long)(RangeStart + movableRange * leftButton.Width / movableWidth));
        }

        if (reCalculateStop)
        {
            // Make sure to get exactly rangestop if thumb is at the end
            if (rightButton.Width == 0.0)
                RangeStopSelected = RangeStop;
            else
                RangeStopSelected =
                    Math.Min(RangeStop, (long)(RangeStop - movableRange * rightButton.Width / movableWidth));
        }

        internalUpdate = false;//set flag to signal that the properties are being set by the object itself

        if (reCalculateStart || reCalculateStop)
            //raise the RangeSelectionChanged event
            OnRangeSelectionChanged(new RangeSelectionChangedEventArgs(this));
    }

    /// <summary>
    /// moves the current selection with x value
    /// </summary>
    /// <param name="isLeft">True if you want to move to the left</param>
    public void MoveSelection(bool isLeft)
    {
        double widthChange = RepeatButtonMoveRatio * (RangeStopSelected - RangeStartSelected)
            * movableWidth / movableRange;

        widthChange = isLeft ? -widthChange : widthChange;
        MoveThumb(leftButton, rightButton, widthChange);
        ReCalculateRangeSelected(true, true);
    }

    /// <summary>
    /// Reset the Slider to the Start/End
    /// </summary>
    /// <param name="isStart">Pass true to reset to start point</param>
    public void ResetSelection(bool isStart)
    {
        double widthChange = RangeStop - RangeStart;
        widthChange = isStart ? -widthChange : widthChange;

        MoveThumb(leftButton, rightButton, widthChange);
        ReCalculateRangeSelected(true, true);
    }

    ///<summary>
    /// Change the range selected 
    ///</summary>
    ///<param name="span">The steps</param>
    public void MoveSelection(long span)
    {
        if (span > 0)
        {
            if (RangeStopSelected + span > RangeStop)
                span = RangeStop - RangeStopSelected;
        }
        else
        {
            if (RangeStartSelected + span < RangeStart)
                span = RangeStart - RangeStartSelected;
        }

        if (span != 0)
        {
            internalUpdate = true;//set flag to signal that the properties are being set by the object itself
            RangeStartSelected += span;
            RangeStopSelected += span;
            ReCalculateWidths();
            internalUpdate = false;//set flag to signal that the properties are being set by the object itself

            OnRangeSelectionChanged(new RangeSelectionChangedEventArgs(this));
        }
    }

    /// <summary>
    /// Sets the selected range in one go. If the selection is invalid, nothing happens.
    /// </summary>
    /// <param name="selectionStart">New selection start value</param>
    /// <param name="selectionStop">New selection stop value</param>
    public void SetSelectedRange(long selectionStart, long selectionStop)
    {
        long start = Math.Max(RangeStart, selectionStart);
        long stop = Math.Min(selectionStop, RangeStop);
        start = Math.Min(start, RangeStop - MinRange);
        stop = Math.Max(RangeStart + MinRange, stop);
        if (stop >= start + MinRange)
        {
            internalUpdate = true;//set flag to signal that the properties are being set by the object itself
            RangeStartSelected = start;
            RangeStopSelected = stop;
            ReCalculateWidths();
            internalUpdate = false;//set flag to signal that the properties are being set by the object itself
            OnRangeSelectionChanged(new RangeSelectionChangedEventArgs(this));
        }
    }

    /// <summary>
    /// Changes the selected range to the supplied range
    /// </summary>
    /// <param name="span">The span to zoom</param>
    public void ZoomToSpan(long span)
    {
        internalUpdate = true;//set flag to signal that the properties are being set by the object itself
        // Ensure new span is within the valid range
        span = Math.Min(span, RangeStop - RangeStart);
        span = Math.Max(span, MinRange);
        if (span == RangeStopSelected - RangeStartSelected)
            return; // No change

        // First zoom half of it to the right
        long rightChange = (span - (RangeStopSelected - RangeStartSelected)) / 2;
        long leftChange = rightChange;

        // If we will hit the right edge, spill over the leftover change to the other side
        if (rightChange > 0 && RangeStopSelected + rightChange > RangeStop)
            leftChange += rightChange - (RangeStop - RangeStopSelected);
        RangeStopSelected = Math.Min(RangeStopSelected + rightChange, RangeStop);
        rightChange = 0;

        // If we will hit the left edge and there is space on the right, add the leftover change to the other side
        if (leftChange > 0 && RangeStartSelected - leftChange < RangeStart)
            rightChange = RangeStart - (RangeStartSelected - leftChange);
        RangeStartSelected = Math.Max(RangeStartSelected - leftChange, RangeStart);
        if (rightChange > 0) // leftovers to the right
            RangeStopSelected = Math.Min(RangeStopSelected + rightChange, RangeStop);

        ReCalculateWidths();
        internalUpdate = false;//set flag to signal that the properties are being set by the object itself
        OnRangeSelectionChanged(new RangeSelectionChangedEventArgs(this));
    }
    #endregion

    //Raises the RangeSelectionChanged event
    private void OnRangeSelectionChanged(RangeSelectionChangedEventArgs e)
    {
        e.RoutedEvent = RangeSelectionChangedEvent;
        RaiseEvent(e);
    }

    /// <summary>
    /// Overide to get the visuals from the control template
    /// </summary>
    public override void OnApplyTemplate()
    {
        base.OnApplyTemplate();

        visualElementsContainer = EnforceInstance<StackPanel>("PART_RangeSliderContainer");
        centerThumb = EnforceInstance<Thumb>("PART_MiddleThumb");
        leftButton = EnforceInstance<RepeatButton>("PART_LeftEdge");
        rightButton = EnforceInstance<RepeatButton>("PART_RightEdge");
        leftThumb = EnforceInstance<Thumb>("PART_LeftThumb");
        rightThumb = EnforceInstance<Thumb>("PART_RightThumb");
        InitializeVisualElementsContainer();
        ReCalculateWidths();
    }

    #region Helper
    T EnforceInstance<T>(string partName)
        where T : FrameworkElement, new()
    {
        T element = GetTemplateChild(partName) as T;
        if (element == null)
            element = new T();
        return element;
    }

    //adds all visual element to the conatiner
    private void InitializeVisualElementsContainer()
    {
        visualElementsContainer.Orientation = Orientation.Horizontal;
        leftThumb.Width = DefaultSplittersThumbWidth;
        leftThumb.Tag = "left";
        rightThumb.Width = DefaultSplittersThumbWidth;
        rightThumb.Tag = "right";

        //handle the drag delta
        centerThumb.DragDelta += CenterThumbDragDelta;
        leftThumb.DragDelta += LeftThumbDragDelta;
        rightThumb.DragDelta += RightThumbDragDelta;
        leftButton.Click += LeftButtonClick;
        rightButton.Click += RightButtonClick;

    }
    #endregion
}

/// <summary>
/// Delegate for the RangeSelectionChanged event
/// </summary>
/// <param name="sender">The object raising the event</param>
/// <param name="e">The event arguments</param>
public delegate void RangeSelectionChangedEventHandler(object sender, RangeSelectionChangedEventArgs e);

/// <summary>
/// Event arguments for the Range slider RangeSelectionChanged event
/// </summary>
public class RangeSelectionChangedEventArgs : RoutedEventArgs
{
    private long newRangeStart;

    /// <summary>
    /// The new range start selected in the range slider
    /// </summary>
    public long NewRangeStart
    {
        get { return newRangeStart; }
        set { newRangeStart = value; }
    }

    private long newRangeStop;

    /// <summary>
    /// The new range stop selected in the range slider
    /// </summary>
    public long NewRangeStop
    {
        get { return newRangeStop; }
        set { newRangeStop = value; }
    }

    /// <summary>
    /// sets the range start and range stop for the event args
    /// </summary>
    /// <param name="newRangeStart">The new range start set</param>
    /// <param name="newRangeStop">The new range stop set</param>
    internal RangeSelectionChangedEventArgs(long newRangeStart, long newRangeStop)
    {
        this.newRangeStart = newRangeStart;
        this.newRangeStop = newRangeStop;
    }

    /// <summary>
    /// sets the range start and range stop for the event args by using the slider RangeStartSelected and RangeStopSelected properties
    /// </summary>
    /// <param name="slider">The slider to get the info from</param>
    internal RangeSelectionChangedEventArgs(RangeSlider slider)
        : this(slider.RangeStartSelected, slider.RangeStopSelected)
    { }





}
{
#区域数据成员
bool internalUpdate=false;
const double RepeatButton平均值=0.1;//用于在单击重复按钮时按x比例移动选择
const double DefaultSplittersThumbWidth=10;
Thumb centerThumb;//移动范围的中心拇指
Thumb leftThumb;//用于扩展选定范围的左拇指
Thumb rightThumb;//用于扩展选定范围的右拇指
RepeatButton leftButton;//控件的左侧(可移动的左侧部分)
RepeatButton rightButton;//控件的右侧(可移动的右侧部分)
StackPanel visualElementsContainer;//用于存储此控件的可视元素的StackPanel
#端区
#区域属性和事件
/// 
///范围滑块范围的最小值
/// 
公共远程启动
{
获取{return(long)GetValue(RangeStartProperty);}
set{SetValue(RangeStartProperty,value);}
}
/// 
///范围滑块范围的最小值
/// 
公共静态只读从属属性RangeStartProperty=
DependencyProperty.Register(“RangeStart”、typeof(long)、typeof(RangeSlaider),
新的UIPropertyMetadata((长)0,
委托(DependencyObject发送方,DependencyPropertyChangedEventArgs e)
{
范围滑块=(范围滑块)发送器;
if(!slider.internalUpdate)//检查属性是否在内部设置
{
slider.recreacteranges();
滑块。重新计算宽度();
}
}));
/// 
///范围滑块范围的最大值
/// 
公共长途站
{
获取{return(long)GetValue(RangeStopProperty);}
set{SetValue(RangeStopProperty,value);}
}
/// 
///范围滑块范围的最大值
/// 
公共静态只读从属属性RangeStopProperty=
DependencyProperty.寄存器(“RangeStop”、typeof(长)、typeof(RangeSlaider),
新UIPropertyMetadata((长)1,
委托(DependencyObject发送方,DependencyPropertyChangedEventArgs e)
{
范围滑块=(范围滑块)发送器;
if(!slider.internalUpdate)//检查属性是否在内部设置
{
slider.recreacteranges();
滑块。重新计算宽度();
}
}));
/// 
///范围滑块选定范围的最小值
/// 
已选择公共远程启动
{
获取{return(long)GetValue(RangeStartSelectedProperty);}
set{SetValue(RangeStartSelectedProperty,value);}
}
/// 
///范围滑块选定范围的最小值
/// 
公共静态只读从属属性RangeStartSelectedProperty=
DependencyProperty.Register(“RangeStartSelected”、typeof(long)、typeof(RangeSlaider),
新的UIPropertyMetadata((长)0,
委托(DependencyObject发送方,DependencyPropertyChangedEventArgs e)
{
范围滑块=(范围滑块)发送器;
if(!slider.internalUpdate)//检查属性是否在内部设置
{
滑块。重新计算宽度();
slider.OnRangeSelectionChanged(新的RangeSelectionChangedEventArgs(slider));
}
}));
/// 
///范围滑块选定范围的最大值
/// 
选择公共长距离停车场
{
获取{return(long)GetValue(RangeStopSelectedProperty);}
set{SetValue(RangeStopSelectedProperty,value);}
}
/// 
///范围滑块选定范围的最大值
/// 
公共静态只读从属属性RangeStopSelectedProperty=
DependencyProperty.Register(“RangeStopSelected”、typeof(long)、typeof(RangeSlaider),
新UIPropertyMetadata((长)1,
委托(DependencyObject发送方,DependencyPropertyChangedEventArgs e)
{
范围滑块=(范围滑块)发送器;
if(!slider.internalUpdate)//检查属性是否在内部设置
{
滑块。重新计算宽度();
slider.OnRangeSelectionChanged(新的RangeSelectionChangedEventArgs(slider));
}
}));
/// 
///可用于范围滑块的最小范围值
/// 
///当MinRange设置为小于0时引发
公共长途电话
{
获取{return(long)GetValue(MinRangeProperty);}
set{SetValue(MinRangeProperty,value);}
}
/// 
///可用于范围滑块的最小范围值
/// 
///当MinRange设置为小于0时引发
公共静态只读从属属性MinRangeProperty=
DependencyProperty.Register(“MinRange”、typeof(long)、typeof(RangeSlider),
新的UIPropertyMetadata((长)0,
委托(DependencyObject发送方,DependencyPropertyChangedEventArgs e)
{
如果((长)e.NewValue<0)
抛出新ArgumentOutOfRangeException(“值”,“MinRange的值不能小于0”);
范围滑块sl