ScrollViewer.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Net / Net / 3.5.50727.3053 / DEVDIV / depot / DevDiv / releases / Orcas / SP / wpf / src / Framework / System / Windows / Controls / ScrollViewer.cs / 1 / 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");

            // Queue up the scroll command, which tells the content to scroll.
            // Will lead to an update of all offsets (both live and deferred). 
            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"); 

            // Queue up the scroll command, which tells the content to scroll. 
            // Will lead to an update of all offsets (both live and deferred). 
            EnqueueCommand(Commands.SetVerticalOffset, validatedOffset, null);
        } 

        private void DeferScrollToHorizontalOffset(double offset)
        {
            double validatedOffset = ScrollContentPresenter.ValidateInputOffset(offset, "offset"); 

            // Update the offset property but not the deferred (content offset) 
            // property, which will be updated when the drag operation is complete. 
            HorizontalOffset = validatedOffset;
        } 

        private void DeferScrollToVerticalOffset(double offset)
        {
            double validatedOffset = ScrollContentPresenter.ValidateInputOffset(offset, "offset"); 

            // Update the offset property but not the deferred (content offset) 
            // property, which will be updated when the drag operation is complete. 
            VerticalOffset = validatedOffset;
        } 

        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
        {
            // _xPositionISI is a local cache of GetValue(HorizontalOffsetProperty) 
            // In the future, it could be replaced with the GetValue call.
            get { return _xPositionISI; } 
            private set { SetValue(HorizontalOffsetPropertyKey, value); } 
        }
 
        /// 
        /// 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
        { 
            // _yPositionISI is a local cache of GetValue(VerticalOffsetProperty) 
            // In the future, it could be replaced with the GetValue call.
            get { return _yPositionISI; } 
            private set { SetValue(VerticalOffsetPropertyKey, value); }
        }

        ///  
        /// 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;
 
        /// 
        ///     When not doing live scrolling, this is the offset value where the 
        ///     content is visually located. 
        /// 
        private static readonly DependencyPropertyKey ContentVerticalOffsetPropertyKey = 
            DependencyProperty.RegisterReadOnly(
                        "ContentVerticalOffset",
                        typeof(double),
                        typeof(ScrollViewer), 
                        new FrameworkPropertyMetadata(0d));
 
        ///  
        ///     DependencyProperty for  property.
        ///  
        public static readonly DependencyProperty ContentVerticalOffsetProperty =
            ContentVerticalOffsetPropertyKey.DependencyProperty;

        ///  
        ///     When not doing live scrolling, this is the offset value where the
        ///     content is visually located. 
        ///  
        public double ContentVerticalOffset
        { 
            get
            {
                return (double)GetValue(ContentVerticalOffsetProperty);
            } 

            private set 
            { 
                SetValue(ContentVerticalOffsetPropertyKey, value);
            } 
        }

        /// 
        ///     When not doing live scrolling, this is the offset value where the 
        ///     content is visually located.
        ///  
        private static readonly DependencyPropertyKey ContentHorizontalOffsetPropertyKey = 
            DependencyProperty.RegisterReadOnly(
                        "ContentHorizontalOffset", 
                        typeof(double),
                        typeof(ScrollViewer),
                        new FrameworkPropertyMetadata(0d));
 
        /// 
        ///     DependencyProperty for  property. 
        ///  
        public static readonly DependencyProperty ContentHorizontalOffsetProperty =
            ContentHorizontalOffsetPropertyKey.DependencyProperty; 

        /// 
        ///     When not doing live scrolling, this is the offset value where the
        ///     content is visually located. 
        /// 
        public double ContentHorizontalOffset 
        { 
            get
            { 
                return (double)GetValue(ContentHorizontalOffsetProperty);
            }

            private set 
            {
                SetValue(ContentHorizontalOffsetPropertyKey, value); 
            } 
        }
 
        /// 
        ///     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; 
 
        /// 
        ///     DependencyProperty that indicates whether the ScrollViewer should 
        ///     scroll contents immediately during a thumb drag or defer until
        ///     a drag completes.
        /// 
        public static readonly DependencyProperty IsDeferredScrollingEnabledProperty = DependencyProperty.RegisterAttached("IsDeferredScrollingEnabled", typeof(bool), typeof(ScrollViewer), new FrameworkPropertyMetadata(BooleanBoxes.FalseBox)); 

        ///  
        ///     Gets the value of IsDeferredScrollingEnabled. 
        /// 
        /// The element on which to query the property. 
        /// The value of the property.
        public static bool GetIsDeferredScrollingEnabled(DependencyObject element)
        {
            if (element == null) 
            {
                throw new ArgumentNullException("element"); 
            } 

            return (bool)element.GetValue(IsDeferredScrollingEnabledProperty); 
        }

        /// 
        ///     Sets the value of IsDeferredScrollingEnabled. 
        /// 
        /// The element on which to set the property. 
        /// The new value of the property. 
        public static void SetIsDeferredScrollingEnabled(DependencyObject element, bool value)
        { 
            if (element == null)
            {
                throw new ArgumentNullException("element");
            } 

            element.SetValue(IsDeferredScrollingEnabledProperty, BooleanBoxes.Box(value)); 
        } 

        ///  
        ///     Indicates whether the ScrollViewer should scroll contents
        ///     immediately during a thumb drag or defer until a drag completes.
        /// 
        public bool IsDeferredScrollingEnabled 
        {
            get 
            { 
                return (bool)GetValue(IsDeferredScrollingEnabledProperty);
            } 

            set
            {
                SetValue(IsDeferredScrollingEnabledProperty, BooleanBoxes.Box(value)); 
            }
        } 
 
        #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);
                BindToTemplatedParent(IsDeferredScrollingEnabledProperty); 
            }
        }

        ///  
        /// 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;
                HorizontalOffset = _xPositionISI; 
                ContentHorizontalOffset = _xPositionISI;
                changed = true; 
            } 

            if (ScrollInfo != null && !DoubleUtil.AreClose(oldActualVerticalOffset, ScrollInfo.VerticalOffset)) 
            {
                _yPositionISI = ScrollInfo.VerticalOffset;
                VerticalOffset = _yPositionISI;
                ContentVerticalOffset = _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.DeferScrollToHorizontalOffsetCommand) 
            {
                if (args.Parameter is double) { ((ScrollViewer)target).DeferScrollToHorizontalOffset((double)args.Parameter); } 
            }
            else if (args.Command == ScrollBar.DeferScrollToVerticalOffsetCommand)
            {
                if (args.Parameter is double) { ((ScrollViewer)target).DeferScrollToVerticalOffset((double)args.Parameter); } 
            }
            else 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;
                } 
            }
            else if ((args.Command == ScrollBar.DeferScrollToHorizontalOffsetCommand) || 
                     (args.Command == ScrollBar.DeferScrollToVerticalOffsetCommand)) 
            {
                // The scroll bar has indicated that a drag operation is in progress. 
                // If deferred scrolling is disabled, then mark the command as
                // not executable so that the scroll bar will fire the regular scroll
                // command, and the scroll viewer will do live scrolling.
                ScrollViewer scrollViewer = target as ScrollViewer; 
                if ((scrollViewer != null) && !scrollViewer.IsDeferredScrollingEnabled)
                { 
                    args.CanExecute = false; 
                }
            } 
        }

        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), ScrollBar.DeferScrollToHorizontalOffsetCommand, executeScrollCommandEventHandler, canExecuteScrollCommandEventHandler); 
            CommandHelpers.RegisterCommandHandler(typeof(ScrollViewer), ScrollBar.DeferScrollToVerticalOffsetCommand,   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.
//---------------------------------------------------------------------------- 
//
// 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");

            // Queue up the scroll command, which tells the content to scroll.
            // Will lead to an update of all offsets (both live and deferred). 
            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"); 

            // Queue up the scroll command, which tells the content to scroll. 
            // Will lead to an update of all offsets (both live and deferred). 
            EnqueueCommand(Commands.SetVerticalOffset, validatedOffset, null);
        } 

        private void DeferScrollToHorizontalOffset(double offset)
        {
            double validatedOffset = ScrollContentPresenter.ValidateInputOffset(offset, "offset"); 

            // Update the offset property but not the deferred (content offset) 
            // property, which will be updated when the drag operation is complete. 
            HorizontalOffset = validatedOffset;
        } 

        private void DeferScrollToVerticalOffset(double offset)
        {
            double validatedOffset = ScrollContentPresenter.ValidateInputOffset(offset, "offset"); 

            // Update the offset property but not the deferred (content offset) 
            // property, which will be updated when the drag operation is complete. 
            VerticalOffset = validatedOffset;
        } 

        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
        {
            // _xPositionISI is a local cache of GetValue(HorizontalOffsetProperty) 
            // In the future, it could be replaced with the GetValue call.
            get { return _xPositionISI; } 
            private set { SetValue(HorizontalOffsetPropertyKey, value); } 
        }
 
        /// 
        /// 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
        { 
            // _yPositionISI is a local cache of GetValue(VerticalOffsetProperty) 
            // In the future, it could be replaced with the GetValue call.
            get { return _yPositionISI; } 
            private set { SetValue(VerticalOffsetPropertyKey, value); }
        }

        ///  
        /// 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;
 
        /// 
        ///     When not doing live scrolling, this is the offset value where the 
        ///     content is visually located. 
        /// 
        private static readonly DependencyPropertyKey ContentVerticalOffsetPropertyKey = 
            DependencyProperty.RegisterReadOnly(
                        "ContentVerticalOffset",
                        typeof(double),
                        typeof(ScrollViewer), 
                        new FrameworkPropertyMetadata(0d));
 
        ///  
        ///     DependencyProperty for  property.
        ///  
        public static readonly DependencyProperty ContentVerticalOffsetProperty =
            ContentVerticalOffsetPropertyKey.DependencyProperty;

        ///  
        ///     When not doing live scrolling, this is the offset value where the
        ///     content is visually located. 
        ///  
        public double ContentVerticalOffset
        { 
            get
            {
                return (double)GetValue(ContentVerticalOffsetProperty);
            } 

            private set 
            { 
                SetValue(ContentVerticalOffsetPropertyKey, value);
            } 
        }

        /// 
        ///     When not doing live scrolling, this is the offset value where the 
        ///     content is visually located.
        ///  
        private static readonly DependencyPropertyKey ContentHorizontalOffsetPropertyKey = 
            DependencyProperty.RegisterReadOnly(
                        "ContentHorizontalOffset", 
                        typeof(double),
                        typeof(ScrollViewer),
                        new FrameworkPropertyMetadata(0d));
 
        /// 
        ///     DependencyProperty for  property. 
        ///  
        public static readonly DependencyProperty ContentHorizontalOffsetProperty =
            ContentHorizontalOffsetPropertyKey.DependencyProperty; 

        /// 
        ///     When not doing live scrolling, this is the offset value where the
        ///     content is visually located. 
        /// 
        public double ContentHorizontalOffset 
        { 
            get
            { 
                return (double)GetValue(ContentHorizontalOffsetProperty);
            }

            private set 
            {
                SetValue(ContentHorizontalOffsetPropertyKey, value); 
            } 
        }
 
        /// 
        ///     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; 
 
        /// 
        ///     DependencyProperty that indicates whether the ScrollViewer should 
        ///     scroll contents immediately during a thumb drag or defer until
        ///     a drag completes.
        /// 
        public static readonly DependencyProperty IsDeferredScrollingEnabledProperty = DependencyProperty.RegisterAttached("IsDeferredScrollingEnabled", typeof(bool), typeof(ScrollViewer), new FrameworkPropertyMetadata(BooleanBoxes.FalseBox)); 

        ///  
        ///     Gets the value of IsDeferredScrollingEnabled. 
        /// 
        /// The element on which to query the property. 
        /// The value of the property.
        public static bool GetIsDeferredScrollingEnabled(DependencyObject element)
        {
            if (element == null) 
            {
                throw new ArgumentNullException("element"); 
            } 

            return (bool)element.GetValue(IsDeferredScrollingEnabledProperty); 
        }

        /// 
        ///     Sets the value of IsDeferredScrollingEnabled. 
        /// 
        /// The element on which to set the property. 
        /// The new value of the property. 
        public static void SetIsDeferredScrollingEnabled(DependencyObject element, bool value)
        { 
            if (element == null)
            {
                throw new ArgumentNullException("element");
            } 

            element.SetValue(IsDeferredScrollingEnabledProperty, BooleanBoxes.Box(value)); 
        } 

        ///  
        ///     Indicates whether the ScrollViewer should scroll contents
        ///     immediately during a thumb drag or defer until a drag completes.
        /// 
        public bool IsDeferredScrollingEnabled 
        {
            get 
            { 
                return (bool)GetValue(IsDeferredScrollingEnabledProperty);
            } 

            set
            {
                SetValue(IsDeferredScrollingEnabledProperty, BooleanBoxes.Box(value)); 
            }
        } 
 
        #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);
                BindToTemplatedParent(IsDeferredScrollingEnabledProperty); 
            }
        }

        ///  
        /// 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;
                HorizontalOffset = _xPositionISI; 
                ContentHorizontalOffset = _xPositionISI;
                changed = true; 
            } 

            if (ScrollInfo != null && !DoubleUtil.AreClose(oldActualVerticalOffset, ScrollInfo.VerticalOffset)) 
            {
                _yPositionISI = ScrollInfo.VerticalOffset;
                VerticalOffset = _yPositionISI;
                ContentVerticalOffset = _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.DeferScrollToHorizontalOffsetCommand) 
            {
                if (args.Parameter is double) { ((ScrollViewer)target).DeferScrollToHorizontalOffset((double)args.Parameter); } 
            }
            else if (args.Command == ScrollBar.DeferScrollToVerticalOffsetCommand)
            {
                if (args.Parameter is double) { ((ScrollViewer)target).DeferScrollToVerticalOffset((double)args.Parameter); } 
            }
            else 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;
                } 
            }
            else if ((args.Command == ScrollBar.DeferScrollToHorizontalOffsetCommand) || 
                     (args.Command == ScrollBar.DeferScrollToVerticalOffsetCommand)) 
            {
                // The scroll bar has indicated that a drag operation is in progress. 
                // If deferred scrolling is disabled, then mark the command as
                // not executable so that the scroll bar will fire the regular scroll
                // command, and the scroll viewer will do live scrolling.
                ScrollViewer scrollViewer = target as ScrollViewer; 
                if ((scrollViewer != null) && !scrollViewer.IsDeferredScrollingEnabled)
                { 
                    args.CanExecute = false; 
                }
            } 
        }

        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), ScrollBar.DeferScrollToHorizontalOffsetCommand, executeScrollCommandEventHandler, canExecuteScrollCommandEventHandler); 
            CommandHelpers.RegisterCommandHandler(typeof(ScrollViewer), ScrollBar.DeferScrollToVerticalOffsetCommand,   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