ScrollViewer.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ DotNET / DotNET / 8.0 / untmp / WIN_WINDOWS / lh_tools_devdiv_wpf / Windows / wcp / Framework / System / Windows / Controls / ScrollViewer.cs / 4 / ScrollViewer.cs

                            //---------------------------------------------------------------------------- 
//
// Copyright (C) Microsoft Corporation.  All rights reserved.
//
//--------------------------------------------------------------------------- 

using MS.Internal; 
using MS.Internal.Commands; 
using MS.Internal.KnownBoxes;
using MS.Internal.PresentationFramework; 
using MS.Utility;
using System;
using System.Collections;
using System.ComponentModel; 
using System.Diagnostics;
using System.Globalization; 
using System.Windows.Threading; 
using System.Windows;
using System.Windows.Automation; 
using System.Windows.Automation.Peers;
using System.Windows.Automation.Provider;
using System.Windows.Controls.Primitives;
using System.Windows.Data; 

using System.Windows.Input; 
using System.Windows.Media; 
using System.Windows.Markup;
using System.Windows.Shapes; 

namespace System.Windows.Controls
{
 
    #region ScrollBarVisibility enum
 
    ///  
    /// ScrollBarVisibilty defines the visibility behavior of a scrollbar.
    ///  
    public enum ScrollBarVisibility
    {
        /// 
        /// No scrollbars and no scrolling in this dimension. 
        /// 
        Disabled = 0, 
        ///  
        /// The scrollbar should be visible only if there is more content than fits in the viewport.
        ///  
        Auto,
        /// 
        /// The scrollbar should never be visible.  No space should ever be reserved for the scrollbar.
        ///  
        Hidden,
        ///  
        /// The scrollbar should always be visible.  Space should always be reserved for the scrollbar. 
        /// 
        Visible, 

        // NOTE: if you add or remove any values in this enum, be sure to update ScrollViewer.IsValidScrollBarVisibility()
    }
 
    #endregion
 
    ///  
    /// A ScrollViewer accepts content and provides the logic that allows it to scroll.
    ///  
    [DefaultEvent("ScrollChangedEvent")]
    [Localizability(LocalizationCategory.Ignore)]
    [TemplatePart(Name = "PART_HorizontalScrollBar", Type = typeof(ScrollBar))]
    [TemplatePart(Name = "PART_VerticalScrollBar", Type = typeof(ScrollBar))] 
    [TemplatePart(Name = "PART_ScrollContentPresenter", Type = typeof(ScrollContentPresenter))]
    public class ScrollViewer : ContentControl 
    { 

        //------------------------------------------------------------------- 
        //
        //  Public Methods
        //
        //------------------------------------------------------------------- 

        #region Public Methods 
 
        /// 
        /// Scroll content by one line to the top. 
        /// 
        public void LineUp() { EnqueueCommand(Commands.LineUp, 0, null); }
        /// 
        /// Scroll content by one line to the bottom. 
        /// 
        public void LineDown() { EnqueueCommand(Commands.LineDown, 0, null); } 
        ///  
        /// Scroll content by one line to the left.
        ///  
        public void LineLeft() { EnqueueCommand(Commands.LineLeft, 0, null); }
        /// 
        /// Scroll content by one line to the right.
        ///  
        public void LineRight() { EnqueueCommand(Commands.LineRight, 0, null); }
 
        ///  
        /// Scroll content by one page to the top.
        ///  
        public void PageUp() { EnqueueCommand(Commands.PageUp, 0, null); }
        /// 
        /// Scroll content by one page to the bottom.
        ///  
        public void PageDown() { EnqueueCommand(Commands.PageDown, 0, null); }
        ///  
        /// Scroll content by one page to the left. 
        /// 
        public void PageLeft() { EnqueueCommand(Commands.PageLeft, 0, null); } 
        /// 
        /// Scroll content by one page to the right.
        /// 
        public void PageRight() { EnqueueCommand(Commands.PageRight, 0, null); } 

        ///  
        /// Horizontally scroll to the beginning of the content. 
        /// 
        public void ScrollToLeftEnd() { EnqueueCommand(Commands.SetHorizontalOffset, Double.NegativeInfinity, null); } 
        /// 
        /// Horizontally scroll to the end of the content.
        /// 
        public void ScrollToRightEnd() { EnqueueCommand(Commands.SetHorizontalOffset, Double.PositiveInfinity, null); } 

        ///  
        /// Scroll to Top-Left of the content. 
        /// 
        public void ScrollToHome() 
        {
            EnqueueCommand(Commands.SetHorizontalOffset, Double.NegativeInfinity, null);
            EnqueueCommand(Commands.SetVerticalOffset, Double.NegativeInfinity, null);
        } 
        /// 
        /// Scroll to Bottom-Left of the content. 
        ///  
        public void ScrollToEnd()
        { 
            EnqueueCommand(Commands.SetHorizontalOffset, Double.NegativeInfinity, null);
            EnqueueCommand(Commands.SetVerticalOffset, Double.PositiveInfinity, null);
        }
 
        /// 
        /// Vertically scroll to the beginning of the content. 
        ///  
        public void ScrollToTop() { EnqueueCommand(Commands.SetVerticalOffset, Double.NegativeInfinity, null); }
        ///  
        /// Vertically scroll to the end of the content.
        /// 
        public void ScrollToBottom() { EnqueueCommand(Commands.SetVerticalOffset, Double.PositiveInfinity, null); }
 
        /// 
        /// Scroll horizontally to specified offset. Not guaranteed to end up at the specified offset though. 
        ///  
        public void ScrollToHorizontalOffset(double offset)
        { 
            double validatedOffset = ScrollContentPresenter.ValidateInputOffset(offset, "offset");
            EnqueueCommand(Commands.SetHorizontalOffset, validatedOffset, null);
        }
 
        /// 
        /// Scroll vertically to specified offset. Not guaranteed to end up at the specified offset though. 
        ///  
        public void ScrollToVerticalOffset(double offset)
        { 
            double validatedOffset = ScrollContentPresenter.ValidateInputOffset(offset, "offset");
            EnqueueCommand(Commands.SetVerticalOffset, validatedOffset, null);
        }
 
        internal void MakeVisible(Visual child, Rect rect)
        { 
            MakeVisibleParams p = new MakeVisibleParams(child, rect); 
            EnqueueCommand(Commands.MakeVisible, 0, p);
        } 

        private void EnsureLayoutUpdatedHandler()
        {
            if (_layoutUpdatedHandler == null) 
            {
                _layoutUpdatedHandler = new EventHandler(OnLayoutUpdated); 
                LayoutUpdated += _layoutUpdatedHandler; 
            }
            InvalidateArrange(); //can be that there is no outstanding need to do layout - make sure it is. 
        }

        private void ClearLayoutUpdatedHandler()
        { 
            // If queue is not empty - then we still need that handler to make sure queue is being processed.
            if ((_layoutUpdatedHandler != null) && (_queue.IsEmpty())) 
            { 
                LayoutUpdated -= _layoutUpdatedHandler;
                _layoutUpdatedHandler = null; 
            }
        }

        ///  
        /// This function is called by an IScrollInfo attached to this ScrollViewer when any values
        /// of scrolling properties (Offset, Extent, and ViewportSize) change.  The function schedules 
        /// invalidation of other elements like ScrollBars that are dependant on these properties. 
        /// 
        public void InvalidateScrollInfo() 
        {
            IScrollInfo isi = this.ScrollInfo;

            //STRESS 1627654: anybody can call this method even if we don't have ISI... 
            if(isi == null)
                return; 
 
            //!InMeasure tells us that ScrollInfo has recomputed its extent/viewport
            //incrementally, not as a result of remeasuring by this ScrollViewer. 
            //that means we should re-run the logic of determining visibility of
            //autoscrollbars, if we have them.

            if(!InMeasure) 
            {
                // 
                // Check if we should remove/add scrollbars. 
                //
                double extent = ScrollInfo.ExtentWidth; 
                double viewport = ScrollInfo.ViewportWidth;

                if (    HorizontalScrollBarVisibility == ScrollBarVisibility.Auto
                    && (    (   _scrollVisibilityX == Visibility.Collapsed 
                            &&  DoubleUtil.GreaterThan(extent, viewport))
                        || (    _scrollVisibilityX == Visibility.Visible 
                            &&  DoubleUtil.LessThanOrClose(extent, viewport)))) 
                {
                    InvalidateMeasure(); 
                }
                else
                {
                    extent = ScrollInfo.ExtentHeight; 
                    viewport = ScrollInfo.ViewportHeight;
 
                    if (VerticalScrollBarVisibility == ScrollBarVisibility.Auto 
                        && ((_scrollVisibilityY == Visibility.Collapsed
                                && DoubleUtil.GreaterThan(extent, viewport)) 
                            || (_scrollVisibilityY == Visibility.Visible
                                && DoubleUtil.LessThanOrClose(extent, viewport))))
                    {
                        InvalidateMeasure(); 
                    }
                } 
            } 

 
            // If any scrolling properties have actually changed, fire public events post-layout
            if (        !DoubleUtil.AreClose(HorizontalOffset, ScrollInfo.HorizontalOffset)
                    ||  !DoubleUtil.AreClose(VerticalOffset, ScrollInfo.VerticalOffset)
                    ||  !DoubleUtil.AreClose(ViewportWidth, ScrollInfo.ViewportWidth) 
                    ||  !DoubleUtil.AreClose(ViewportHeight, ScrollInfo.ViewportHeight)
                    ||  !DoubleUtil.AreClose(ExtentWidth, ScrollInfo.ExtentWidth) 
                    ||  !DoubleUtil.AreClose(ExtentHeight, ScrollInfo.ExtentHeight)) 
            {
                EnsureLayoutUpdatedHandler(); 
            }
        }

        #endregion 

        //-------------------------------------------------------------------- 
        // 
        //  Public Properties
        // 
        //-------------------------------------------------------------------

        #region Public Properties
 
        /// 
        /// This property indicates whether the Content should handle scrolling if it can. 
        /// A true value indicates Content should be allowed to scroll if it supports IScrollInfo. 
        /// A false value will always use the default physically scrolling handler.
        ///  
        public bool CanContentScroll
        {
            get { return (bool)GetValue(CanContentScrollProperty); }
            set { SetValue(CanContentScrollProperty, value); } 
        }
 
        ///  
        /// HorizonalScollbarVisibility is a  that
        /// determines if a horizontal scrollbar is shown. 
        /// 
        [Bindable(true), Category("Appearance")]
        public ScrollBarVisibility HorizontalScrollBarVisibility
        { 
            get { return (ScrollBarVisibility) GetValue(HorizontalScrollBarVisibilityProperty); }
            set { SetValue(HorizontalScrollBarVisibilityProperty, value); } 
        } 

        ///  
        /// VerticalScrollBarVisibility is a  that
        /// determines if a vertical scrollbar is shown.
        /// 
        [Bindable(true), Category("Appearance")] 
        public ScrollBarVisibility VerticalScrollBarVisibility
        { 
            get { return (ScrollBarVisibility) GetValue(VerticalScrollBarVisibilityProperty); } 
            set { SetValue(VerticalScrollBarVisibilityProperty, value); }
        } 

        /// 
        /// ComputedHorizontalScrollBarVisibility contains the ScrollViewer's current calculation as to
        /// whether or not scrollbars should be displayed. 
        /// 
        public Visibility ComputedHorizontalScrollBarVisibility 
        { 
            get { return _scrollVisibilityX; }
        } 
        /// 
        /// ComputedVerticalScrollBarVisibility contains the ScrollViewer's current calculation as to
        /// whether or not scrollbars should be displayed.
        ///  
        public Visibility ComputedVerticalScrollBarVisibility
        { 
            get { return _scrollVisibilityY; } 
        }
 
        /// 
        /// Actual HorizontalOffset contains the ScrollViewer's current horizontal offset.
        /// This is a computed value, derived from viewport/content size and previous scroll commands
        ///  
        public double HorizontalOffset
        { 
            get { return _xPositionISI; } 
        }
 
        /// 
        /// Actual VerticalOffset contains the ScrollViewer's current Vertical offset.
        /// This is a computed value, derived from viewport/content size and previous scroll commands
        ///  
        public double VerticalOffset
        { 
            get { return _yPositionISI; } 
        }
 
        /// 
        /// ExtentWidth contains the horizontal size of the scrolled content element.
        /// 
        ///  
        /// ExtentWidth is only an output property; it can effectively be set by specifying
        ///  on the content element. 
        ///  
        [Category("Layout")]
        public double ExtentWidth 
        {
            get { return _xExtent; }
        }
        ///  
        /// ExtentHeight contains the vertical size of the scrolled content element.
        ///  
        ///  
        /// ExtentHeight is only an output property; it can effectively be set by specifying
        ///  on the content element. 
        /// 
        [Category("Layout")]
        public double ExtentHeight
        { 
            get { return _yExtent; }
        } 
 
        /// 
        /// ScrollableWidth contains the horizontal size of the content element that can be scrolled. 
        /// 
        public double ScrollableWidth
        {
            get { return Math.Max(0.0, ExtentWidth - ViewportWidth); } 
        }
 
        ///  
        /// ScrollableHeight contains the vertical size of the content element that can be scrolled.
        ///  
        public double ScrollableHeight
        {
            get { return Math.Max(0.0, ExtentHeight - ViewportHeight); }
        } 

        ///  
        /// ViewportWidth contains the horizontal size of the scrolling viewport. 
        /// 
        ///  
        /// ExtentWidth is only an output property; it can effectively be set by specifying
        ///  on this element.
        /// 
        [Category("Layout")] 
        public double ViewportWidth
        { 
            get { return _xSize; } 
        }
        ///  
        /// ViewportHeight contains the vertical size of the scrolling viewport.
        /// 
        /// 
        /// ViewportHeight is only an output property; it can effectively be set by specifying 
        ///  on this element.
        ///  
        [Category("Layout")] 
        public double ViewportHeight
        { 
            get { return _ySize; }
        }

        ///  
        /// DependencyProperty for  property.
        ///  
        [CommonDependencyProperty] 
        public static readonly DependencyProperty CanContentScrollProperty =
                DependencyProperty.RegisterAttached( 
                        "CanContentScroll",
                        typeof(bool),
                        typeof(ScrollViewer),
                        new FrameworkPropertyMetadata(BooleanBoxes.FalseBox)); 

        ///  
        /// Helper for setting CanContentScroll property. 
        /// 
        public static void SetCanContentScroll(DependencyObject element, bool canContentScroll) 
        {
            if (element == null)
            {
                throw new ArgumentNullException("element"); 
            }
 
            element.SetValue(CanContentScrollProperty, canContentScroll); 
        }
 
        /// 
        /// Helper for reading CanContentScroll property.
        /// 
        public static bool GetCanContentScroll(DependencyObject element) 
        {
            if (element == null) 
            { 
                throw new ArgumentNullException("element");
            } 

            return ((bool)element.GetValue(CanContentScrollProperty));
        }
 
        /// 
        /// DependencyProperty for  property. 
        ///  
        [CommonDependencyProperty]
        public static readonly DependencyProperty HorizontalScrollBarVisibilityProperty = 
                DependencyProperty.RegisterAttached(
                        "HorizontalScrollBarVisibility",
                        typeof(ScrollBarVisibility),
                        typeof(ScrollViewer), 
                        new FrameworkPropertyMetadata(
                                ScrollBarVisibility.Disabled, 
                                FrameworkPropertyMetadataOptions.AffectsMeasure), 
                        new ValidateValueCallback(IsValidScrollBarVisibility));
 
        /// 
        /// Helper for setting HorizontalScrollBarVisibility property.
        /// 
        public static void SetHorizontalScrollBarVisibility(DependencyObject element, ScrollBarVisibility horizontalScrollBarVisibility) 
        {
            if (element == null) 
            { 
                throw new ArgumentNullException("element");
            } 

            element.SetValue(HorizontalScrollBarVisibilityProperty, horizontalScrollBarVisibility);
        }
 
        /// 
        /// Helper for reading HorizontalScrollBarVisibility property. 
        ///  
        public static ScrollBarVisibility GetHorizontalScrollBarVisibility(DependencyObject element)
        { 
            if (element == null)
            {
                throw new ArgumentNullException("element");
            } 

            return ((ScrollBarVisibility)element.GetValue(HorizontalScrollBarVisibilityProperty)); 
        } 

        ///  
        /// DependencyProperty for  property.
        /// 
        [CommonDependencyProperty]
        public static readonly DependencyProperty VerticalScrollBarVisibilityProperty = 
                DependencyProperty.RegisterAttached(
                        "VerticalScrollBarVisibility", 
                        typeof(ScrollBarVisibility), 
                        typeof(ScrollViewer),
                        new FrameworkPropertyMetadata( 
                                ScrollBarVisibility.Visible,
                                FrameworkPropertyMetadataOptions.AffectsMeasure),
                        new ValidateValueCallback(IsValidScrollBarVisibility));
 
        /// 
        /// Helper for setting VerticalScrollBarVisibility property. 
        ///  
        public static void SetVerticalScrollBarVisibility(DependencyObject element, ScrollBarVisibility verticalScrollBarVisibility)
        { 
            if (element == null)
            {
                throw new ArgumentNullException("element");
            } 

            element.SetValue(VerticalScrollBarVisibilityProperty, verticalScrollBarVisibility); 
        } 

        ///  
        /// Helper for reading VerticalScrollBarVisibility property.
        /// 
        public static ScrollBarVisibility GetVerticalScrollBarVisibility(DependencyObject element)
        { 
            if (element == null)
            { 
                throw new ArgumentNullException("element"); 
            }
 
            return ((ScrollBarVisibility)element.GetValue(VerticalScrollBarVisibilityProperty));
        }

        ///  
        ///     The key needed set a read-only property.
        ///  
        private static readonly DependencyPropertyKey ComputedHorizontalScrollBarVisibilityPropertyKey = 
                DependencyProperty.RegisterReadOnly(
                        "ComputedHorizontalScrollBarVisibility", 
                        typeof(Visibility),
                        typeof(ScrollViewer),
                        new FrameworkPropertyMetadata(Visibility.Visible));
 
        /// 
        /// Dependency property that indicates whether horizontal scrollbars should display.  The 
        /// value of this property is computed by ScrollViewer; it can be controlled via the 
        /// 
        ///  
        public static readonly DependencyProperty ComputedHorizontalScrollBarVisibilityProperty =
                ComputedHorizontalScrollBarVisibilityPropertyKey.DependencyProperty;

        ///  
        ///     The key needed set a read-only property.
        ///  
        private static readonly DependencyPropertyKey ComputedVerticalScrollBarVisibilityPropertyKey = 
                DependencyProperty.RegisterReadOnly(
                        "ComputedVerticalScrollBarVisibility", 
                        typeof(Visibility),
                        typeof(ScrollViewer),
                        new FrameworkPropertyMetadata(Visibility.Visible));
 
        /// 
        /// Dependency property that indicates whether vertical scrollbars should display.  The 
        /// value of this property is computed by ScrollViewer; it can be controlled via the 
        /// 
        ///  
        public static readonly DependencyProperty ComputedVerticalScrollBarVisibilityProperty =
                ComputedVerticalScrollBarVisibilityPropertyKey.DependencyProperty;

 
        /// 
        ///     Actual VerticalOffset. 
        ///  
        private static readonly DependencyPropertyKey VerticalOffsetPropertyKey =
            DependencyProperty.RegisterReadOnly( 
                        "VerticalOffset",
                        typeof(double),
                        typeof(ScrollViewer),
                        new FrameworkPropertyMetadata(0d)); 

        ///  
        /// DependencyProperty for  property. 
        /// 
        public static readonly DependencyProperty VerticalOffsetProperty = 
            VerticalOffsetPropertyKey.DependencyProperty;


        ///  
        ///     HorizontalOffset.
        ///  
        private static readonly DependencyPropertyKey HorizontalOffsetPropertyKey = 
            DependencyProperty.RegisterReadOnly(
                        "HorizontalOffset", 
                        typeof(double),
                        typeof(ScrollViewer),
                        new FrameworkPropertyMetadata(0d));
 
        /// 
        /// DependencyProperty for  property. 
        ///  
        public static readonly DependencyProperty HorizontalOffsetProperty =
            HorizontalOffsetPropertyKey.DependencyProperty; 

        /// 
        ///     The key needed set a read-only property.
        ///  
        private static readonly DependencyPropertyKey ExtentWidthPropertyKey =
                DependencyProperty.RegisterReadOnly( 
                        "ExtentWidth", 
                        typeof(double),
                        typeof(ScrollViewer), 
                        new FrameworkPropertyMetadata(0d));

        /// 
        /// DependencyProperty for  property. 
        /// 
        public static readonly DependencyProperty ExtentWidthProperty = 
            ExtentWidthPropertyKey.DependencyProperty; 

        ///  
        ///     The key needed set a read-only property.
        /// 
        private static readonly DependencyPropertyKey ExtentHeightPropertyKey =
                DependencyProperty.RegisterReadOnly( 
                        "ExtentHeight",
                        typeof(double), 
                        typeof(ScrollViewer), 
                        new FrameworkPropertyMetadata(0d));
 
        /// 
        /// DependencyProperty for  property.
        /// 
        public static readonly DependencyProperty ExtentHeightProperty = 
            ExtentHeightPropertyKey.DependencyProperty;
 
        ///  
        ///     The key needed set a read-only property.
        ///  
        private static readonly DependencyPropertyKey ScrollableWidthPropertyKey =
                DependencyProperty.RegisterReadOnly(
                        "ScrollableWidth",
                        typeof(double), 
                        typeof(ScrollViewer),
                        new FrameworkPropertyMetadata(0d)); 
 
        /// 
        /// DependencyProperty for  property. 
        /// 
        public static readonly DependencyProperty ScrollableWidthProperty =
            ScrollableWidthPropertyKey.DependencyProperty;
 
        /// 
        ///     The key needed set a read-only property. 
        ///  
        private static readonly DependencyPropertyKey ScrollableHeightPropertyKey =
                DependencyProperty.RegisterReadOnly( 
                        "ScrollableHeight",
                        typeof(double),
                        typeof(ScrollViewer),
                        new FrameworkPropertyMetadata(0d)); 

        ///  
        /// DependencyProperty for  property. 
        /// 
        public static readonly DependencyProperty ScrollableHeightProperty = 
            ScrollableHeightPropertyKey.DependencyProperty;

        /// 
        ///     The key needed set a read-only property. 
        /// 
        private static readonly DependencyPropertyKey ViewportWidthPropertyKey = 
                DependencyProperty.RegisterReadOnly( 
                        "ViewportWidth",
                        typeof(double), 
                        typeof(ScrollViewer),
                        new FrameworkPropertyMetadata(0d));

        ///  
        /// DependencyProperty for  property.
        ///  
        public static readonly DependencyProperty ViewportWidthProperty = 
            ViewportWidthPropertyKey.DependencyProperty;
 
        /// 
        ///     The key needed set a read-only property.
        /// 
        internal static readonly DependencyPropertyKey ViewportHeightPropertyKey = 
                DependencyProperty.RegisterReadOnly(
                        "ViewportHeight", 
                        typeof(double), 
                        typeof(ScrollViewer),
                        new FrameworkPropertyMetadata(0d)); 


        /// 
        /// DependencyProperty for  property. 
        /// 
        public static readonly DependencyProperty ViewportHeightProperty = 
            ViewportHeightPropertyKey.DependencyProperty; 

        #endregion 

        //--------------------------------------------------------------------
        //
        //  Public Events (CLR + Avalon) 
        //
        //-------------------------------------------------------------------- 
 
        #region Public Events
 
        /// 
        /// Event ID that corresponds to a change in scrolling state.
        /// See ScrollChangeEvent for the corresponding event handler.
        ///  
        public static readonly RoutedEvent ScrollChangedEvent = EventManager.RegisterRoutedEvent(
            "ScrollChanged", 
            RoutingStrategy.Bubble, 
            typeof(ScrollChangedEventHandler),
            typeof(ScrollViewer)); 

        /// 
        /// Event handler registration for the event fired when scrolling state changes.
        ///  
        [Category("Action")]
        public event ScrollChangedEventHandler ScrollChanged 
        { 
            add { AddHandler(ScrollChangedEvent, value); }
            remove { RemoveHandler(ScrollChangedEvent, value); } 
        }

        #endregion
 

        //------------------------------------------------------------------- 
        // 
        //  Protected Methods
        // 
        //--------------------------------------------------------------------

        #region Protected Methods
 
        /// 
        /// OnScrollChanged is an override called whenever scrolling state changes on this ScrollViewer. 
        ///  
        /// 
        /// OnScrollChanged fires the ScrollChangedEvent.  Overriders of this method should call 
        /// base.OnScrollChanged(args) if they want the event to be fired.
        /// 
        /// ScrollChangedEventArgs containing information about the change in scrolling state.
        protected virtual void OnScrollChanged(ScrollChangedEventArgs e) 
        {
            // Fire the event. 
            RaiseEvent(e); 
        }
 
        /// 
        /// ScrollViewer always wants to be hit even when transparent so that it gets input such as MouseWheel.
        /// 
        protected override HitTestResult HitTestCore(PointHitTestParameters hitTestParameters) 
        {
            // Assumptions: 
            // 1. Input comes after layout, so Actual* are valid at this point 
            // 2. The clipping part of scrolling is on the SCP, not SV.  Thus, Actual* not taking clipping into
            //    account is okay here, barring psychotic styles. 
            Rect rc = new Rect(0, 0, this.ActualWidth, this.ActualHeight);
            if (rc.Contains(hitTestParameters.HitPoint))
            {
                return new PointHitTestResult(this, hitTestParameters.HitPoint); 
            }
            else 
            { 
                return null;
            } 
        }

        /// 
        ///     If control has a scrollviewer in its style and has a custom keyboard scrolling behavior when HandlesScrolling should return true. 
        /// Then ScrollViewer will not handle keyboard input and leave it up to the control.
        ///  
        protected internal override bool HandlesScrolling 
        {
            get { return true; } 
        }

        /// 
        /// ScrollArea handles keyboard scrolling events. 
        /// ScrollArea handles:  Left, Right, Up, Down, PageUp, PageDown, Home, End
        ///  
        protected override void OnKeyDown(KeyEventArgs e) 
        {
            if (e.Handled) 
                return;

            Control templatedParentControl = TemplatedParent as Control;
            if (templatedParentControl != null && templatedParentControl.HandlesScrolling) 
                return;
 
            // If the ScrollViewer has focus or other that arrow key is pressed 
            // then it only scrolls
            if (e.OriginalSource == this) 
            {
                ScrollInDirection(e);
            }
            // Focus is on the element within the ScrollViewer 
            else
            { 
                // If arrow key is pressed 
                if (e.Key == Key.Left || e.Key == Key.Right || e.Key == Key.Up || e.Key == Key.Down)
                { 
                    ScrollContentPresenter viewPort = GetTemplateChild(ScrollContentPresenterTemplateName) as ScrollContentPresenter;
                    // If style changes and ConentSite cannot be found - just scroll and exit
                    if (viewPort == null)
                    { 
                        ScrollInDirection(e);
                        return; 
                    } 

                    FocusNavigationDirection direction = KeyboardNavigation.KeyToTraversalDirection(e.Key); 
                    DependencyObject predictedFocus = null;
                    DependencyObject focusedElement = Keyboard.FocusedElement as DependencyObject;
                    bool isFocusWithinViewport = IsInViewport(viewPort, focusedElement);
 
                    if (isFocusWithinViewport)
                    { 
                        // Navigate from current focused element 
                        UIElement currentFocusUIElement = focusedElement as UIElement;
                        if (currentFocusUIElement != null) 
                        {
                            predictedFocus = currentFocusUIElement.PredictFocus(direction);
                        }
                        else 
                        {
                            ContentElement currentFocusContentElement = focusedElement as ContentElement; 
                            if (currentFocusContentElement != null) 
                            {
                                predictedFocus = currentFocusContentElement.PredictFocus(direction); 
                            }
                            else
                            {
                                UIElement3D currentFocusUIElement3D = focusedElement as UIElement3D; 
                                if (currentFocusUIElement3D != null)
                                { 
                                    predictedFocus = currentFocusUIElement3D.PredictFocus(direction); 
                                }
                            } 
                        }
                    }
                    else
                    { // Navigate from current viewport 
                        predictedFocus = viewPort.PredictFocus(direction);
                    } 
 
                    if (predictedFocus == null)
                    { 
                        // predictedFocus is null - just scroll
                        ScrollInDirection(e);
                    }
                    else 
                    {
                        // Case 1: predictedFocus is entirely in current view port 
                        // Action: Set focus to predictedFocus, handle the event and exit 
                        if (IsInViewport(viewPort, predictedFocus))
                        { 
                            ((IInputElement)predictedFocus).Focus();
                            e.Handled = true;
                        }
                        // Case 2: else - predictedFocus is not entirely in the viewport 
                        // Scroll in the direction
                        // If predictedFocus is in the new viewport - set focus 
                        // handle the event and exit 
                        else
                        { 
                            ScrollInDirection(e);
                            UpdateLayout();
                            if (IsInViewport(viewPort, predictedFocus))
                            { 
                                ((IInputElement)predictedFocus).Focus();
                            } 
                        } 
                    }
                } 
                else // If other than arrow Key is down
                {
                    ScrollInDirection(e);
                } 
            }
        } 
 

        // Returns true only if element is partly visible in the current viewport 
        private bool IsInViewport(ScrollContentPresenter scp, DependencyObject element)
        {
            Rect viewPortRect = KeyboardNavigation.GetRectangle(scp);
            Rect elementRect = KeyboardNavigation.GetRectangle(element); 
            return viewPortRect.IntersectsWith(elementRect);
        } 
 
        internal void ScrollInDirection(KeyEventArgs e)
        { 
            bool fControlDown = ((e.KeyboardDevice.Modifiers & ModifierKeys.Control) != 0);
            bool fAltDown = ((e.KeyboardDevice.Modifiers & ModifierKeys.Alt) != 0);

            // We don't handle Alt + Key 
            if (!fAltDown)
            { 
                bool fInvertForRTL = (FlowDirection == FlowDirection.RightToLeft); 
                switch (e.Key)
                { 
                    case Key.Left:
                        if (fInvertForRTL) LineRight(); else LineLeft();
                        e.Handled = true;
                        break; 
                    case Key.Right:
                        if (fInvertForRTL) LineLeft(); else LineRight(); 
                        e.Handled = true; 
                        break;
                    case Key.Up: 
                        LineUp();
                        e.Handled = true;
                        break;
                    case Key.Down: 
                        LineDown();
                        e.Handled = true; 
                        break; 
                    case Key.PageUp:
                        PageUp(); 
                        e.Handled = true;
                        break;
                    case Key.PageDown:
                        PageDown(); 
                        e.Handled = true;
                        break; 
                    case Key.Home: 
                        if (fControlDown) ScrollToTop(); else ScrollToLeftEnd();
                        e.Handled = true; 
                        break;
                    case Key.End:
                        if (fControlDown) ScrollToBottom(); else ScrollToRightEnd();
                        e.Handled = true; 
                        break;
                } 
            } 
        }
 
        /// 
        /// This is the method that responds to the MouseWheel event.
        /// 
        /// Event Arguments 
        protected override void OnMouseWheel(MouseWheelEventArgs e)
        { 
            if (e.Handled) { return; } 

            if (!HandlesMouseWheelScrolling) 
            {
                return;
            }
 
            if (ScrollInfo != null)
            { 
                if (e.Delta < 0) { ScrollInfo.MouseWheelDown(); } 
                else { ScrollInfo.MouseWheelUp(); }
            } 

            e.Handled = true;
        }
 
        /// 
        /// This is the method that responds to the MouseButtonEvent event. 
        ///  
        /// 
        protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e) 
        {
            if (Focus())
                e.Handled = true;
            base.OnMouseLeftButtonDown(e); 
        }
 
        ///  
        /// Updates DesiredSize of the ScrollViewer.  Called by parent UIElement.  This is the first pass of layout.
        ///  
        /// Constraint size is an "upper limit" that the return value should not exceed.
        /// The ScrollViewer's desired size.
        protected override Size MeasureOverride(Size constraint)
        { 
            InChildInvalidateMeasure = false;
            IScrollInfo isi = this.ScrollInfo; 
            int count = this.VisualChildrenCount; 

            UIElement child = (count > 0) ? this.GetVisualChild(0) as UIElement : null; 
            ScrollBarVisibility vsbv = VerticalScrollBarVisibility;
            ScrollBarVisibility hsbv = HorizontalScrollBarVisibility;
            if (child == null) { return new Size(); }
 
            bool etwTracingEnabled = EventTrace.IsEnabled(EventTrace.Flags.performance, EventTrace.Level.normal);
            if (etwTracingEnabled) 
            { 
                EventTrace.EventProvider.TraceEvent(EventTrace.GuidFromId(EventTraceGuidId.GENERICSTRINGGUID), MS.Utility.EventType.StartEvent, "SCROLLVIEWER:MeasureOverride");
            } 

            try
            {
                InMeasure = true; 

                bool vsbAuto = (vsbv == ScrollBarVisibility.Auto); 
                bool hsbAuto = (hsbv == ScrollBarVisibility.Auto); 
                bool vDisableScroll = (vsbv == ScrollBarVisibility.Disabled);
                bool hDisableScroll = (hsbv == ScrollBarVisibility.Disabled); 
                Visibility vv = (vsbv == ScrollBarVisibility.Visible) ? Visibility.Visible : Visibility.Collapsed;
                Visibility hv = (hsbv == ScrollBarVisibility.Visible) ? Visibility.Visible : Visibility.Collapsed;

                if (_scrollVisibilityY != vv) 
                {
                    _scrollVisibilityY = vv; 
                    SetValue(ComputedVerticalScrollBarVisibilityPropertyKey, _scrollVisibilityY); 
                }
                if (_scrollVisibilityX != hv) 
                {
                    _scrollVisibilityX = hv;
                    SetValue(ComputedHorizontalScrollBarVisibilityPropertyKey, _scrollVisibilityX);
                } 

                if (isi != null) 
                { 
                    isi.CanHorizontallyScroll = !hDisableScroll;
                    isi.CanVerticallyScroll = !vDisableScroll; 
                }

                // Measure our visual tree.
                child.Measure(constraint); 

                //it could now be here as a result of visual template expansion that happens during Measure 
                isi = this.ScrollInfo; 

                if (isi != null && (hsbAuto || vsbAuto)) 
                {
                    bool makeHorizontalBarVisible = hsbAuto && DoubleUtil.GreaterThan(isi.ExtentWidth, isi.ViewportWidth);
                    bool makeVerticalBarVisible = vsbAuto && DoubleUtil.GreaterThan(isi.ExtentHeight, isi.ViewportHeight);
 
                    if (makeHorizontalBarVisible)
                    { 
                        if (_scrollVisibilityX != Visibility.Visible) 
                        {
                            _scrollVisibilityX = Visibility.Visible; 
                            SetValue(ComputedHorizontalScrollBarVisibilityPropertyKey, _scrollVisibilityX);
                        }
                    }
 
                    if (makeVerticalBarVisible)
                    { 
                        if (_scrollVisibilityY != Visibility.Visible) 
                        {
                            _scrollVisibilityY = Visibility.Visible; 
                            SetValue(ComputedVerticalScrollBarVisibilityPropertyKey, _scrollVisibilityY);
                        }
                    }
 
                    if (makeHorizontalBarVisible || makeVerticalBarVisible)
                    { 
                        // Remeasure our visual tree. 
                        // Requires this extra invalidation because we need to remeasure Grid which is not neccessarily dirty now
                        // since we only invlaidated scrollbars but we don't have LayoutUpdate loop at our disposal here 
                        InChildInvalidateMeasure = true;
                        child.InvalidateMeasure();
                        child.Measure(constraint);
                    } 

                    //if both are Auto, then appearance of one scrollbar may causes appearance of another. 
                    //If we don't re-check here, we get some part of content covered by auto scrollbar and can never reach to it since 
                    //another scrollbar may not appear (in cases when viewport==extent) - bug 1199443
                    if(hsbAuto && vsbAuto && (makeHorizontalBarVisible != makeVerticalBarVisible)) 
                    {
                        bool makeHorizontalBarVisible2 = !makeHorizontalBarVisible && DoubleUtil.GreaterThan(isi.ExtentWidth, isi.ViewportWidth);
                        bool makeVerticalBarVisible2 = !makeVerticalBarVisible && DoubleUtil.GreaterThan(isi.ExtentHeight, isi.ViewportHeight);
 
                        if(makeHorizontalBarVisible2)
                        { 
                            if (_scrollVisibilityX != Visibility.Visible) 
                            {
                                _scrollVisibilityX = Visibility.Visible; 
                                SetValue(ComputedHorizontalScrollBarVisibilityPropertyKey, _scrollVisibilityX);
                            }
                        }
                        else if (makeVerticalBarVisible2) //only one can be true 
                        {
                            if (_scrollVisibilityY != Visibility.Visible) 
                            { 
                                _scrollVisibilityY = Visibility.Visible;
                                SetValue(ComputedVerticalScrollBarVisibilityPropertyKey, _scrollVisibilityY); 
                            }
                        }

                        if (makeHorizontalBarVisible2 || makeVerticalBarVisible2) 
                        {
                            // Remeasure our visual tree. 
                            // Requires this extra invalidation because we need to remeasure Grid which is not neccessarily dirty now 
                            // since we only invlaidated scrollbars but we don't have LayoutUpdate loop at our disposal here
                            InChildInvalidateMeasure = true; 
                            child.InvalidateMeasure();
                            child.Measure(constraint);
                        }
 
                    }
                } 
            } 
            finally
            { 
                InMeasure = false;
            }

            if (etwTracingEnabled) 
            {
                EventTrace.EventProvider.TraceEvent(EventTrace.GuidFromId(EventTraceGuidId.GENERICSTRINGGUID), MS.Utility.EventType.EndEvent, "SCROLLVIEWER:MeasureOverride"); 
            } 

            return child.DesiredSize; 
        }


        private void BindToTemplatedParent(DependencyProperty property) 
        {
            if (!HasNonDefaultValue(property)) 
            { 
                Binding binding = new Binding();
                binding.RelativeSource = RelativeSource.TemplatedParent; 
                binding.Path = new PropertyPath(property);
                SetBinding(property, binding);
            }
        } 

        ///  
        /// ScrollViewer binds to the TemplatedParent's attached properties 
        /// if they are not set directly on the ScrollViewer
        ///  
        internal override void OnPreApplyTemplate()
        {
            base.OnPreApplyTemplate();
 
            if (TemplatedParent != null)
            { 
                BindToTemplatedParent(HorizontalScrollBarVisibilityProperty); 
                BindToTemplatedParent(VerticalScrollBarVisibilityProperty);
                BindToTemplatedParent(CanContentScrollProperty); 
            }
        }

        ///  
        /// Called when the Template's tree has been generated
        ///  
        public override void OnApplyTemplate() 
        {
            base.OnApplyTemplate(); 

            ScrollBar scrollBar = GetTemplateChild(HorizontalScrollBarTemplateName) as ScrollBar;

            if (scrollBar != null) 
                scrollBar.IsStandalone = false;
 
            scrollBar = GetTemplateChild(VerticalScrollBarTemplateName) as ScrollBar; 

            if (scrollBar != null) 
                scrollBar.IsStandalone = false;
        }

        #endregion 

        //------------------------------------------------------------------- 
        // 
        //  Protected Propeties
        // 
        //-------------------------------------------------------------------

        #region Protected Properties
 

        ///  
        /// The ScrollInfo is the source of scrolling properties (Extent, Offset, and ViewportSize) 
        /// for this ScrollViewer and any of its components like scrollbars.
        ///  
        protected internal IScrollInfo ScrollInfo
        {
            get { return _scrollInfo; }
            set 
            {
                _scrollInfo = value; 
                if (_scrollInfo != null) 
                {
                    _scrollInfo.CanHorizontallyScroll = (HorizontalScrollBarVisibility != ScrollBarVisibility.Disabled); 
                    _scrollInfo.CanVerticallyScroll = (VerticalScrollBarVisibility != ScrollBarVisibility.Disabled);
                    EnsureQueueProcessing();
                }
            } 
        }
 
        #endregion 

        //------------------------------------------------------------------- 
        //
        //  Internal Propeties
        //
        //-------------------------------------------------------------------- 

        #region Internal Properties 
 
        /// 
        /// Whether or not the ScrollViewer should handle mouse wheel events.  This property was 
        /// specifically introduced for TextBoxBase, to prevent mouse wheel scrolling from "breaking"
        /// if the mouse pointer happens to land on a TextBoxBase with no more content in the direction
        /// of the scroll, as with a single-line TextBox.  In that scenario, ScrollViewer would
        /// try to scroll the TextBoxBase and not allow the scroll event to bubble up to an outer 
        /// control even though the TextBoxBase doesn't scroll.
        /// 
        /// This property defaults to true.  TextBoxBase sets it to false. 
        /// 
        internal bool HandlesMouseWheelScrolling 
        {
            get
            {
                return _handlesMouseWheelScrolling; 
            }
            set 
            { 
                _handlesMouseWheelScrolling = value;
            } 
        }

        #endregion Internal Properties
 
        //-------------------------------------------------------------------
        // 
        //  Private Methods 
        //
        //-------------------------------------------------------------------- 

        #region Private Methods

        private enum Commands 
        {
            Invalid, 
            LineUp, 
            LineDown,
            LineLeft, 
            LineRight,
            PageUp,
            PageDown,
            PageLeft, 
            PageRight,
            SetHorizontalOffset, 
            SetVerticalOffset, 
            MakeVisible,
        } 

        private struct Command
        {
            internal Command(Commands code, double param, MakeVisibleParams mvp) 
            {
                Code = code; 
                Param = param; 
                MakeVisibleParam = mvp;
            } 

            internal Commands Code;
            internal double Param;
            internal MakeVisibleParams MakeVisibleParam; 
        }
 
        private class MakeVisibleParams 
        {
            internal MakeVisibleParams(Visual child, Rect targetRect) 
            {
                Child = child;
                TargetRect = targetRect;
            } 
            internal Visual Child;
            internal Rect TargetRect; 
        } 

        // implements ring buffer of commands 
        private struct CommandQueue
        {
            private const int _capacity = 32;
 
            //returns false if capacity is used up and entry ignored
            internal void Enqueue(Command command) 
            { 
                if(_lastWritePosition == _lastReadPosition) //buffer is empty
                { 
                    _array = new Command[_capacity];
                    _lastWritePosition = _lastReadPosition = 0;
                }
 
                if(!OptimizeCommand(command)) //regular insertion, if optimization didn't happen
                { 
                    _lastWritePosition = (_lastWritePosition + 1) % _capacity; 

                    if(_lastWritePosition == _lastReadPosition) //buffer is full 
                    {
                        // throw away the oldest entry and continue to accumulate fresh input
                        _lastReadPosition = (_lastReadPosition + 1) % _capacity;
                    } 

                    _array[_lastWritePosition] = command; 
                } 
            }
 
            // this tries to "merge" the incoming command with the accumulated queue
            // for example, if we get SetHorizontalOffset incoming, all "horizontal"
            // commands in the queue get removed and replaced with incoming one,
            // since horizontal position is going to end up at the specified offset anyways. 
            private bool OptimizeCommand(Command command)
            { 
                if(_lastWritePosition != _lastReadPosition) //buffer has something 
                {
 
                    if(   (   command.Code == Commands.SetHorizontalOffset
                           && _array[_lastWritePosition].Code == Commands.SetHorizontalOffset)
                       || (   command.Code == Commands.SetVerticalOffset
                           && _array[_lastWritePosition].Code == Commands.SetVerticalOffset)) 
                    {
                        //if the last command was "set offset", simply replace offset and 
                        //don't insert new command 
                        _array[_lastWritePosition].Param = command.Param;
                        return true; 
                    }
                }
                return false;
            } 

            // returns Invalid command if there is no more commands 
            internal Command Fetch() 
            {
                if(_lastWritePosition == _lastReadPosition) //buffer is empty 
                {
                    return new Command(Commands.Invalid, 0, null);
                }
                _lastReadPosition = (_lastReadPosition + 1) % _capacity; 

                //array exists always if writePos != readPos 
                Command command = _array[_lastReadPosition]; 
                _array[_lastReadPosition].MakeVisibleParam = null; //to release the allocated object
 
                if(_lastWritePosition == _lastReadPosition) //it was the last command
                {
                    _array = null; // make GC work. Hopefully the whole queue is processed in Gen0
                } 
                return command;
            } 
 
            internal bool IsEmpty()
            { 
                return (_lastWritePosition == _lastReadPosition);
            }

            private int _lastWritePosition; 
            private int _lastReadPosition;
            private Command[] _array; 
 
        }
 
        //returns true if there was a command sent to ISI
        private bool ExecuteNextCommand()
        {
            IScrollInfo isi = ScrollInfo; 
            if(isi == null) return false;
 
            Command cmd = _queue.Fetch(); 
            switch(cmd.Code)
            { 
                case Commands.LineUp:    isi.LineUp();    break;
                case Commands.LineDown:  isi.LineDown();  break;
                case Commands.LineLeft:  isi.LineLeft();  break;
                case Commands.LineRight: isi.LineRight(); break; 

                case Commands.PageUp:    isi.PageUp();    break; 
                case Commands.PageDown:  isi.PageDown();  break; 
                case Commands.PageLeft:  isi.PageLeft();  break;
                case Commands.PageRight: isi.PageRight(); break; 

                case Commands.SetHorizontalOffset: isi.SetHorizontalOffset(cmd.Param); break;
                case Commands.SetVerticalOffset:   isi.SetVerticalOffset(cmd.Param);   break;
 
                case Commands.MakeVisible:
                { 
                    Visual child = cmd.MakeVisibleParam.Child; 
                    Visual visi = isi as Visual;
 
                    if (    child != null
                        &&  visi != null
                        &&  (visi == child || visi.IsAncestorOf(child))
                        //  bug 1616807. ISI could be removed from visual tree, 
                        //  but ScrollViewer.ScrollInfo may not reflect this yet.
                        &&  this.IsAncestorOf(visi) ) 
                    { 
                        Rect targetRect = cmd.MakeVisibleParam.TargetRect;
                        if(targetRect.IsEmpty) 
                        {
                            UIElement uie = child as UIElement;
                            if(uie != null)
                                targetRect = new Rect(uie.RenderSize); 
                            else
                                targetRect = new Rect(); //not a good idea to invoke ISI with Empty rect 
                        } 

                        // 



                        Rect rcNew; 
                        if(isi.GetType() == typeof(System.Windows.Controls.ScrollContentPresenter))
                        { 
                            rcNew = ((System.Windows.Controls.ScrollContentPresenter)isi).MakeVisible(child, targetRect, false); 
                        }
                        else 
                        {
                            rcNew = isi.MakeVisible(child, targetRect);
                        }
 
                        if (!rcNew.IsEmpty)
                        { 
                            GeneralTransform t = visi.TransformToAncestor(this); 
                            rcNew = t.TransformBounds(rcNew);
                        } 

                        BringIntoView(rcNew);
                    }
                } 
                break;
 
                case Commands.Invalid: return false; 
            }
            return true; 
        }

        private void EnqueueCommand(Commands code, double param, MakeVisibleParams mvp)
        { 
            _queue.Enqueue(new Command(code, param, mvp));
            EnsureQueueProcessing(); 
        } 

        private void EnsureQueueProcessing() 
        {
            if(!_queue.IsEmpty())
            {
                EnsureLayoutUpdatedHandler(); 
            }
        } 
 
        // LayoutUpdated event handler.
        // 1. executes next queued command, if any 
        // 2. If no commands to execute, updates properties and fires events
        private void OnLayoutUpdated(object sender, EventArgs e)
        {
            // if there was a command, execute it and leave the handler for the next pass 
            if(ExecuteNextCommand())
            { 
                InvalidateArrange(); 
                return;
            } 

            double oldActualHorizontalOffset = HorizontalOffset;
            double oldActualVerticalOffset = VerticalOffset;
 
            double oldViewportWidth = ViewportWidth;
            double oldViewportHeight = ViewportHeight; 
 
            double oldExtentWidth = ExtentWidth;
            double oldExtentHeight = ExtentHeight; 

            double oldScrollableWidth = ScrollableWidth;
            double oldScrollableHeight = ScrollableHeight;
 
            bool changed = false;
 
            // 
            // Go through scrolling properties updating values.
            // 
            if (ScrollInfo != null && !DoubleUtil.AreClose(oldActualHorizontalOffset, ScrollInfo.HorizontalOffset))
            {
                _xPositionISI = ScrollInfo.HorizontalOffset;
                SetValue(HorizontalOffsetPropertyKey, _xPositionISI); 
                changed = true;
            } 
 
            if (ScrollInfo != null && !DoubleUtil.AreClose(oldActualVerticalOffset, ScrollInfo.VerticalOffset))
            { 
                _yPositionISI = ScrollInfo.VerticalOffset;
                SetValue(VerticalOffsetPropertyKey, _yPositionISI);
                changed = true;
            } 

            if (ScrollInfo != null && !DoubleUtil.AreClose(oldViewportWidth, ScrollInfo.ViewportWidth)) 
            { 
                _xSize = ScrollInfo.ViewportWidth;
                SetValue(ViewportWidthPropertyKey, _xSize); 
                changed = true;
            }

            if (ScrollInfo != null && !DoubleUtil.AreClose(oldViewportHeight, ScrollInfo.ViewportHeight)) 
            {
                _ySize = ScrollInfo.ViewportHeight; 
                SetValue(ViewportHeightPropertyKey, _ySize); 
                changed = true;
            } 

            if (ScrollInfo != null && !DoubleUtil.AreClose(oldExtentWidth, ScrollInfo.ExtentWidth))
            {
                _xExtent = ScrollInfo.ExtentWidth; 
                SetValue(ExtentWidthPropertyKey, _xExtent);
                changed = true; 
            } 

            if (ScrollInfo != null && !DoubleUtil.AreClose(oldExtentHeight, ScrollInfo.ExtentHeight)) 
            {
                _yExtent = ScrollInfo.ExtentHeight;
                SetValue(ExtentHeightPropertyKey, _yExtent);
                changed = true; 
            }
 
            // ScrollableWidth/Height are dependant on Viewport and Extent set above.  This check must be done after those. 
            double scrollableWidth = ScrollableWidth;
            if (!DoubleUtil.AreClose(oldScrollableWidth, ScrollableWidth)) 
            {
                SetValue(ScrollableWidthPropertyKey, scrollableWidth);
                changed = true;
            } 

            double scrollableHeight = ScrollableHeight; 
            if (!DoubleUtil.AreClose(oldScrollableHeight, ScrollableHeight)) 
            {
                SetValue(ScrollableHeightPropertyKey, scrollableHeight); 
                changed = true;
            }

            Debug.Assert(DoubleUtil.GreaterThanOrClose(_xSize, 0.0) && DoubleUtil.GreaterThanOrClose(_ySize, 0.0), "Negative size for scrolling viewport.  Bad IScrollInfo implementation."); 

 
            // 
            // Fire scrolling events.
            // 
            if(changed)
            {
                // Fire ScrollChange event
                ScrollChangedEventArgs args = new ScrollChangedEventArgs( 
                    new Vector(HorizontalOffset, VerticalOffset),
                    new Vector(HorizontalOffset - oldActualHorizontalOffset, VerticalOffset - oldActualVerticalOffset), 
                    new Size(ExtentWidth, ExtentHeight), 
                    new Vector(ExtentWidth - oldExtentWidth, ExtentHeight - oldExtentHeight),
                    new Size(ViewportWidth, ViewportHeight), 
                    new Vector(ViewportWidth - oldViewportWidth, ViewportHeight - oldViewportHeight));
                args.RoutedEvent = ScrollChangedEvent;
                args.Source = this;
 
                try
                { 
 
                    OnScrollChanged(args);
 
                    // Fire automation events if automation is active.
                    ScrollViewerAutomationPeer peer = UIElementAutomationPeer.FromElement(this) as ScrollViewerAutomationPeer;
                    if(peer != null)
                    { 
                        peer.RaiseAutomationEvents(oldExtentWidth,
                                                   oldExtentHeight, 
                                                   oldViewportWidth, 
                                                   oldViewportHeight,
                                                   oldActualHorizontalOffset, 
                                                   oldActualVerticalOffset);
                    }
                }
                finally 
                {
                    // 
                    // Disconnect the layout listener. 
                    //
                    ClearLayoutUpdatedHandler(); 
                }
            }

            ClearLayoutUpdatedHandler(); 
        }
 
 
        /// 
        /// Creates AutomationPeer () 
        /// 
        protected override AutomationPeer OnCreateAutomationPeer()
        {
            return new ScrollViewerAutomationPeer(this); 
        }
 
 
        /// 
        /// OnRequestBringIntoView is called from the event handler ScrollViewer registers for the event. 
        /// The default implementation checks to make sure the visual is a child of the IScrollInfo, and then
        /// delegates to a method there
        /// 
        /// The instance handling the event. 
        /// RequestBringIntoViewEventArgs indicates the element and region to scroll into view.
        private static void OnRequestBringIntoView(object sender, RequestBringIntoViewEventArgs e) 
        { 
            ScrollViewer sv = sender as ScrollViewer;
            Visual child = e.TargetObject as Visual; 

            //the event starts from the elemetn itself, so if it is an SV.BringINtoView we would
            //get an SV trying to bring into view itself  - this does not work obviously
            //so don't handle if the request is about ourselves, the event will bubble 
            if(child != null && child != sv && child.IsDescendantOf(sv))
            { 
                e.Handled = true; 
                sv.MakeVisible(child, e.TargetRect);
            } 
        }

        private static void OnScrollCommand(object target, ExecutedRoutedEventArgs args)
        { 
            if (args.Command == ScrollBar.LineLeftCommand)
            { 
                ((ScrollViewer)target).LineLeft(); 
            }
            else if (args.Command == ScrollBar.LineRightCommand) 
            {
                ((ScrollViewer)target).LineRight();
            }
            else if (args.Command == ScrollBar.PageLeftCommand) 
            {
                ((ScrollViewer)target).PageLeft(); 
            } 
            else if (args.Command == ScrollBar.PageRightCommand)
            { 
                ((ScrollViewer)target).PageRight();
            }
            else if (args.Command == ScrollBar.LineUpCommand)
            { 
                ((ScrollViewer)target).LineUp();
            } 
            else if (args.Command == ScrollBar.LineDownCommand) 
            {
                ((ScrollViewer)target).LineDown(); 
            }
            else if (   args.Command == ScrollBar.PageUpCommand
                    ||  args.Command == ComponentCommands.ScrollPageUp  )
            { 
                ((ScrollViewer)target).PageUp();
            } 
            else if (   args.Command == ScrollBar.PageDownCommand 
                    ||  args.Command == ComponentCommands.ScrollPageDown    )
            { 
                ((ScrollViewer)target).PageDown();
            }
            else if (args.Command == ScrollBar.ScrollToEndCommand)
            { 
                ((ScrollViewer)target).ScrollToEnd();
            } 
            else if (args.Command == ScrollBar.ScrollToHomeCommand) 
            {
                ((ScrollViewer)target).ScrollToHome(); 
            }
            else if (args.Command == ScrollBar.ScrollToLeftEndCommand)
            {
                ((ScrollViewer)target).ScrollToLeftEnd(); 
            }
            else if (args.Command == ScrollBar.ScrollToRightEndCommand) 
            { 
                ((ScrollViewer)target).ScrollToRightEnd();
            } 
            else if (args.Command == ScrollBar.ScrollToTopCommand)
            {
                ((ScrollViewer)target).ScrollToTop();
            } 
            else if (args.Command == ScrollBar.ScrollToBottomCommand)
            { 
                ((ScrollViewer)target).ScrollToBottom(); 
            }
            else if (args.Command == ScrollBar.ScrollToHorizontalOffsetCommand) 
            {
                if (args.Parameter is double) { ((ScrollViewer)target).ScrollToHorizontalOffset((double)args.Parameter); }
            }
            else if (args.Command == ScrollBar.ScrollToVerticalOffsetCommand) 
            {
                if (args.Parameter is double) { ((ScrollViewer)target).ScrollToVerticalOffset((double)args.Parameter); } 
            } 
        }
 
        private static void OnQueryScrollCommand(object target, CanExecuteRoutedEventArgs args)
        {
            args.CanExecute = true;
 
            //  ScrollViewer is capable of execution of the majority of commands.
            //  The only special case is the component commands below. 
            //  When scroll viewer is a primitive / part of another control 
            //  capable to handle scrolling - scroll viewer leaves it up
            //  to the control to deal with component commands... 
            if (    args.Command == ComponentCommands.ScrollPageUp
                ||  args.Command == ComponentCommands.ScrollPageDown    )
            {
                ScrollViewer scrollViewer = target as ScrollViewer; 
                Control templatedParentControl = scrollViewer != null ? scrollViewer.TemplatedParent as Control : null;
 
                if (    templatedParentControl != null 
                    &&  templatedParentControl.HandlesScrolling )
                { 
                    args.CanExecute = false;
                    args.ContinueRouting = true;
                }
            } 
        }
 
        private static void InitializeCommands() 
        {
            ExecutedRoutedEventHandler executeScrollCommandEventHandler = new ExecutedRoutedEventHandler(OnScrollCommand); 
            CanExecuteRoutedEventHandler canExecuteScrollCommandEventHandler = new CanExecuteRoutedEventHandler(OnQueryScrollCommand);

            CommandHelpers.RegisterCommandHandler(typeof(ScrollViewer), ScrollBar.LineLeftCommand,          executeScrollCommandEventHandler, canExecuteScrollCommandEventHandler);
            CommandHelpers.RegisterCommandHandler(typeof(ScrollViewer), ScrollBar.LineRightCommand,         executeScrollCommandEventHandler, canExecuteScrollCommandEventHandler); 
            CommandHelpers.RegisterCommandHandler(typeof(ScrollViewer), ScrollBar.PageLeftCommand,          executeScrollCommandEventHandler, canExecuteScrollCommandEventHandler);
            CommandHelpers.RegisterCommandHandler(typeof(ScrollViewer), ScrollBar.PageRightCommand,         executeScrollCommandEventHandler, canExecuteScrollCommandEventHandler); 
            CommandHelpers.RegisterCommandHandler(typeof(ScrollViewer), ScrollBar.LineUpCommand,            executeScrollCommandEventHandler, canExecuteScrollCommandEventHandler); 
            CommandHelpers.RegisterCommandHandler(typeof(ScrollViewer), ScrollBar.LineDownCommand,          executeScrollCommandEventHandler, canExecuteScrollCommandEventHandler);
            CommandHelpers.RegisterCommandHandler(typeof(ScrollViewer), ScrollBar.PageUpCommand,            executeScrollCommandEventHandler, canExecuteScrollCommandEventHandler); 
            CommandHelpers.RegisterCommandHandler(typeof(ScrollViewer), ScrollBar.PageDownCommand,          executeScrollCommandEventHandler, canExecuteScrollCommandEventHandler);
            CommandHelpers.RegisterCommandHandler(typeof(ScrollViewer), ScrollBar.ScrollToLeftEndCommand,   executeScrollCommandEventHandler, canExecuteScrollCommandEventHandler);
            CommandHelpers.RegisterCommandHandler(typeof(ScrollViewer), ScrollBar.ScrollToRightEndCommand,  executeScrollCommandEventHandler, canExecuteScrollCommandEventHandler);
            CommandHelpers.RegisterCommandHandler(typeof(ScrollViewer), ScrollBar.ScrollToEndCommand,       executeScrollCommandEventHandler, canExecuteScrollCommandEventHandler); 
            CommandHelpers.RegisterCommandHandler(typeof(ScrollViewer), ScrollBar.ScrollToHomeCommand,      executeScrollCommandEventHandler, canExecuteScrollCommandEventHandler);
            CommandHelpers.RegisterCommandHandler(typeof(ScrollViewer), ScrollBar.ScrollToTopCommand,       executeScrollCommandEventHandler, canExecuteScrollCommandEventHandler); 
            CommandHelpers.RegisterCommandHandler(typeof(ScrollViewer), ScrollBar.ScrollToBottomCommand,    executeScrollCommandEventHandler, canExecuteScrollCommandEventHandler); 
            CommandHelpers.RegisterCommandHandler(typeof(ScrollViewer), ScrollBar.ScrollToHorizontalOffsetCommand,  executeScrollCommandEventHandler, canExecuteScrollCommandEventHandler);
            CommandHelpers.RegisterCommandHandler(typeof(ScrollViewer), ScrollBar.ScrollToVerticalOffsetCommand,    executeScrollCommandEventHandler, canExecuteScrollCommandEventHandler); 

            CommandHelpers.RegisterCommandHandler(typeof(ScrollViewer), ComponentCommands.ScrollPageUp,     executeScrollCommandEventHandler, canExecuteScrollCommandEventHandler);
            CommandHelpers.RegisterCommandHandler(typeof(ScrollViewer), ComponentCommands.ScrollPageDown,   executeScrollCommandEventHandler, canExecuteScrollCommandEventHandler);
        } 

        // Creates the default control template for ScrollViewer. 
        private static ControlTemplate CreateDefaultControlTemplate() 
        {
            ControlTemplate template = null; 

            // Our default style is a 2x2 grid:
            //         // Grid
            //    
            //   
            //    
            //    
            //                                      // Cell 1-2, 1-2
            //      
            //   
            //                        // Cell 1, 2
            //                       // Cell 2, 1
            //  
            FrameworkElementFactory grid = new FrameworkElementFactory(typeof(Grid), "Grid");
            FrameworkElementFactory gridColumn1 = new FrameworkElementFactory(typeof(ColumnDefinition), "ColumnDefinitionOne"); 
            FrameworkElementFactory gridColumn2 = new FrameworkElementFactory(typeof(ColumnDefinition), "ColumnDefinitionTwo"); 
            FrameworkElementFactory gridRow1 = new FrameworkElementFactory(typeof(RowDefinition), "RowDefinitionOne");
            FrameworkElementFactory gridRow2 = new FrameworkElementFactory(typeof(RowDefinition), "RowDefinitionTwo"); 
            FrameworkElementFactory vsb = new FrameworkElementFactory(typeof(ScrollBar), VerticalScrollBarTemplateName);
            FrameworkElementFactory hsb = new FrameworkElementFactory(typeof(ScrollBar), HorizontalScrollBarTemplateName);
            FrameworkElementFactory content = new FrameworkElementFactory(typeof(ScrollContentPresenter), ScrollContentPresenterTemplateName);
            FrameworkElementFactory corner = new FrameworkElementFactory(typeof(Rectangle), "Corner"); 

            // Bind Actual HorizontalOffset to HorizontalScrollBar.Value 
            // Bind Actual VerticalOffset to VerticalScrollbar.Value 
            Binding bindingHorizontalOffset = new Binding("HorizontalOffset");
            bindingHorizontalOffset.Mode = BindingMode.OneWay; 
            bindingHorizontalOffset.RelativeSource = RelativeSource.TemplatedParent;
            Binding bindingVerticalOffset = new Binding("VerticalOffset");
            bindingVerticalOffset.Mode = BindingMode.OneWay;
            bindingVerticalOffset.RelativeSource = RelativeSource.TemplatedParent; 

            grid.SetValue(Grid.BackgroundProperty, new TemplateBindingExtension(BackgroundProperty)); 
            grid.AppendChild(gridColumn1); 
            grid.AppendChild(gridColumn2);
            grid.AppendChild(gridRow1); 
            grid.AppendChild(gridRow2);
            grid.AppendChild(corner);
            grid.AppendChild(content);
            grid.AppendChild(vsb); 
            grid.AppendChild(hsb);
 
            gridColumn1.SetValue(ColumnDefinition.WidthProperty, new GridLength(1.0, GridUnitType.Star)); 
            gridColumn2.SetValue(ColumnDefinition.WidthProperty, new GridLength(1.0, GridUnitType.Auto));
            gridRow1.SetValue(RowDefinition.HeightProperty, new GridLength(1.0, GridUnitType.Star)); 
            gridRow2.SetValue(RowDefinition.HeightProperty, new GridLength(1.0, GridUnitType.Auto));

            content.SetValue(Grid.ColumnProperty, 0);
            content.SetValue(Grid.RowProperty, 0); 
            content.SetValue(ContentPresenter.MarginProperty, new TemplateBindingExtension(PaddingProperty));
            content.SetValue(ContentProperty, new TemplateBindingExtension(ContentProperty)); 
            content.SetValue(ContentTemplateProperty, new TemplateBindingExtension(ContentTemplateProperty)); 
            content.SetValue(CanContentScrollProperty, new TemplateBindingExtension(CanContentScrollProperty));
 
            hsb.SetValue(ScrollBar.OrientationProperty, Orientation.Horizontal);
            hsb.SetValue(Grid.ColumnProperty, 0);
            hsb.SetValue(Grid.RowProperty, 1);
            hsb.SetValue(RangeBase.MinimumProperty, 0.0); 
            hsb.SetValue(RangeBase.MaximumProperty, new TemplateBindingExtension(ScrollableWidthProperty));
            hsb.SetValue(ScrollBar.ViewportSizeProperty, new TemplateBindingExtension(ViewportWidthProperty)); 
            hsb.SetBinding(RangeBase.ValueProperty, bindingHorizontalOffset); 
            hsb.SetValue(UIElement.VisibilityProperty, new TemplateBindingExtension(ComputedHorizontalScrollBarVisibilityProperty));
            hsb.SetValue(FrameworkElement.CursorProperty, Cursors.Arrow); 
            hsb.SetValue(AutomationProperties.AutomationIdProperty, "HorizontalScrollBar");

            vsb.SetValue(Grid.ColumnProperty, 1);
            vsb.SetValue(Grid.RowProperty, 0); 
            vsb.SetValue(RangeBase.MinimumProperty, 0.0);
            vsb.SetValue(RangeBase.MaximumProperty, new TemplateBindingExtension(ScrollableHeightProperty)); 
            vsb.SetValue(ScrollBar.ViewportSizeProperty, new TemplateBindingExtension(ViewportHeightProperty)); 
            vsb.SetBinding(RangeBase.ValueProperty, bindingVerticalOffset);
            vsb.SetValue(UIElement.VisibilityProperty, new TemplateBindingExtension(ComputedVerticalScrollBarVisibilityProperty)); 
            vsb.SetValue(FrameworkElement.CursorProperty, Cursors.Arrow);
            vsb.SetValue(AutomationProperties.AutomationIdProperty, "VerticalScrollBar");

            corner.SetValue(Grid.ColumnProperty, 1); 
            corner.SetValue(Grid.RowProperty, 1);
            corner.SetResourceReference(Rectangle.FillProperty, SystemColors.ControlBrushKey); 
 
            template = new ControlTemplate(typeof(ScrollViewer));
            template.VisualTree = grid; 
            template.Seal();

            return (template);
        } 

        #endregion 
 

        //-------------------------------------------------------------------- 
        //
        //  Private Fields
        //
        //------------------------------------------------------------------- 

        #region Private Fields 
 
        // Scrolling physical "line" metrics.
        internal const double _scrollLineDelta = 16.0;   // Default physical amount to scroll with one Up/Down/Left/Right key 
        internal const double _mouseWheelDelta = 48.0;   // Default physical amount to scroll with one MouseWheel.

        private const string HorizontalScrollBarTemplateName = "PART_HorizontalScrollBar";
        private const string VerticalScrollBarTemplateName = "PART_VerticalScrollBar"; 
        internal const string ScrollContentPresenterTemplateName = "PART_ScrollContentPresenter";
 
        // Property caching 
        private Visibility _scrollVisibilityX;
        private Visibility _scrollVisibilityY; 

        // Scroll property values - cache of what was computed by ISI
        private double _xPositionISI;
        private double _yPositionISI; 
        private double _xExtent;
        private double _yExtent; 
        private double _xSize; 
        private double _ySize;
 
        // Event/infrastructure
        private EventHandler _layoutUpdatedHandler;
        private IScrollInfo _scrollInfo;
 
        private CommandQueue _queue;
        private bool InMeasure; 
        internal bool InChildInvalidateMeasure = false; 

        private bool _handlesMouseWheelScrolling = true; 

        #endregion

        //-------------------------------------------------------------------- 
        //
        //  Static Constructors & Delegates 
        // 
        //-------------------------------------------------------------------
 
        #region Static Constructors & Delegates

        static ScrollViewer()
        { 
            DefaultStyleKeyProperty.OverrideMetadata(typeof(ScrollViewer), new FrameworkPropertyMetadata(typeof(ScrollViewer)));
            _dType = DependencyObjectType.FromSystemTypeInternal(typeof(ScrollViewer)); 
 
            InitializeCommands();
 
            ControlTemplate template = CreateDefaultControlTemplate();
            Control.TemplateProperty.OverrideMetadata(typeof(ScrollViewer), new FrameworkPropertyMetadata(template));
            IsTabStopProperty.OverrideMetadata(typeof(ScrollViewer), new FrameworkPropertyMetadata(BooleanBoxes.FalseBox));
            KeyboardNavigation.DirectionalNavigationProperty.OverrideMetadata(typeof(ScrollViewer), new FrameworkPropertyMetadata(KeyboardNavigationMode.Local)); 

            EventManager.RegisterClassHandler(typeof(ScrollViewer), RequestBringIntoViewEvent, new RequestBringIntoViewEventHandler(OnRequestBringIntoView)); 
        } 

        private static bool IsValidScrollBarVisibility(object o) 
        {
            ScrollBarVisibility value = (ScrollBarVisibility)o;
            return (value == ScrollBarVisibility.Disabled
                || value == ScrollBarVisibility.Auto 
                || value == ScrollBarVisibility.Hidden
                || value == ScrollBarVisibility.Visible); 
        } 

        // 
        //  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

        #region DTypeThemeStyleKey
 
        // Returns the DependencyObjectType for the registered ThemeStyleKey's default
        // value. Controls will override this method to return approriate types. 
        internal override DependencyObjectType DTypeThemeStyleKey 
        {
            get { return _dType; } 
        }

        private static DependencyObjectType _dType;
 
        #endregion DTypeThemeStyleKey
    } 
} 


// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.


                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK