Code:
/ Net / Net / 3.5.50727.3053 / DEVDIV / depot / DevDiv / releases / Orcas / SP / wpf / src / Framework / System / Windows / Controls / Primitives / Track.cs / 3 / Track.cs
//---------------------------------------------------------------------------- // // Copyright (C) Microsoft Corporation. All rights reserved. // // File: Track.cs // // Description: Contains the Track class. // //--------------------------------------------------------------------------- using MS.Internal; using MS.Internal.KnownBoxes; using MS.Internal.PresentationFramework; using MS.Utility; using System.Collections; using System.ComponentModel; using System.Threading; using System.Windows.Automation; using System.Windows.Automation.Provider; using System.Windows.Controls; using System.Windows; using System.Windows.Data; using System.Windows.Media; using System.Windows.Markup; using System.Windows.Input; using System; using System.Diagnostics; namespace System.Windows.Controls.Primitives { ////// Track handles layout of the parts of a ScrollBar and Slider. /// [Localizability(LocalizationCategory.None, Readability = Readability.Unreadable)] // cannot be read & localized as string public class Track : FrameworkElement { //------------------------------------------------------------------- // // Constructors // //------------------------------------------------------------------- #region Constructors static Track() { } ////// Default DependencyObject constructor /// public Track() : base() { } #endregion //-------------------------------------------------------------------- // // Public Methods // //------------------------------------------------------------------- #region Public Methods ////// Calculate the value from given Point. The input point is relative to TopLeft conner of Track. /// /// Point (in Track's co-ordinate). public virtual double ValueFromPoint(Point pt) { double val; // Find distance from center of thumb to given point. if (Orientation == Orientation.Horizontal) { val = Value + ValueFromDistance(pt.X - ThumbCenterOffset, pt.Y - (RenderSize.Height * 0.5)); } else { val = Value + ValueFromDistance(pt.X - (RenderSize.Width * 0.5), pt.Y - ThumbCenterOffset); } return Math.Max(Minimum, Math.Min(Maximum, val)); } ////// This function returns the delta in value that would be caused by moving the thumb the given pixel distances. /// The returned delta value is not guaranteed to be inside the valid Value range. /// /// Total horizontal distance that the Thumb has moved. /// Total vertical distance that the Thumb has moved. public virtual double ValueFromDistance(double horizontal, double vertical) { double scale = IsDirectionReversed ? -1 : 1; // // Note: To implement 'Snap-Back' feature, we could check whether the point is far away from center of the track. // If so, just return current value (this should move the Thumb back to its original localtion). // if (Orientation == Orientation.Horizontal) { return scale * horizontal * Density; } else { // Increases in y cause decreases in Sliders value return -1 * scale * vertical * Density; } } #endregion //-------------------------------------------------------------------- // // Public Properties // //-------------------------------------------------------------------- #region Public Properties private void UpdateComponent(Control oldValue, Control newValue) { if (oldValue != newValue) { if (_visualChildren == null) { _visualChildren = new Visual[3]; } if (oldValue != null) { // notify the visual layer that the old component has been removed. RemoveVisualChild(oldValue); } // Remove the old value from our z index list and add new value to end int i = 0; while (i < 3) { // Array isn't full, break if (_visualChildren[i] == null) break; // found the old value if (_visualChildren[i] == oldValue) { // Move values down until end of array or a null element while (i < 2 && _visualChildren[i + 1] != null) { _visualChildren[i] = _visualChildren[i + 1]; i++; } } else { i++; } } // Add newValue at end of z-order _visualChildren[i] = newValue; AddVisualChild(newValue); InvalidateMeasure(); InvalidateArrange(); } } ////// The RepeatButton used to decrease the Value /// public RepeatButton DecreaseRepeatButton { get { return _decreaseButton; } set { if (_increaseButton == value) { throw new NotSupportedException(SR.Get(SRID.Track_SameButtons)); } UpdateComponent(_decreaseButton, value); _decreaseButton = value; if (_decreaseButton != null) { CommandManager.InvalidateRequerySuggested(); // Should post an idle queue item to update IsEnabled on button } } } ////// The Thumb in the Track /// public Thumb Thumb { get { return _thumb; } set { UpdateComponent(_thumb, value); _thumb = value; } } ////// The RepeatButton used to increase the Value /// public RepeatButton IncreaseRepeatButton { get { return _increaseButton; } set { if (_decreaseButton == value) { throw new NotSupportedException(SR.Get(SRID.Track_SameButtons)); } UpdateComponent(_increaseButton, value); _increaseButton = value; if (_increaseButton != null) { CommandManager.InvalidateRequerySuggested(); // Should post an idle queue item to update IsEnabled on button } } } ////// DependencyProperty for [CommonDependencyProperty] public static readonly DependencyProperty OrientationProperty = DependencyProperty.Register("Orientation", typeof(Orientation), typeof(Track), new FrameworkPropertyMetadata(Orientation.Horizontal, FrameworkPropertyMetadataOptions.AffectsMeasure), new ValidateValueCallback(ScrollBar.IsValidOrientation)); ///property. /// /// This property represents the Track layout orientation: Vertical or Horizontal. /// On vertical ScrollBars, the thumb moves up and down. On horizontal bars, the thumb moves left to right. /// public Orientation Orientation { get { return (Orientation)GetValue(OrientationProperty); } set { SetValue(OrientationProperty, value); } } ////// DependencyProperty for [CommonDependencyProperty] public static readonly DependencyProperty MinimumProperty = RangeBase.MinimumProperty.AddOwner(typeof(Track), new FrameworkPropertyMetadata(0d, FrameworkPropertyMetadataOptions.AffectsArrange)); ///property. /// /// The Minimum value of the Slider or ScrollBar /// public double Minimum { get { return (double)GetValue(MinimumProperty); } set { SetValue(MinimumProperty, value); } } ////// DependencyProperty for [CommonDependencyProperty] public static readonly DependencyProperty MaximumProperty = RangeBase.MaximumProperty.AddOwner(typeof(Track), new FrameworkPropertyMetadata(1d, FrameworkPropertyMetadataOptions.AffectsArrange)); ///property. /// /// The Maximum value of the Slider or ScrollBar /// public double Maximum { get { return (double)GetValue(MaximumProperty); } set { SetValue(MaximumProperty, value); } } ////// DependencyProperty for [CommonDependencyProperty] public static readonly DependencyProperty ValueProperty = RangeBase.ValueProperty.AddOwner(typeof(Track), new FrameworkPropertyMetadata(0d, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault | FrameworkPropertyMetadataOptions.AffectsArrange)); ///property. /// /// The current value of the Slider or ScrollBar /// public double Value { get { return (double)GetValue(ValueProperty); } set { SetValue(ValueProperty, value); } } ////// DependencyProperty for [CommonDependencyProperty] public static readonly DependencyProperty ViewportSizeProperty = DependencyProperty.Register("ViewportSize", typeof(double), typeof(Track), new FrameworkPropertyMetadata(double.NaN, FrameworkPropertyMetadataOptions.AffectsArrange), new ValidateValueCallback(IsValidViewport)); ///property. /// /// ViewportSize is the amount of the scrolled extent currently visible. For most scrolled content, this value /// will be bound to one of public double ViewportSize { get { return (double)GetValue(ViewportSizeProperty); } set { SetValue(ViewportSizeProperty, value); } } private static bool IsValidViewport(object o) { double d = (double)o; return d >= 0.0 || double.IsNaN(d); } ///'s ViewportSize properties. /// This property is in logical scrolling units. /// /// Setting this value to NaN will turn off automatic sizing of the thumb /// /// DependencyProperty for [CommonDependencyProperty] public static readonly DependencyProperty IsDirectionReversedProperty = DependencyProperty.Register("IsDirectionReversed", typeof(bool), typeof(Track), new FrameworkPropertyMetadata(BooleanBoxes.FalseBox)); ///property. /// /// Indicates if the location of the DecreaseRepeatButton and IncreaseRepeatButton /// should be swapped. /// public bool IsDirectionReversed { get { return (bool)GetValue(IsDirectionReversedProperty); } set { SetValue(IsDirectionReversedProperty, value); } } #endregion //------------------------------------------------------------------- // // Protected Methods // //-------------------------------------------------------------------- #region Protected Methods ////// Derived class must implement to support Visual children. The method must return /// the child at the specified index. Index must be between 0 and GetVisualChildrenCount-1. /// /// By default a Visual does not have any children. /// /// Remark: /// During this virtual call it is not valid to modify the Visual tree. /// protected override Visual GetVisualChild(int index) { if (_visualChildren == null || _visualChildren[index] == null) { throw new ArgumentOutOfRangeException("index", index, SR.Get(SRID.Visual_ArgumentOutOfRange)); } return _visualChildren[index]; } ////// Derived classes override this property to enable the Visual code to enumerate /// the Visual children. Derived classes need to return the number of children /// from this method. /// /// By default a Visual does not have any children. /// /// Remark: During this virtual method the Visual tree must not be modified. /// protected override int VisualChildrenCount { get { if (_visualChildren == null || _visualChildren[0] == null) { Debug.Assert(_visualChildren == null || _visualChildren[1] == null, "Child[1] should be null if Child[0] == null)"); Debug.Assert(_visualChildren == null || _visualChildren[2] == null, "Child[2] should be null if Child[0] == null)"); return 0; } else if (_visualChildren[1] == null) { Debug.Assert(_visualChildren[2] == null, "Child[2] should be null if Child[1] == null)"); return 1; } else { return _visualChildren[2] == null ? 2 : 3; } } } ////// The desired size of a Track is the width (if vertically oriented) or height (if horizontally /// oriented) of the Thumb. /// /// When ViewportSize is NaN: /// The thumb is measured to find the other dimension. /// Otherwise: /// Zero size is returned; Track can scale to any size along its children. /// This means that it will occupy no space (and not display) unless made larger by a parent or specified size. /// protected override Size MeasureOverride(Size availableSize) { Size desiredSize = new Size(0.0, 0.0); // Only measure thumb // Repeat buttons will be sized based on thumb if (Thumb != null) { Thumb.Measure(availableSize); desiredSize = Thumb.DesiredSize; } if (!double.IsNaN(ViewportSize)) { // ScrollBar can shrink to 0 in the direction of scrolling if (Orientation == Orientation.Vertical) desiredSize.Height = 0.0; else desiredSize.Width = 0.0; } return desiredSize; } // Force length of one of track's pieces to be > 0 and less than tracklength private static void CoerceLength(ref double componentLength, double trackLength) { if (componentLength < 0) { componentLength = 0.0; } else if (componentLength > trackLength || double.IsNaN(componentLength)) { componentLength = trackLength; } } ////// /// Children will be stretched to fit horizontally (if vertically oriented) or vertically (if horizontally /// oriented). /// /// There are essentially three possible layout states: /// 1. The track is enabled and the thumb is proportionally sizing. /// 2. The track is enabled and the thumb has reached its minimum size. /// 3. The track is disabled or there is not enough room for the thumb. /// Track elements are not displayed, and will not be arranged. /// protected override Size ArrangeOverride(Size arrangeSize) { double decreaseButtonLength, thumbLength, increaseButtonLength; bool isVertical = (Orientation == Orientation.Vertical); double viewportSize = Math.Max(0.0, ViewportSize); // If viewport is NaN, compute thumb's size based on its desired size, // otherwise compute the thumb base on the viewport and extent properties if (double.IsNaN(viewportSize)) { ComputeSliderLengths(arrangeSize, isVertical, out decreaseButtonLength, out thumbLength, out increaseButtonLength); } else { // Don't arrange if there's not enough content or the track is too small if (!ComputeScrollBarLengths(arrangeSize, viewportSize, isVertical, out decreaseButtonLength, out thumbLength, out increaseButtonLength)) { return arrangeSize; } } // Layout the pieces of track Point offset = new Point(); Size pieceSize = arrangeSize; bool isDirectionReversed = IsDirectionReversed; if (isVertical) { // Vertical Normal : |Inc Button | // |Thumb | // |Dec Button | // Vertical Reversed : |Dec Button | // |Thumb | // |Inc Button | CoerceLength(ref decreaseButtonLength, arrangeSize.Height); CoerceLength(ref increaseButtonLength, arrangeSize.Height); CoerceLength(ref thumbLength, arrangeSize.Height); offset.Y = isDirectionReversed ? decreaseButtonLength + thumbLength : 0.0; pieceSize.Height = increaseButtonLength; if (IncreaseRepeatButton != null) IncreaseRepeatButton.Arrange(new Rect(offset, pieceSize)); offset.Y = isDirectionReversed ? 0.0 : increaseButtonLength + thumbLength; pieceSize.Height = decreaseButtonLength; if (DecreaseRepeatButton != null) DecreaseRepeatButton.Arrange(new Rect(offset, pieceSize)); offset.Y = isDirectionReversed ? decreaseButtonLength : increaseButtonLength; pieceSize.Height = thumbLength; if (Thumb != null) Thumb.Arrange(new Rect(offset, pieceSize)); ThumbCenterOffset = offset.Y + (thumbLength * 0.5); } else { // Horizontal Normal : |Dec Button |Thumb| Inc Button| // Horizontal Reversed : |Inc Button |Thumb| Dec Button| CoerceLength(ref decreaseButtonLength, arrangeSize.Width); CoerceLength(ref increaseButtonLength, arrangeSize.Width); CoerceLength(ref thumbLength, arrangeSize.Width); offset.X = isDirectionReversed ? increaseButtonLength + thumbLength : 0.0; pieceSize.Width = decreaseButtonLength; if (DecreaseRepeatButton != null) DecreaseRepeatButton.Arrange(new Rect(offset, pieceSize)); offset.X = isDirectionReversed ? 0.0 : decreaseButtonLength + thumbLength; pieceSize.Width = increaseButtonLength; if (IncreaseRepeatButton != null) IncreaseRepeatButton.Arrange(new Rect(offset, pieceSize)); offset.X = isDirectionReversed ? increaseButtonLength : decreaseButtonLength; pieceSize.Width = thumbLength; if (Thumb != null) Thumb.Arrange(new Rect(offset, pieceSize)); ThumbCenterOffset = offset.X + (thumbLength * 0.5); } return arrangeSize; } // Computes the length of the decrease button, thumb and increase button // Thumb's size is based on it's desired size private void ComputeSliderLengths(Size arrangeSize, bool isVertical, out double decreaseButtonLength, out double thumbLength, out double increaseButtonLength) { double min = Minimum; double range = Math.Max(0.0, Maximum - min); double offset = Math.Min(range, Value - min); double trackLength; // Compute thumb size if (isVertical) { trackLength = arrangeSize.Height; thumbLength = Thumb == null ? 0 : Thumb.DesiredSize.Height; } else { trackLength = arrangeSize.Width; thumbLength = Thumb == null ? 0 : Thumb.DesiredSize.Width; } CoerceLength(ref thumbLength, trackLength); double remainingTrackLength = trackLength - thumbLength; decreaseButtonLength = remainingTrackLength * offset / range; CoerceLength(ref decreaseButtonLength, remainingTrackLength); increaseButtonLength = remainingTrackLength - decreaseButtonLength; CoerceLength(ref increaseButtonLength, remainingTrackLength); Debug.Assert(decreaseButtonLength >= 0.0 && decreaseButtonLength <= remainingTrackLength, "decreaseButtonLength is outside bounds"); Debug.Assert(increaseButtonLength >= 0.0 && increaseButtonLength <= remainingTrackLength, "increaseButtonLength is outside bounds"); Density = range / remainingTrackLength; } // Computes the length of the decrease button, thumb and increase button // Thumb's size is based on viewport and extent // returns false if the track should be hidden private bool ComputeScrollBarLengths(Size arrangeSize, double viewportSize, bool isVertical, out double decreaseButtonLength, out double thumbLength, out double increaseButtonLength) { double min = Minimum; double range = Math.Max(0.0, Maximum - min); double offset = Math.Min(range, Value - min); Debug.Assert(DoubleUtil.GreaterThanOrClose(offset, 0.0), "Invalid offest (negative value)."); double extent = Math.Max(0.0, range) + viewportSize; double trackLength; // Compute thumb size double thumbMinLength; if (isVertical) { trackLength = arrangeSize.Height; // Try to use the apps resource if it exists, fall back to SystemParameters if it doesn't object buttonHeightResource = TryFindResource(SystemParameters.VerticalScrollBarButtonHeightKey); double buttonHeight = buttonHeightResource is double ? (double)buttonHeightResource : SystemParameters.VerticalScrollBarButtonHeight; thumbMinLength = Math.Floor(buttonHeight * 0.5); } else { trackLength = arrangeSize.Width; // Try to use the apps resource if it exists, fall back to SystemParameters if it doesn't object buttonWidthResource = TryFindResource(SystemParameters.HorizontalScrollBarButtonWidthKey); double buttonWidth = buttonWidthResource is double ? (double)buttonWidthResource : SystemParameters.HorizontalScrollBarButtonWidth; thumbMinLength = Math.Floor(buttonWidth * 0.5); } thumbLength = trackLength * viewportSize / extent; CoerceLength(ref thumbLength, trackLength); thumbLength = Math.Max(thumbMinLength, thumbLength); // If we don't have enough content to scroll, disable the track. bool notEnoughContentToScroll = DoubleUtil.LessThanOrClose(range, 0.0); bool thumbLongerThanTrack = thumbLength > trackLength; // if there's not enough content or the thumb is longer than the track, // hide the track and don't arrange the pieces if (notEnoughContentToScroll || thumbLongerThanTrack) { if (Visibility != Visibility.Hidden) { Visibility = Visibility.Hidden; } ThumbCenterOffset = Double.NaN; Density = Double.NaN; decreaseButtonLength = 0.0; increaseButtonLength = 0.0; return false; // don't arrange } else if (Visibility != Visibility.Visible) { Visibility = Visibility.Visible; } // Compute lengths of increase and decrease button double remainingTrackLength = trackLength - thumbLength; decreaseButtonLength = remainingTrackLength * offset / range; CoerceLength(ref decreaseButtonLength, remainingTrackLength); increaseButtonLength = remainingTrackLength - decreaseButtonLength; CoerceLength(ref increaseButtonLength, remainingTrackLength); Density = range / remainingTrackLength; return true; } // Bind track to templated parent private void BindToTemplatedParent(DependencyProperty target, DependencyProperty source) { if (!HasNonDefaultValue(target)) { Binding binding = new Binding(); binding.RelativeSource = RelativeSource.TemplatedParent; binding.Path = new PropertyPath(source); SetBinding(target, binding); } } // Bind thumb or repeat button to templated parent private void BindChildToTemplatedParent(FrameworkElement element, DependencyProperty target, DependencyProperty source) { if (element != null && !element.HasNonDefaultValue(target)) { Binding binding = new Binding(); binding.Source = this.TemplatedParent; binding.Path = new PropertyPath(source); element.SetBinding(target, binding); } } ////// /// Track automatically sets bindings to its templated parent /// to aid styling /// internal override void OnPreApplyTemplate() { base.OnPreApplyTemplate(); RangeBase rangeBase = TemplatedParent as RangeBase; if (rangeBase != null) { BindToTemplatedParent(MinimumProperty, RangeBase.MinimumProperty); BindToTemplatedParent(MaximumProperty, RangeBase.MaximumProperty); BindToTemplatedParent(ValueProperty, RangeBase.ValueProperty); // Setup ScrollBar specific bindings ScrollBar scrollBar = rangeBase as ScrollBar; if (scrollBar != null) { BindToTemplatedParent(ViewportSizeProperty, ScrollBar.ViewportSizeProperty); BindToTemplatedParent(OrientationProperty, ScrollBar.OrientationProperty); } else { // Setup Slider specific bindings Slider slider = rangeBase as Slider; if (slider != null) { BindToTemplatedParent(OrientationProperty, Slider.OrientationProperty); BindToTemplatedParent(IsDirectionReversedProperty, Slider.IsDirectionReversedProperty); BindChildToTemplatedParent(DecreaseRepeatButton, RepeatButton.DelayProperty, Slider.DelayProperty); BindChildToTemplatedParent(DecreaseRepeatButton, RepeatButton.IntervalProperty, Slider.IntervalProperty); BindChildToTemplatedParent(IncreaseRepeatButton, RepeatButton.DelayProperty, Slider.DelayProperty); BindChildToTemplatedParent(IncreaseRepeatButton, RepeatButton.IntervalProperty, Slider.IntervalProperty); } } } } #endregion //------------------------------------------------------------------- // // Private Methods // //------------------------------------------------------------------- #region Private Methods #endregion //------------------------------------------------------------------- // // Private Properties // //-------------------------------------------------------------------- #region Private Properties private double ThumbCenterOffset { get { return _thumbCenterOffset; } set { _thumbCenterOffset = value; } } private double Density { get { return _density; } set { _density = value; } } // // This property // 1. Finds the correct initial size for the _effectiveValues store on the current DependencyObject // 2. This is a performance optimization // internal override int EffectiveValuesInitialSize { get { return 28; } } #endregion //------------------------------------------------------------------- // // Private Fields // //-------------------------------------------------------------------- #region Private Fields private RepeatButton _increaseButton; private RepeatButton _decreaseButton; private Thumb _thumb; private Visual[] _visualChildren; // Density of scrolling units present in 1/96" of track (not thumb). Computed during ArrangeOverride. // Note that density default really *is* NaN. This corresponds to no track having been computed/displayed. private double _density = Double.NaN; private double _thumbCenterOffset = Double.NaN; #endregion } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved. //---------------------------------------------------------------------------- // // Copyright (C) Microsoft Corporation. All rights reserved. // // File: Track.cs // // Description: Contains the Track class. // //--------------------------------------------------------------------------- using MS.Internal; using MS.Internal.KnownBoxes; using MS.Internal.PresentationFramework; using MS.Utility; using System.Collections; using System.ComponentModel; using System.Threading; using System.Windows.Automation; using System.Windows.Automation.Provider; using System.Windows.Controls; using System.Windows; using System.Windows.Data; using System.Windows.Media; using System.Windows.Markup; using System.Windows.Input; using System; using System.Diagnostics; namespace System.Windows.Controls.Primitives { ////// Track handles layout of the parts of a ScrollBar and Slider. /// [Localizability(LocalizationCategory.None, Readability = Readability.Unreadable)] // cannot be read & localized as string public class Track : FrameworkElement { //------------------------------------------------------------------- // // Constructors // //------------------------------------------------------------------- #region Constructors static Track() { } ////// Default DependencyObject constructor /// public Track() : base() { } #endregion //-------------------------------------------------------------------- // // Public Methods // //------------------------------------------------------------------- #region Public Methods ////// Calculate the value from given Point. The input point is relative to TopLeft conner of Track. /// /// Point (in Track's co-ordinate). public virtual double ValueFromPoint(Point pt) { double val; // Find distance from center of thumb to given point. if (Orientation == Orientation.Horizontal) { val = Value + ValueFromDistance(pt.X - ThumbCenterOffset, pt.Y - (RenderSize.Height * 0.5)); } else { val = Value + ValueFromDistance(pt.X - (RenderSize.Width * 0.5), pt.Y - ThumbCenterOffset); } return Math.Max(Minimum, Math.Min(Maximum, val)); } ////// This function returns the delta in value that would be caused by moving the thumb the given pixel distances. /// The returned delta value is not guaranteed to be inside the valid Value range. /// /// Total horizontal distance that the Thumb has moved. /// Total vertical distance that the Thumb has moved. public virtual double ValueFromDistance(double horizontal, double vertical) { double scale = IsDirectionReversed ? -1 : 1; // // Note: To implement 'Snap-Back' feature, we could check whether the point is far away from center of the track. // If so, just return current value (this should move the Thumb back to its original localtion). // if (Orientation == Orientation.Horizontal) { return scale * horizontal * Density; } else { // Increases in y cause decreases in Sliders value return -1 * scale * vertical * Density; } } #endregion //-------------------------------------------------------------------- // // Public Properties // //-------------------------------------------------------------------- #region Public Properties private void UpdateComponent(Control oldValue, Control newValue) { if (oldValue != newValue) { if (_visualChildren == null) { _visualChildren = new Visual[3]; } if (oldValue != null) { // notify the visual layer that the old component has been removed. RemoveVisualChild(oldValue); } // Remove the old value from our z index list and add new value to end int i = 0; while (i < 3) { // Array isn't full, break if (_visualChildren[i] == null) break; // found the old value if (_visualChildren[i] == oldValue) { // Move values down until end of array or a null element while (i < 2 && _visualChildren[i + 1] != null) { _visualChildren[i] = _visualChildren[i + 1]; i++; } } else { i++; } } // Add newValue at end of z-order _visualChildren[i] = newValue; AddVisualChild(newValue); InvalidateMeasure(); InvalidateArrange(); } } ////// The RepeatButton used to decrease the Value /// public RepeatButton DecreaseRepeatButton { get { return _decreaseButton; } set { if (_increaseButton == value) { throw new NotSupportedException(SR.Get(SRID.Track_SameButtons)); } UpdateComponent(_decreaseButton, value); _decreaseButton = value; if (_decreaseButton != null) { CommandManager.InvalidateRequerySuggested(); // Should post an idle queue item to update IsEnabled on button } } } ////// The Thumb in the Track /// public Thumb Thumb { get { return _thumb; } set { UpdateComponent(_thumb, value); _thumb = value; } } ////// The RepeatButton used to increase the Value /// public RepeatButton IncreaseRepeatButton { get { return _increaseButton; } set { if (_decreaseButton == value) { throw new NotSupportedException(SR.Get(SRID.Track_SameButtons)); } UpdateComponent(_increaseButton, value); _increaseButton = value; if (_increaseButton != null) { CommandManager.InvalidateRequerySuggested(); // Should post an idle queue item to update IsEnabled on button } } } ////// DependencyProperty for [CommonDependencyProperty] public static readonly DependencyProperty OrientationProperty = DependencyProperty.Register("Orientation", typeof(Orientation), typeof(Track), new FrameworkPropertyMetadata(Orientation.Horizontal, FrameworkPropertyMetadataOptions.AffectsMeasure), new ValidateValueCallback(ScrollBar.IsValidOrientation)); ///property. /// /// This property represents the Track layout orientation: Vertical or Horizontal. /// On vertical ScrollBars, the thumb moves up and down. On horizontal bars, the thumb moves left to right. /// public Orientation Orientation { get { return (Orientation)GetValue(OrientationProperty); } set { SetValue(OrientationProperty, value); } } ////// DependencyProperty for [CommonDependencyProperty] public static readonly DependencyProperty MinimumProperty = RangeBase.MinimumProperty.AddOwner(typeof(Track), new FrameworkPropertyMetadata(0d, FrameworkPropertyMetadataOptions.AffectsArrange)); ///property. /// /// The Minimum value of the Slider or ScrollBar /// public double Minimum { get { return (double)GetValue(MinimumProperty); } set { SetValue(MinimumProperty, value); } } ////// DependencyProperty for [CommonDependencyProperty] public static readonly DependencyProperty MaximumProperty = RangeBase.MaximumProperty.AddOwner(typeof(Track), new FrameworkPropertyMetadata(1d, FrameworkPropertyMetadataOptions.AffectsArrange)); ///property. /// /// The Maximum value of the Slider or ScrollBar /// public double Maximum { get { return (double)GetValue(MaximumProperty); } set { SetValue(MaximumProperty, value); } } ////// DependencyProperty for [CommonDependencyProperty] public static readonly DependencyProperty ValueProperty = RangeBase.ValueProperty.AddOwner(typeof(Track), new FrameworkPropertyMetadata(0d, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault | FrameworkPropertyMetadataOptions.AffectsArrange)); ///property. /// /// The current value of the Slider or ScrollBar /// public double Value { get { return (double)GetValue(ValueProperty); } set { SetValue(ValueProperty, value); } } ////// DependencyProperty for [CommonDependencyProperty] public static readonly DependencyProperty ViewportSizeProperty = DependencyProperty.Register("ViewportSize", typeof(double), typeof(Track), new FrameworkPropertyMetadata(double.NaN, FrameworkPropertyMetadataOptions.AffectsArrange), new ValidateValueCallback(IsValidViewport)); ///property. /// /// ViewportSize is the amount of the scrolled extent currently visible. For most scrolled content, this value /// will be bound to one of public double ViewportSize { get { return (double)GetValue(ViewportSizeProperty); } set { SetValue(ViewportSizeProperty, value); } } private static bool IsValidViewport(object o) { double d = (double)o; return d >= 0.0 || double.IsNaN(d); } ///'s ViewportSize properties. /// This property is in logical scrolling units. /// /// Setting this value to NaN will turn off automatic sizing of the thumb /// /// DependencyProperty for [CommonDependencyProperty] public static readonly DependencyProperty IsDirectionReversedProperty = DependencyProperty.Register("IsDirectionReversed", typeof(bool), typeof(Track), new FrameworkPropertyMetadata(BooleanBoxes.FalseBox)); ///property. /// /// Indicates if the location of the DecreaseRepeatButton and IncreaseRepeatButton /// should be swapped. /// public bool IsDirectionReversed { get { return (bool)GetValue(IsDirectionReversedProperty); } set { SetValue(IsDirectionReversedProperty, value); } } #endregion //------------------------------------------------------------------- // // Protected Methods // //-------------------------------------------------------------------- #region Protected Methods ////// Derived class must implement to support Visual children. The method must return /// the child at the specified index. Index must be between 0 and GetVisualChildrenCount-1. /// /// By default a Visual does not have any children. /// /// Remark: /// During this virtual call it is not valid to modify the Visual tree. /// protected override Visual GetVisualChild(int index) { if (_visualChildren == null || _visualChildren[index] == null) { throw new ArgumentOutOfRangeException("index", index, SR.Get(SRID.Visual_ArgumentOutOfRange)); } return _visualChildren[index]; } ////// Derived classes override this property to enable the Visual code to enumerate /// the Visual children. Derived classes need to return the number of children /// from this method. /// /// By default a Visual does not have any children. /// /// Remark: During this virtual method the Visual tree must not be modified. /// protected override int VisualChildrenCount { get { if (_visualChildren == null || _visualChildren[0] == null) { Debug.Assert(_visualChildren == null || _visualChildren[1] == null, "Child[1] should be null if Child[0] == null)"); Debug.Assert(_visualChildren == null || _visualChildren[2] == null, "Child[2] should be null if Child[0] == null)"); return 0; } else if (_visualChildren[1] == null) { Debug.Assert(_visualChildren[2] == null, "Child[2] should be null if Child[1] == null)"); return 1; } else { return _visualChildren[2] == null ? 2 : 3; } } } ////// The desired size of a Track is the width (if vertically oriented) or height (if horizontally /// oriented) of the Thumb. /// /// When ViewportSize is NaN: /// The thumb is measured to find the other dimension. /// Otherwise: /// Zero size is returned; Track can scale to any size along its children. /// This means that it will occupy no space (and not display) unless made larger by a parent or specified size. /// protected override Size MeasureOverride(Size availableSize) { Size desiredSize = new Size(0.0, 0.0); // Only measure thumb // Repeat buttons will be sized based on thumb if (Thumb != null) { Thumb.Measure(availableSize); desiredSize = Thumb.DesiredSize; } if (!double.IsNaN(ViewportSize)) { // ScrollBar can shrink to 0 in the direction of scrolling if (Orientation == Orientation.Vertical) desiredSize.Height = 0.0; else desiredSize.Width = 0.0; } return desiredSize; } // Force length of one of track's pieces to be > 0 and less than tracklength private static void CoerceLength(ref double componentLength, double trackLength) { if (componentLength < 0) { componentLength = 0.0; } else if (componentLength > trackLength || double.IsNaN(componentLength)) { componentLength = trackLength; } } ////// /// Children will be stretched to fit horizontally (if vertically oriented) or vertically (if horizontally /// oriented). /// /// There are essentially three possible layout states: /// 1. The track is enabled and the thumb is proportionally sizing. /// 2. The track is enabled and the thumb has reached its minimum size. /// 3. The track is disabled or there is not enough room for the thumb. /// Track elements are not displayed, and will not be arranged. /// protected override Size ArrangeOverride(Size arrangeSize) { double decreaseButtonLength, thumbLength, increaseButtonLength; bool isVertical = (Orientation == Orientation.Vertical); double viewportSize = Math.Max(0.0, ViewportSize); // If viewport is NaN, compute thumb's size based on its desired size, // otherwise compute the thumb base on the viewport and extent properties if (double.IsNaN(viewportSize)) { ComputeSliderLengths(arrangeSize, isVertical, out decreaseButtonLength, out thumbLength, out increaseButtonLength); } else { // Don't arrange if there's not enough content or the track is too small if (!ComputeScrollBarLengths(arrangeSize, viewportSize, isVertical, out decreaseButtonLength, out thumbLength, out increaseButtonLength)) { return arrangeSize; } } // Layout the pieces of track Point offset = new Point(); Size pieceSize = arrangeSize; bool isDirectionReversed = IsDirectionReversed; if (isVertical) { // Vertical Normal : |Inc Button | // |Thumb | // |Dec Button | // Vertical Reversed : |Dec Button | // |Thumb | // |Inc Button | CoerceLength(ref decreaseButtonLength, arrangeSize.Height); CoerceLength(ref increaseButtonLength, arrangeSize.Height); CoerceLength(ref thumbLength, arrangeSize.Height); offset.Y = isDirectionReversed ? decreaseButtonLength + thumbLength : 0.0; pieceSize.Height = increaseButtonLength; if (IncreaseRepeatButton != null) IncreaseRepeatButton.Arrange(new Rect(offset, pieceSize)); offset.Y = isDirectionReversed ? 0.0 : increaseButtonLength + thumbLength; pieceSize.Height = decreaseButtonLength; if (DecreaseRepeatButton != null) DecreaseRepeatButton.Arrange(new Rect(offset, pieceSize)); offset.Y = isDirectionReversed ? decreaseButtonLength : increaseButtonLength; pieceSize.Height = thumbLength; if (Thumb != null) Thumb.Arrange(new Rect(offset, pieceSize)); ThumbCenterOffset = offset.Y + (thumbLength * 0.5); } else { // Horizontal Normal : |Dec Button |Thumb| Inc Button| // Horizontal Reversed : |Inc Button |Thumb| Dec Button| CoerceLength(ref decreaseButtonLength, arrangeSize.Width); CoerceLength(ref increaseButtonLength, arrangeSize.Width); CoerceLength(ref thumbLength, arrangeSize.Width); offset.X = isDirectionReversed ? increaseButtonLength + thumbLength : 0.0; pieceSize.Width = decreaseButtonLength; if (DecreaseRepeatButton != null) DecreaseRepeatButton.Arrange(new Rect(offset, pieceSize)); offset.X = isDirectionReversed ? 0.0 : decreaseButtonLength + thumbLength; pieceSize.Width = increaseButtonLength; if (IncreaseRepeatButton != null) IncreaseRepeatButton.Arrange(new Rect(offset, pieceSize)); offset.X = isDirectionReversed ? increaseButtonLength : decreaseButtonLength; pieceSize.Width = thumbLength; if (Thumb != null) Thumb.Arrange(new Rect(offset, pieceSize)); ThumbCenterOffset = offset.X + (thumbLength * 0.5); } return arrangeSize; } // Computes the length of the decrease button, thumb and increase button // Thumb's size is based on it's desired size private void ComputeSliderLengths(Size arrangeSize, bool isVertical, out double decreaseButtonLength, out double thumbLength, out double increaseButtonLength) { double min = Minimum; double range = Math.Max(0.0, Maximum - min); double offset = Math.Min(range, Value - min); double trackLength; // Compute thumb size if (isVertical) { trackLength = arrangeSize.Height; thumbLength = Thumb == null ? 0 : Thumb.DesiredSize.Height; } else { trackLength = arrangeSize.Width; thumbLength = Thumb == null ? 0 : Thumb.DesiredSize.Width; } CoerceLength(ref thumbLength, trackLength); double remainingTrackLength = trackLength - thumbLength; decreaseButtonLength = remainingTrackLength * offset / range; CoerceLength(ref decreaseButtonLength, remainingTrackLength); increaseButtonLength = remainingTrackLength - decreaseButtonLength; CoerceLength(ref increaseButtonLength, remainingTrackLength); Debug.Assert(decreaseButtonLength >= 0.0 && decreaseButtonLength <= remainingTrackLength, "decreaseButtonLength is outside bounds"); Debug.Assert(increaseButtonLength >= 0.0 && increaseButtonLength <= remainingTrackLength, "increaseButtonLength is outside bounds"); Density = range / remainingTrackLength; } // Computes the length of the decrease button, thumb and increase button // Thumb's size is based on viewport and extent // returns false if the track should be hidden private bool ComputeScrollBarLengths(Size arrangeSize, double viewportSize, bool isVertical, out double decreaseButtonLength, out double thumbLength, out double increaseButtonLength) { double min = Minimum; double range = Math.Max(0.0, Maximum - min); double offset = Math.Min(range, Value - min); Debug.Assert(DoubleUtil.GreaterThanOrClose(offset, 0.0), "Invalid offest (negative value)."); double extent = Math.Max(0.0, range) + viewportSize; double trackLength; // Compute thumb size double thumbMinLength; if (isVertical) { trackLength = arrangeSize.Height; // Try to use the apps resource if it exists, fall back to SystemParameters if it doesn't object buttonHeightResource = TryFindResource(SystemParameters.VerticalScrollBarButtonHeightKey); double buttonHeight = buttonHeightResource is double ? (double)buttonHeightResource : SystemParameters.VerticalScrollBarButtonHeight; thumbMinLength = Math.Floor(buttonHeight * 0.5); } else { trackLength = arrangeSize.Width; // Try to use the apps resource if it exists, fall back to SystemParameters if it doesn't object buttonWidthResource = TryFindResource(SystemParameters.HorizontalScrollBarButtonWidthKey); double buttonWidth = buttonWidthResource is double ? (double)buttonWidthResource : SystemParameters.HorizontalScrollBarButtonWidth; thumbMinLength = Math.Floor(buttonWidth * 0.5); } thumbLength = trackLength * viewportSize / extent; CoerceLength(ref thumbLength, trackLength); thumbLength = Math.Max(thumbMinLength, thumbLength); // If we don't have enough content to scroll, disable the track. bool notEnoughContentToScroll = DoubleUtil.LessThanOrClose(range, 0.0); bool thumbLongerThanTrack = thumbLength > trackLength; // if there's not enough content or the thumb is longer than the track, // hide the track and don't arrange the pieces if (notEnoughContentToScroll || thumbLongerThanTrack) { if (Visibility != Visibility.Hidden) { Visibility = Visibility.Hidden; } ThumbCenterOffset = Double.NaN; Density = Double.NaN; decreaseButtonLength = 0.0; increaseButtonLength = 0.0; return false; // don't arrange } else if (Visibility != Visibility.Visible) { Visibility = Visibility.Visible; } // Compute lengths of increase and decrease button double remainingTrackLength = trackLength - thumbLength; decreaseButtonLength = remainingTrackLength * offset / range; CoerceLength(ref decreaseButtonLength, remainingTrackLength); increaseButtonLength = remainingTrackLength - decreaseButtonLength; CoerceLength(ref increaseButtonLength, remainingTrackLength); Density = range / remainingTrackLength; return true; } // Bind track to templated parent private void BindToTemplatedParent(DependencyProperty target, DependencyProperty source) { if (!HasNonDefaultValue(target)) { Binding binding = new Binding(); binding.RelativeSource = RelativeSource.TemplatedParent; binding.Path = new PropertyPath(source); SetBinding(target, binding); } } // Bind thumb or repeat button to templated parent private void BindChildToTemplatedParent(FrameworkElement element, DependencyProperty target, DependencyProperty source) { if (element != null && !element.HasNonDefaultValue(target)) { Binding binding = new Binding(); binding.Source = this.TemplatedParent; binding.Path = new PropertyPath(source); element.SetBinding(target, binding); } } ////// /// Track automatically sets bindings to its templated parent /// to aid styling /// internal override void OnPreApplyTemplate() { base.OnPreApplyTemplate(); RangeBase rangeBase = TemplatedParent as RangeBase; if (rangeBase != null) { BindToTemplatedParent(MinimumProperty, RangeBase.MinimumProperty); BindToTemplatedParent(MaximumProperty, RangeBase.MaximumProperty); BindToTemplatedParent(ValueProperty, RangeBase.ValueProperty); // Setup ScrollBar specific bindings ScrollBar scrollBar = rangeBase as ScrollBar; if (scrollBar != null) { BindToTemplatedParent(ViewportSizeProperty, ScrollBar.ViewportSizeProperty); BindToTemplatedParent(OrientationProperty, ScrollBar.OrientationProperty); } else { // Setup Slider specific bindings Slider slider = rangeBase as Slider; if (slider != null) { BindToTemplatedParent(OrientationProperty, Slider.OrientationProperty); BindToTemplatedParent(IsDirectionReversedProperty, Slider.IsDirectionReversedProperty); BindChildToTemplatedParent(DecreaseRepeatButton, RepeatButton.DelayProperty, Slider.DelayProperty); BindChildToTemplatedParent(DecreaseRepeatButton, RepeatButton.IntervalProperty, Slider.IntervalProperty); BindChildToTemplatedParent(IncreaseRepeatButton, RepeatButton.DelayProperty, Slider.DelayProperty); BindChildToTemplatedParent(IncreaseRepeatButton, RepeatButton.IntervalProperty, Slider.IntervalProperty); } } } } #endregion //------------------------------------------------------------------- // // Private Methods // //------------------------------------------------------------------- #region Private Methods #endregion //------------------------------------------------------------------- // // Private Properties // //-------------------------------------------------------------------- #region Private Properties private double ThumbCenterOffset { get { return _thumbCenterOffset; } set { _thumbCenterOffset = value; } } private double Density { get { return _density; } set { _density = value; } } // // This property // 1. Finds the correct initial size for the _effectiveValues store on the current DependencyObject // 2. This is a performance optimization // internal override int EffectiveValuesInitialSize { get { return 28; } } #endregion //------------------------------------------------------------------- // // Private Fields // //-------------------------------------------------------------------- #region Private Fields private RepeatButton _increaseButton; private RepeatButton _decreaseButton; private Thumb _thumb; private Visual[] _visualChildren; // Density of scrolling units present in 1/96" of track (not thumb). Computed during ArrangeOverride. // Note that density default really *is* NaN. This corresponds to no track having been computed/displayed. private double _density = Double.NaN; private double _thumbCenterOffset = Double.NaN; #endregion } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved.
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- UTF32Encoding.cs
- FrugalList.cs
- ApplicationDirectory.cs
- RectangleConverter.cs
- XmlNamespaceDeclarationsAttribute.cs
- TextRangeEdit.cs
- FeatureManager.cs
- AssemblyHash.cs
- InertiaRotationBehavior.cs
- DependencyObjectType.cs
- DBProviderConfigurationHandler.cs
- ProjectedSlot.cs
- Buffer.cs
- EnumerableRowCollectionExtensions.cs
- HwndSubclass.cs
- BaseComponentEditor.cs
- IntSecurity.cs
- TypeUsageBuilder.cs
- Module.cs
- SqlRetyper.cs
- SqlInternalConnectionTds.cs
- RelatedCurrencyManager.cs
- InkCanvas.cs
- TextSearch.cs
- CodeIndexerExpression.cs
- RoleBoolean.cs
- DataRowCollection.cs
- WebPart.cs
- EndOfStreamException.cs
- BaseComponentEditor.cs
- PhysicalFontFamily.cs
- DataRowComparer.cs
- DragEventArgs.cs
- datacache.cs
- App.cs
- AdornerDecorator.cs
- TranslateTransform.cs
- TextModifier.cs
- AlternateViewCollection.cs
- CriticalExceptions.cs
- DelayedRegex.cs
- BaseUriHelper.cs
- XmlNamespaceDeclarationsAttribute.cs
- Completion.cs
- TextProperties.cs
- HttpValueCollection.cs
- ReceiveActivityDesignerTheme.cs
- SqlUserDefinedTypeAttribute.cs
- ExceptionUtil.cs
- InvalidEnumArgumentException.cs
- CopyNamespacesAction.cs
- ColumnPropertiesGroup.cs
- AdornerHitTestResult.cs
- BufferBuilder.cs
- ExpressionBuilder.cs
- EntityProviderFactory.cs
- Query.cs
- PointCollectionConverter.cs
- HtmlInputFile.cs
- InfoCardRSAOAEPKeyExchangeDeformatter.cs
- WizardPanel.cs
- BamlReader.cs
- DummyDataSource.cs
- ColorConverter.cs
- UrlMappingsModule.cs
- CacheMemory.cs
- TextEditorContextMenu.cs
- SchemaImporterExtensionsSection.cs
- SelectionProcessor.cs
- RunInstallerAttribute.cs
- DataGridViewSelectedCellCollection.cs
- OdbcFactory.cs
- ResetableIterator.cs
- SystemIPv4InterfaceProperties.cs
- TabletCollection.cs
- ListBoxChrome.cs
- ElementProxy.cs
- ErrorHandler.cs
- PartManifestEntry.cs
- EncodingDataItem.cs
- SqlLiftIndependentRowExpressions.cs
- CommandLibraryHelper.cs
- HostingEnvironmentWrapper.cs
- InteropBitmapSource.cs
- GlyphCollection.cs
- IndependentAnimationStorage.cs
- PointHitTestParameters.cs
- GenerateHelper.cs
- PrePrepareMethodAttribute.cs
- AsymmetricSignatureDeformatter.cs
- AxHostDesigner.cs
- WebEventCodes.cs
- RowCache.cs
- PeerEndPoint.cs
- Nullable.cs
- initElementDictionary.cs
- GuidelineSet.cs
- FileLogRecordStream.cs
- OleDbDataReader.cs
- AppDomainUnloadedException.cs