DocumentViewer.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / wpf / src / Framework / System / Windows / Controls / DocumentViewer.cs / 1305600 / DocumentViewer.cs

                            //---------------------------------------------------------------------------- 
//
// 
//    Copyright (C) Microsoft Corporation.  All rights reserved.
//  
//
// 
// Description: Control for displaying paginated content. 
//
// History: 
// 06/01/2002 - JerrySh - Created.
// 07/09/2003 - JDersch - Initial port to WCP tree
// 11/07/2003 - JDersch - VisualTree Styling overhaul
// 09/21/2004 - JDersch - Cut Annotations, RM & DigSig and Browser-Hosted Toolband 
// 09/23/2004 - JeremyNS - Cut INavigator, IUriContext, SourceProperty
// 10/21/2004 - JeremyNS - Overhauled, and renamed from PageViewer to DocumentViewer 
// 05/10/2005 - JDersch - Ported to DocumentViewerBase 
//
//--------------------------------------------------------------------------- 

using MS.Internal;                                      // For Invariant.Assert
using MS.Internal.Commands;
using MS.Internal.Documents; 
using MS.Utility;
using System; 
using System.Collections; 
using System.Collections.Generic;
using System.Collections.ObjectModel; 
using System.ComponentModel;                            // For DesignerSerializationVisibility
using System.Globalization;
using System.Reflection;
using System.Windows; 
using System.Windows.Automation;
using System.Windows.Automation.Peers; 
using System.Windows.Automation.Provider; 
using System.Windows.Controls;
using System.Windows.Controls.Primitives; 
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Navigation;                        // For HyperLink navigation event. 
using System.Windows.Markup;
using MS.Internal.Automation;                           // For TextAdaptor. 
using System.Security; 

 
namespace System.Windows.Controls
{

    ///  
    /// DocumentViewer is a control that allows developers to create a custom reading
    /// experience in their applications for digital documents. 
    ///  
    /// 
    /// http://d2/DRX/default.aspx 
    [TemplatePart(Name = "PART_FindToolBarHost", Type = typeof(ContentControl))]
    [TemplatePart(Name = "PART_ContentHost", Type = typeof(ScrollViewer))]
    public class DocumentViewer : DocumentViewerBase
    { 

        //----------------------------------------------------- 
        // 
        //  Constructors
        // 
        //-----------------------------------------------------

        #region Constructors
        ///  
        /// Initializes class-wide settings.
        ///  
        static DocumentViewer() 
        {
            // Create our CommandBindings 
            CreateCommandBindings();

            // Register property metadata
            RegisterMetadata(); 
        }
 
        ///  
        /// Instantiates a new instance of a DocumentViewer
        ///  
        public DocumentViewer() : base()
        {
            //Perf Tracing - DocumentViewer Construction
            EventTrace.EasyTraceEvent(EventTrace.Keyword.KeywordXPS, EventTrace.Event.WClientDRXInstantiated); 

            SetUp(); 
        } 

        #endregion Constructors 

        //------------------------------------------------------
        //
        //  Public Methods 
        //
        //----------------------------------------------------- 
 
        #region Public Methods
 
        #region Command convenience methods

        /// 
        /// Tells DocumentViewer to display a "thumbnail view" of pages.  This is analogous 
        /// to the ViewThumbnailsCommand.
        ///  
        public void ViewThumbnails() 
        {
            OnViewThumbnailsCommand(); 
        }

        /// 
        /// Tells DocumentViewer to fit a single page to the width of the current viewport. 
        /// This is analogous to the FitToWidthCommand.
        ///  
        public void FitToWidth() 
        {
            OnFitToWidthCommand(); 
        }

        /// 
        /// Tells DocumentViewer to fit a single page to the height of the current viewport. 
        /// This is analogous to the FitToHeightCommand.
        ///  
        public void FitToHeight() 
        {
            OnFitToHeightCommand(); 
        }

        /// 
        /// Tells DocumentViewer to fit the current MaxPagesAcross count to the current 
        /// viewport.  This is analogous to the FitToMaxPagesAcrossCommand.
        ///  
        public void FitToMaxPagesAcross() 
        {
            OnFitToMaxPagesAcrossCommand(); 
        }

        /// 
        /// Tells DocumentViewer to fit the specified number of pages across to the current viewport 
        /// and sets MaxPagesAcross to the passed in value.  This is analogous to the
        /// FitMaxPagesAcrossCommand. 
        ///  
        /// 
        public void FitToMaxPagesAcross(int pagesAcross) 
        {
            if (ValidateMaxPagesAcross(pagesAcross))
            {
                if (_documentScrollInfo != null) 
                {
                    _documentScrollInfo.FitColumns(pagesAcross); 
                } 
            }
            else 
            {
                throw new ArgumentOutOfRangeException("pagesAcross");
            }
        } 

        ///  
        /// Tells DocumentViewer to invoke the Find Dialog.  This is analogous to the 
        /// FindCommand.
        ///  
        public void Find()
        {
            OnFindCommand();
        } 

        ///  
        /// Tells DocumentViewer to scroll up by one viewport.  This is analogous to the 
        /// ScrollPageUpCommand.
        ///  
        public void ScrollPageUp()
        {
            OnScrollPageUpCommand();
        } 

        ///  
        /// Tells DocumentViewer to scroll down by one viewport.  This is analogous to the 
        /// ScrollPageDownCommand.
        ///  
        public void ScrollPageDown()
        {
            OnScrollPageDownCommand();
        } 

        ///  
        /// Tells DocumentViewer to scroll left by one viewport.  This is analogous to the 
        /// ScrollPageLeftCommand.
        ///  
        public void ScrollPageLeft()
        {
            OnScrollPageLeftCommand();
        } 

        ///  
        /// Tells DocumentViewer to scroll right by one viewport.  This is analogous to the 
        /// ScrollPageRightCommand.
        ///  
        public void ScrollPageRight()
        {
            OnScrollPageRightCommand();
        } 

        ///  
        /// Tells DocumentViewer to scroll up by one line (16px).  This is analogous to the 
        /// MoveUpCommand.
        ///  
        public void MoveUp()
        {
            OnMoveUpCommand();
        } 

        ///  
        /// Tells DocumentViewer to scroll down by one line (16px).  This is analogous to the 
        /// MoveDownCommand.
        ///  
        public void MoveDown()
        {
            OnMoveDownCommand();
        } 

        ///  
        /// Tells DocumentViewer to scroll left by one line (16px).  This is analogous to the 
        /// MoveLeftCommand.
        ///  
        public void MoveLeft()
        {
            OnMoveLeftCommand();
        } 

        ///  
        /// Tells DocumentViewer to scroll right by one line (16px).  This is analogous to the 
        /// MoveRightCommand.
        ///  
        public void MoveRight()
        {
            OnMoveRightCommand();
        } 

        ///  
        /// Tells DocumentViewer to increase Zoom by a predefined, nonlinear value.  This is 
        /// analogous to the IncreaseZoomCommand.
        ///  
        public void IncreaseZoom()
        {
            OnIncreaseZoomCommand();
        } 

        ///  
        /// Tells DocumentViewer to decrease Zoom by a predefined, nonlinear value.  This is 
        /// analogous to the DecreaseZoomCommand.
        ///  
        public void DecreaseZoom()
        {
            OnDecreaseZoomCommand();
        } 

        #endregion Command convenience methods 
 
        /// 
        /// Called when the Template's tree has been generated 
        /// 
        /// 
        /// This method is commonly used to check the status of the visual
        /// tree prior to rendering, so that elements of the tree can be 
        /// customized before they are shown.
        /// If a style is changed that affects the visual tree, the 
        /// ApplyTemplate method will expand the new visual tree and return 
        /// true. Otherwise, it will return false.
        /// When overriding this method, be sure to call the ApplyTemplate 
        /// method of the base class.
        /// 
        /// 
        /// True if the Visual Tree has been created 
        /// 
        /// There must be a ScrollViewer in 
        /// DocumentViewer's visual tree which has Name PART_ContentHost. 
        public override void OnApplyTemplate()
        { 
            base.OnApplyTemplate();

            // Walk the visual tree, locating those elements marked with the special
            // properties such as "I'm the Content area!" 
            FindContentHost();
 
            // Create the Find toolbar and add it to our Visual Tree when appropriate. 
            InstantiateFindToolBar();
 
            //Perf Tracing - DocumentViewer Visuals Created
            EventTrace.EasyTraceEvent(EventTrace.Keyword.KeywordXPS, EventTrace.Event.WClientDRXStyleCreated);

            // If unset, we will set the ContextMenu property to null -- this will prevent the TextEditor 
            // from overriding our ContextMenu with its own.  The TextEditor checks the UIScope (DocumentViewer)
            // not the RenderScope (DocumentGrid) for previously-set Context Menus, and if it finds one (or if 
            // it finds that ContextMenu has explicitly been set to null, it will not override it. 
            // Since DocumentViewer doesn't have a ContextMenu -- the ContextMenu is set on DocumentGrid which the
            // TextEditor won't find, we set ContextMenu to null here. 
            // Yes, this seems, on the surface, to be a bit redundant -- but there is a difference between an
            // "unset null" and an "explicitly set" null to the Property engine that the TextEditor looks for.
            // We check that the ContextMenu is null because we don't want to override any user-specified ContextMenus.
            if (this.ContextMenu == null) 
            {
                this.ContextMenu = null; 
            } 
        }
 
        #endregion Public Methods

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

        #region Public Properties 

        #region Commands

        ///  
        /// This command will invoke ViewThumbnails method, causing as many pages
        /// as feasible to be displayed in the current viewport. 
        ///  
        public static RoutedUICommand ViewThumbnailsCommand
        { 
             get
             {
                 return _viewThumbnailsCommand;
             } 
        }
 
        ///  
        /// This command will invoke the FitToWidth method,
        /// setting the layout to 1 page across, and zooming so that one page is displayed 
        /// at the width of the current viewport.
        /// 
        public static RoutedUICommand FitToWidthCommand
        { 
            get
            { 
                return _fitToWidthCommand; 
            }
        } 

        /// 
        /// This command will invoke the FitToWidth method,
        /// setting the layout to 1 page across, and zooming so that one page is displayed 
        /// at the height of the current viewport.
        ///  
        public static RoutedUICommand FitToHeightCommand 
        {
            get 
            {
                return _fitToHeightCommand;
            }
        } 

        ///  
        /// This command will invoke the FitToMaxPagesAcross method, 
        /// effectively setting MaxPagesAcross
        /// to the value of the parameter and fitting those pages into view. 
        /// 
        public static RoutedUICommand FitToMaxPagesAcrossCommand
        {
            get 
            {
                return _fitToMaxPagesAcrossCommand; 
            } 
        }
 
        #endregion Commands

        #region Dependency Properties
 
        #region HorizontalOffset
        ///  
        /// Reflects the current Horizontal position in the document in pixel units given 
        /// the current page layout.
        ///  
        public static readonly DependencyProperty HorizontalOffsetProperty =
                DependencyProperty.Register(
                        "HorizontalOffset",
                        typeof(double), 
                        typeof(DocumentViewer),
                        new FrameworkPropertyMetadata( 
                                _horizontalOffsetDefault, //default value 
                                FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, //MetaData flags
                                new PropertyChangedCallback(OnHorizontalOffsetChanged)), //changed callback 
                        new ValidateValueCallback(ValidateOffset)); //validate callback

        /// 
        /// Reflects the current Horizontal position in the document in pixel units given 
        /// the current page layout.
        ///  
        public double HorizontalOffset 
        {
            get { return (double) GetValue(HorizontalOffsetProperty); } 
            set
            {
                SetValue(HorizontalOffsetProperty, value);
            } 
        }
        #endregion HorizontalOffset 
 
        #region VerticalOffset
        ///  
        /// Reflects the current Vertical position in the document in pixel units given
        /// the current page layout.
        /// 
        public static readonly DependencyProperty VerticalOffsetProperty = 
                DependencyProperty.Register(
                        "VerticalOffset", 
                        typeof(double), 
                        typeof(DocumentViewer),
                        new FrameworkPropertyMetadata( 
                                _verticalOffsetDefault, //default value
                                FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, //MetaData flags
                                new PropertyChangedCallback(OnVerticalOffsetChanged)), //changed callback
                        new ValidateValueCallback(ValidateOffset)); //validate callback 

        ///  
        /// Reflects the current Vertical position in the document in pixel units given 
        /// the current page layout.
        ///  
        public double VerticalOffset
        {
            get { return (double) GetValue(VerticalOffsetProperty); }
            set 
            {
                SetValue(VerticalOffsetProperty, value); 
            } 
        }
        #endregion VerticalOffset 

        #region ExtentWidth
        /// 
        /// Reflects the current width of the document layout. 
        /// 
        private static readonly DependencyPropertyKey ExtentWidthPropertyKey = 
                DependencyProperty.RegisterReadOnly( 
                        "ExtentWidth",
                        typeof(double), 
                        typeof(DocumentViewer),
                        new FrameworkPropertyMetadata(
                                _extentWidthDefault,
                                new PropertyChangedCallback(OnExtentWidthChanged))); 

        ///  
        /// Reflects the current width of the document layout. 
        /// 
        public static readonly DependencyProperty ExtentWidthProperty = 
                ExtentWidthPropertyKey.DependencyProperty;

        /// 
        /// Reflects the current width of the document layout. 
        /// 
        public double ExtentWidth 
        { 
            get { return (double) GetValue(ExtentWidthProperty); }
        } 
        #endregion ExtentWidth

        #region ExtentHeight
        ///  
        /// Reflects the current height of the document layout.
        ///  
        private static readonly DependencyPropertyKey ExtentHeightPropertyKey = 
                DependencyProperty.RegisterReadOnly(
                        "ExtentHeight", 
                        typeof(double),
                        typeof(DocumentViewer),
                        new FrameworkPropertyMetadata(
                                _extentHeightDefault, 
                                new PropertyChangedCallback(OnExtentHeightChanged)));
 
        ///  
        /// Reflects the current height of the document layout.
        ///  
        public static readonly DependencyProperty ExtentHeightProperty =
                ExtentHeightPropertyKey.DependencyProperty;

        ///  
        /// Reflects the current height of the document layout.
        ///  
        public double ExtentHeight 
        {
            get { return (double) GetValue(ExtentHeightProperty); } 
        }
        #endregion ExtentHeight

        #region ViewportWidth 
        /// 
        /// Reflects the current width of the DocumentViewer's content area. 
        ///  
        private static readonly DependencyPropertyKey ViewportWidthPropertyKey =
                DependencyProperty.RegisterReadOnly( 
                        "ViewportWidth",
                        typeof(double),
                        typeof(DocumentViewer),
                        new FrameworkPropertyMetadata( 
                                _viewportWidthDefault,
                                new PropertyChangedCallback(OnViewportWidthChanged))); 
 

        ///  
        /// Reflects the current width of the DocumentViewer's content area.
        /// 
        public static readonly DependencyProperty ViewportWidthProperty =
                ViewportWidthPropertyKey.DependencyProperty; 

        ///  
        /// Reflects the current width of the DocumentViewer's content area. 
        /// 
        public double ViewportWidth 
        {
            get { return (double) GetValue(ViewportWidthProperty); }
        }
        #endregion ViewportWidth 

        #region ViewportHeight 
        ///  
        /// Reflects the current height of the DocumentViewer's content area.
        ///  
        private static readonly DependencyPropertyKey ViewportHeightPropertyKey =
                DependencyProperty.RegisterReadOnly(
                        "ViewportHeight",
                        typeof(double), 
                        typeof(DocumentViewer),
                        new FrameworkPropertyMetadata( 
                                _viewportHeightDefault, 
                                new PropertyChangedCallback(OnViewportHeightChanged)));
 
        /// 
        /// Reflects the current height of the DocumentViewer's content area.
        /// 
        public static readonly DependencyProperty ViewportHeightProperty = 
                ViewportHeightPropertyKey.DependencyProperty;
 
        ///  
        /// Reflects the current height of the DocumentViewer's content area.
        ///  
        public double ViewportHeight
        {
            get { return (double) GetValue(ViewportHeightProperty);  }
        } 
        #endregion ViewportHeight
 
        #region ShowPageBorders 
        /// 
        /// Reflects whether a "Drop Shadow" border should be shown around the pages being displayed. 
        /// 
        public static readonly DependencyProperty ShowPageBordersProperty =
                DependencyProperty.Register(
                        "ShowPageBorders", 
                        typeof(bool),
                        typeof(DocumentViewer), 
                        new FrameworkPropertyMetadata( 
                                _showPageBordersDefault, //default value
                                FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, //MetaData flags 
                                new PropertyChangedCallback(OnShowPageBordersChanged))); //changed callback

        /// 
        /// Reflects whether a "Drop Shadow" border should be shown around the pages being displayed. 
        /// 
        public bool ShowPageBorders 
        { 
            get { return (bool) GetValue(ShowPageBordersProperty); }
            set { SetValue(ShowPageBordersProperty, value); } 
        }
        #endregion ShowPageBorders

        #region Zoom 
        /// 
        /// Reflects the effective Zoom percentage based on the last layout related 
        /// property set or command issued. 
        /// If this was the last property set, or the Zoom command was last issued,
        /// then this will just be the last Zoom value set. 
        /// When another layout related property (ie MaxPagesAcross, etc) was set
        /// or a command (ie FitToMaxPagesAcross, FitToHeight, etc) was issued, then
        /// this value will be the resulting Zoom value from that layout adjustment.
        /// 
        /// Must be greater than 5.0 and less than 5000.0.  Invalid values will throw.
        ///  
        public static readonly DependencyProperty ZoomProperty = 
                DependencyProperty.Register(
                        "Zoom", 
                        typeof(double),
                        typeof(DocumentViewer),
                        new FrameworkPropertyMetadata(
                                _zoomPercentageDefault, //default value 
                                FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, //MetaData flags
                                new PropertyChangedCallback(OnZoomChanged),  //changed callback 
                                new CoerceValueCallback(CoerceZoom))); // coercion callback 

        ///  
        /// Reflects the effective Zoom percentage based on the last layout related
        /// property set or command issued.
        /// If this was the last property set, or the Zoom command was last issued,
        /// then this will just be the last Zoom value set. 
        /// When another layout related property (ie MaxPagesAcross, etc) was set
        /// or a command (ie FitToMaxPagesAcross, FitToHeight, etc) was issued, then 
        /// this value will be the resulting Zoom value from that layout adjustment. 
        ///
        /// Must be greater than 5.0 and less than 5000.0. 
        /// 
        public double Zoom
        {
            get { return (double) GetValue(ZoomProperty); } 
            set { SetValue(ZoomProperty, value); }
        } 
        #endregion Zoom 

        #region MaxPagesAcross 
        /// 
        /// Reflects the number of Columns of pages displayed, based on the last
        /// value set through this property, or a layout related command
        /// (ie FitToMaxPagesAcross, ViewThumbnails, etc..) 
        /// 
        public static readonly DependencyProperty MaxPagesAcrossProperty = 
                DependencyProperty.Register( 
                        "MaxPagesAcross",
                        typeof(int), 
                        typeof(DocumentViewer),
                        new FrameworkPropertyMetadata(
                                _maxPagesAcrossDefault, //default value
                                FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, //MetaData flags 
                                new PropertyChangedCallback(OnMaxPagesAcrossChanged)), //changed callback
                        new ValidateValueCallback(ValidateMaxPagesAcross)); //validation callback 
 
        /// 
        /// Reflects the number of Columns of pages displayed, based on the last 
        /// value set through this property, or a layout related command
        /// (ie FitToMaxPagesAcross, ViewThumbnails, etc..)
        /// Valid values are from 1 to 32, inclusive.
        ///  
        public int MaxPagesAcross
        { 
            get { return (int) GetValue(MaxPagesAcrossProperty); } 
            set { SetValue(MaxPagesAcrossProperty, value); }
        } 
        #endregion MaxPagesAcross

        #region VerticalPageSpacing
        ///  
        /// Reflects the vertical gap between Pages when laid out, in pixel units.
        ///  
        public static readonly DependencyProperty VerticalPageSpacingProperty = 
                DependencyProperty.Register(
                        "VerticalPageSpacing", 
                        typeof(double),
                        typeof(DocumentViewer),
                        new FrameworkPropertyMetadata(
                                _verticalPageSpacingDefault, //default value 
                                new PropertyChangedCallback(OnVerticalPageSpacingChanged)), //changed callback
                        new ValidateValueCallback(ValidatePageSpacing)); //validation callback 
 
        /// 
        /// Reflects the vertical gap between Pages when laid out, in pixel units. 
        /// 
        public double VerticalPageSpacing
        {
            get { return (double) GetValue(VerticalPageSpacingProperty); } 
            set { SetValue(VerticalPageSpacingProperty, value); }
        } 
        #endregion VerticalPageSpacing 

        #region HorizontalPageSpacing 
        /// 
        /// Reflects the horizontal gap between Pages when laid out, in pixel units.
        /// 
        public static readonly DependencyProperty HorizontalPageSpacingProperty = 
                DependencyProperty.Register(
                        "HorizontalPageSpacing", 
                        typeof(double), 
                        typeof(DocumentViewer),
                        new FrameworkPropertyMetadata( 
                                _horizontalPageSpacingDefault, //default value
                                new PropertyChangedCallback(OnHorizontalPageSpacingChanged)), //changed callback
                        new ValidateValueCallback(ValidatePageSpacing)); //validation callback
 
        /// 
        /// Reflects the horizontal gap between Pages when laid out, in pixel units. 
        ///  
        public double HorizontalPageSpacing
        { 
            get { return (double) GetValue(HorizontalPageSpacingProperty); }
            set { SetValue(HorizontalPageSpacingProperty, value); }
        }
        #endregion HorizontalPageSpacing 

        #region CanMoveUp 
        ///  
        /// Reflects whether the DocumentViewer is at the top of the current document.
        ///  
        private static readonly DependencyPropertyKey CanMoveUpPropertyKey =
                DependencyProperty.RegisterReadOnly(
                        "CanMoveUp",
                        typeof(bool), 
                        typeof(DocumentViewer),
                        new FrameworkPropertyMetadata(_canMoveUpDefault)); 
 
        /// 
        /// Reflects whether the DocumentViewer is at the top of the current document. 
        /// 
        public static readonly DependencyProperty CanMoveUpProperty =
                CanMoveUpPropertyKey.DependencyProperty;
 
        /// 
        /// Reflects whether the DocumentViewer is at the top of the current document. 
        ///  
        public bool CanMoveUp
        { 
            get { return (bool) GetValue(CanMoveUpProperty); }
        }
        #endregion CanMoveUp
 
        #region CanMoveDown
        ///  
        /// Reflects whether the DocumentViewer is at the bottom of the current document. 
        /// 
        private static readonly DependencyPropertyKey CanMoveDownPropertyKey = 
                DependencyProperty.RegisterReadOnly(
                        "CanMoveDown",
                        typeof(bool),
                        typeof(DocumentViewer), 
                        new FrameworkPropertyMetadata(_canMoveDownDefault));
 
        ///  
        /// Reflects whether the DocumentViewer is at the bottom of the current document.
        ///  
        public static readonly DependencyProperty CanMoveDownProperty =
                CanMoveDownPropertyKey.DependencyProperty;

        ///  
        /// Reflects whether the DocumentViewer is at the bottom of the current document.
        ///  
        public bool CanMoveDown 
        {
            get { return (bool) GetValue(CanMoveDownProperty); } 
        }
        #endregion CanMoveDown

        #region CanMoveLeft 
        /// 
        /// Reflects whether the DocumentViewer is at the leftmost extent of the current document. 
        ///  
        private static readonly DependencyPropertyKey CanMoveLeftPropertyKey =
                DependencyProperty.RegisterReadOnly( 
                        "CanMoveLeft",
                        typeof(bool),
                        typeof(DocumentViewer),
                        new FrameworkPropertyMetadata(_canMoveLeftDefault)); 

        ///  
        /// Reflects whether the DocumentViewer is at the leftmost extent of the current document. 
        /// 
        public static readonly DependencyProperty CanMoveLeftProperty = 
                CanMoveLeftPropertyKey.DependencyProperty;

        /// 
        /// Reflects whether the DocumentViewer is at the leftmost extent of the current document. 
        /// 
        public bool CanMoveLeft 
        { 
            get { return (bool) GetValue(CanMoveLeftProperty); }
        } 
        #endregion CanMoveLeft

        #region CanMoveRight
        ///  
        /// Reflects whether the DocumentViewer is at the rightmost extent of the current document.
        ///  
        private static readonly DependencyPropertyKey CanMoveRightPropertyKey = 
                DependencyProperty.RegisterReadOnly(
                        "CanMoveRight", 
                        typeof(bool),
                        typeof(DocumentViewer),
                        new FrameworkPropertyMetadata(_canMoveRightDefault));
 
        /// 
        /// Reflects whether the DocumentViewer is at the rightmost extent of the current document. 
        ///  
        public static readonly DependencyProperty CanMoveRightProperty =
                CanMoveRightPropertyKey.DependencyProperty; 

        /// 
        /// Reflects whether the DocumentViewer is at the rightmost extent of the current document.
        ///  
        public bool CanMoveRight
        { 
            get { return (bool) GetValue(CanMoveRightProperty); } 
        }
        #endregion CanMoveRight 

        #region CanIncreaseZoom
        /// 
        /// Reflects whether the DocumentViewer can zoom in any further 
        /// (ie not at the highest "zoom level") of the current document.
        ///  
        private static readonly DependencyPropertyKey CanIncreaseZoomPropertyKey = 
                DependencyProperty.RegisterReadOnly(
                        "CanIncreaseZoom", 
                        typeof(bool),
                        typeof(DocumentViewer),
                        new FrameworkPropertyMetadata(_canIncreaseZoomDefault));
 
        /// 
        /// Reflects whether the DocumentViewer can zoom in any further 
        /// (ie not at the highest "zoom level") of the current document. 
        /// 
        public static readonly DependencyProperty CanIncreaseZoomProperty = 
                CanIncreaseZoomPropertyKey.DependencyProperty;

        /// 
        /// Reflects whether the DocumentViewer can zoom in any further 
        /// (ie not at the highest "zoom level") of the current document.
        ///  
        public bool CanIncreaseZoom 
        {
            get { return (bool) GetValue(CanIncreaseZoomProperty); } 
        }
        #endregion CanIncreaseZoom

        #region CanDecreaseZoom 
        /// 
        /// Reflects whether the DocumentViewer can zoom out any further 
        /// (ie not at the lowest "zoom level") of the current document. 
        /// 
        private static readonly DependencyPropertyKey CanDecreaseZoomPropertyKey = 
                DependencyProperty.RegisterReadOnly(
                        "CanDecreaseZoom",
                        typeof(bool),
                        typeof(DocumentViewer), 
                        new FrameworkPropertyMetadata(_canDecreaseZoomDefault));
 
        ///  
        /// Reflects whether the DocumentViewer can zoom out any further
        /// (ie not at the lowest "zoom level") of the current document. 
        /// 
        public static readonly DependencyProperty CanDecreaseZoomProperty =
                CanDecreaseZoomPropertyKey.DependencyProperty;
 
        /// 
        /// Reflects whether the DocumentViewer can zoom out any further 
        /// (ie not at the lowest "zoom level") of the current document. 
        /// 
        public bool CanDecreaseZoom 
        {
            get { return (bool) GetValue(CanDecreaseZoomProperty); }
        }
        #endregion CanDecreaseZoom 

        #endregion Dependency Properties 
 
        #endregion Public Properties
 
        //-----------------------------------------------------
        //
        //  Public Operators
        // 
        //------------------------------------------------------
 
        //----------------------------------------------------- 
        //
        //  Public Events 
        //
        //-----------------------------------------------------

        //----------------------------------------------------- 
        //
        //  Protected Methods 
        // 
        //------------------------------------------------------
        #region Protected Methods 

        /// 
        /// Creates AutomationPeer ()
        ///  
        protected override AutomationPeer OnCreateAutomationPeer()
        { 
            return new DocumentViewerAutomationPeer(this); 
        }
 
        /// 
        /// Attaches DocumentGrid to our document when it changes.
        /// 
        ///  
        /// Critical: set_DocumentLoaded is defined in a non-APTCA assembly.
        /// TreatAsSafe: call to set_DocumentLoaded does not entail any risk. 
        ///  
        [SecurityCritical, SecurityTreatAsSafe]
        protected override void OnDocumentChanged() 
        {
            // Validate the new document type
            if (!(Document is FixedDocument) && !(Document is FixedDocumentSequence)
                && !(Document == null)) 
            {
                throw new NotSupportedException(SR.Get(SRID.DocumentViewerOnlySupportsFixedDocumentSequence)); 
            } 

            //Call the base so that TextEditors are attached. 
            base.OnDocumentChanged();

            //Assign the content to DocumentGrid.
            AttachContent(); 

            // Update the toolbar with our current document state. 
            if (_findToolbar != null) 
            {
                _findToolbar.DocumentLoaded = (Document != null) ? true : false; 
            }

            // We do not automatically go to the first page on the _first_ content
            // assignment, for two reasons: 
            //  1) If this is the first assignment, then we're already there by default.
            //  2) The user may have specified vertical or horizontal offsets in markup or 
            //     otherwise () and we need to honor 
            //     those settings.
            if (!_firstDocumentAssignment) 
            {
                // Go to the first page of new content.
                OnGoToPageCommand(1);
            } 
            _firstDocumentAssignment = false;
 
        } 

        ///  
        /// Called when a BringIntoView event is bubbled up from the Document.
        /// Base implementation will move the master page to the page
        /// on which the element occurs.
        ///  
        /// The object to make visible.
        /// The rectangular region in the object's coordinate space which should be made visible. 
        ///  
        protected override void OnBringIntoView(DependencyObject element, Rect rect, int pageNumber)
        { 
            // DVBase will give us a 1-indexed page number, we convert to 0-indexed.
            int zeroIndexed = pageNumber - 1;
            if (zeroIndexed >= 0 && zeroIndexed < PageCount)
            { 
                _documentScrollInfo.MakeVisible(element, rect, zeroIndexed);
            } 
        } 

        ///  
        /// Handler for the PreviousPage command.
        /// 
        protected override void OnPreviousPageCommand()
        { 
            //Scroll to the previous row.
            if (_documentScrollInfo != null) 
            { 
                _documentScrollInfo.ScrollToPreviousRow();
            } 
        }

        /// 
        /// Handler for the NextPage command. 
        /// 
        protected override void OnNextPageCommand() 
        { 
            //Scroll to the previous row.
            if (_documentScrollInfo != null) 
            {
                _documentScrollInfo.ScrollToNextRow();
            }
        } 

        ///  
        /// Handler for the FirstPage command. 
        /// 
        protected override void OnFirstPageCommand() 
        {
            //Scroll to the top of the document.
            if (_documentScrollInfo != null)
            { 
                _documentScrollInfo.MakePageVisible( 0 );
            } 
        } 

        ///  
        /// Handler for the LastPage command.
        /// 
        protected override void OnLastPageCommand()
        { 
            //Scroll to the bottom of the document.
            if (_documentScrollInfo != null) 
            { 
                _documentScrollInfo.MakePageVisible( PageCount - 1 );
            } 
        }

        /// 
        /// Handler for the GoToPage command. 
        /// 
        protected override void OnGoToPageCommand(int pageNumber) 
        { 
            // Check if we can go to the specified page.
            // and navigate there. 
            if (CanGoToPage(pageNumber))
            {
                //Scroll to the specified page in the document.
                if (_documentScrollInfo != null) 
                {
                    // CanGoToPage should have guaranteed that this assert is always true. 
                    Invariant.Assert(pageNumber > 0, "PageNumber must be positive."); 
                    _documentScrollInfo.MakePageVisible(pageNumber - 1);
                } 
            }
        }

        ///  
        /// Handler for the ViewThumbnails Command
        ///  
        protected virtual void OnViewThumbnailsCommand() 
        {
            if (_documentScrollInfo != null) 
            {
                _documentScrollInfo.ViewThumbnails();
            }
        } 

        ///  
        /// Handler for the FitToWidth Command 
        /// 
        protected virtual void OnFitToWidthCommand() 
        {
            if (_documentScrollInfo != null)
            {
                _documentScrollInfo.FitToPageWidth(); 
            }
        } 
 
        /// 
        /// Handler for the FitToHeight Command 
        /// 
        protected virtual void OnFitToHeightCommand()
        {
            if (_documentScrollInfo != null) 
            {
                _documentScrollInfo.FitToPageHeight(); 
            } 
        }
 
        /// 
        /// Handler for the FitToMaxPagesAcross Command
        /// 
        protected virtual void OnFitToMaxPagesAcrossCommand() 
        {
            if (_documentScrollInfo != null) 
            { 
                _documentScrollInfo.FitColumns(MaxPagesAcross);
            } 
        }

        /// 
        /// HAndler for the FitMaxPagesAcross Command 
        /// 
        ///  
        protected virtual void OnFitToMaxPagesAcrossCommand(int pagesAcross) 
        {
            if (ValidateMaxPagesAcross(pagesAcross)) 
            {
                if (_documentScrollInfo != null)
                {
                    _documentScrollInfo.FitColumns(pagesAcross); 
                }
            } 
            else 
            {
                throw new ArgumentOutOfRangeException("pagesAcross"); 
            }
        }

        ///  
        /// Handler for the Find Command
        ///  
        protected virtual void OnFindCommand() 
        {
            GoToFind(); 
        }

        /// 
        /// This is the method that responds to the KeyDown event. 
        /// 
        ///  
        protected override void OnKeyDown(KeyEventArgs e) 
        {
            // Look for Find specific key inputs and process them. 
            // If the key is processed, this event will be marked handled.
            e = ProcessFindKeys(e);

            base.OnKeyDown(e); 
        }
 
        ///  
        /// Handler for the ScrollPageUp Command
        ///  
        protected virtual void OnScrollPageUpCommand()
        {
            if (_documentScrollInfo != null)
            { 
                _documentScrollInfo.PageUp();
            } 
        } 

        ///  
        /// Handler for the ScrollPageDown Command
        /// 
        protected virtual void OnScrollPageDownCommand()
        { 
            if (_documentScrollInfo != null)
            { 
                _documentScrollInfo.PageDown(); 
            }
        } 

        /// 
        /// Handler for the ScrollPageLeft Command
        ///  
        protected virtual void OnScrollPageLeftCommand()
        { 
            if (_documentScrollInfo != null) 
            {
                _documentScrollInfo.PageLeft(); 
            }
        }

        ///  
        /// Handler for the ScrollPageRight Command
        ///  
        protected virtual void OnScrollPageRightCommand() 
        {
            if (_documentScrollInfo != null) 
            {
                _documentScrollInfo.PageRight();
            }
        } 

        ///  
        /// Handler for the MoveUp Command 
        /// 
        protected virtual void OnMoveUpCommand() 
        {
            if (_documentScrollInfo != null)
            {
                _documentScrollInfo.LineUp(); 
            }
        } 
 
        /// 
        /// Handler for the MoveDown Command 
        /// 
        protected virtual void OnMoveDownCommand()
        {
            if (_documentScrollInfo != null) 
            {
                _documentScrollInfo.LineDown(); 
            } 
        }
 
        /// 
        /// Handler for the MoveLeft Command
        /// 
        protected virtual void OnMoveLeftCommand() 
        {
            if (_documentScrollInfo != null) 
            { 
                _documentScrollInfo.LineLeft();
            } 
        }

        /// 
        /// Handler for the MoveRight Command 
        /// 
        protected virtual void OnMoveRightCommand() 
        { 
            if (_documentScrollInfo != null)
            { 
                _documentScrollInfo.LineRight();
            }
        }
 
        /// 
        /// Handler for the IncreaseZoom Command 
        ///  
        protected virtual void OnIncreaseZoomCommand()
        { 
            // Check if possible to zoom in
            if (CanIncreaseZoom)
            {
                // Update the zoom level index to the appropriate place. 
                double oldZoom = Zoom;
                FindZoomLevelIndex(); 
                // As long as more zoomLevel's exist, increase zoom. 
                if (_zoomLevelIndex > 0)
                { 
                    _zoomLevelIndex--;
                }

                // Set the zoom percentage, with _updatingInternalZoomLevel set to true to 
                //   avoid resetting the zoom level index.
                _updatingInternalZoomLevel = true; 
                Zoom = DocumentViewer._zoomLevelCollection[_zoomLevelIndex]; 
                _updatingInternalZoomLevel = false;
            } 
        }

        /// 
        /// Handler for the DecreaseZoom Command 
        /// 
        protected virtual void OnDecreaseZoomCommand() 
        { 
            // Check if possible to zoom out.
            if (CanDecreaseZoom) 
            {
                // Update the zoom level index to the appropriate place.
                double oldZoom = Zoom;
                FindZoomLevelIndex(); 
                // If the current zoom value exists in the zoomLevelCollection, and can
                //   still be zoomed out, then zoom out another level. 
                if ((oldZoom == DocumentViewer._zoomLevelCollection[_zoomLevelIndex]) && 
                    (_zoomLevelIndex < DocumentViewer._zoomLevelCollection.Length - 1))
               { 
                    _zoomLevelIndex++;
                }

                // Set the zoom percentage, with _updatingInternalZoomLevel set to true to 
                //   avoid resetting the zoom level index.
                _updatingInternalZoomLevel = true; 
                Zoom = _zoomLevelCollection[_zoomLevelIndex]; 
                _updatingInternalZoomLevel = false;
            } 
        }

        /// 
        /// Overrides the base implementation and returns the current collection of 
        /// DocumentPageViews being displayed in our IDSI.
        ///  
        ///  
        /// 
        protected override ReadOnlyCollection GetPageViewsCollection(out bool changed) 
        {
            ReadOnlyCollection pageViews = null;

            //Save off the current value of our PageView changed flag so we can 
            //return it to indicate if the collection has actually changed.
            changed = _pageViewCollectionChanged; 
 
            //Reset the flag so that if this is called again before InvalidatePageViews is called
            //it'll reflect the unchanged-ness of the collection. 
            _pageViewCollectionChanged = false;

            if (_documentScrollInfo != null && _documentScrollInfo.PageViews != null)
            { 
                //Return the current collection.
                pageViews = _documentScrollInfo.PageViews; 
            } 
            else
            { 
                //Return an empty collection (null is not valid).
                pageViews = new ReadOnlyCollection(new List(0));
            }
 
            return pageViews;
        } 
 
        /// 
        /// Overrides the OnMouseLeftButtonDown method so that we can take focus when clicked. 
        /// 
        /// The MouseButtonEventArgs associated with this mouse event.
        protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
        { 
            base.OnMouseLeftButtonDown(e);
 
            // If no other controls in our Template have handled the event, we'll 
            // take focus here.
            if (!e.Handled) 
            {
                Focus();
                e.Handled = true;
            } 
        }
 
        ///  
        /// OnPreviewMouseWheel Zooms in/out on the document when the
        /// mouse wheel is scrolled and the Ctrl key is depressed. 
        /// 
        /// Event Arguments
        protected override void OnPreviewMouseWheel(MouseWheelEventArgs e)
        { 
            if (e.Handled)
            { 
                return; 
            }
 
            //Get the state of the Ctrl key -- if it's pressed, we'll Zoom.
            //Otherwise we do nothing and let others handle this event.
            if (Keyboard.IsKeyDown(Key.LeftCtrl) ||
                Keyboard.IsKeyDown(Key.RightCtrl)) 
            {
                e.Handled = true; 
 
                //Zoom based on the direction of the wheel.
                if (e.Delta < 0) 
                {
                    DecreaseZoom();
                }
                else 
                {
                    IncreaseZoom(); 
                } 
            }
        } 

        #endregion Protected Methods

        #region Internal Methods 
        /// 
        /// Called when our IDocumentScrollInfo has new layout information to share with us. 
        ///  
        internal void InvalidateDocumentScrollInfo()
        { 
            // We need to see if any IDocumentScrollInfo properties that DocumentViewer
            //   either exposes or makes use of have changed.  If so we invalidate properties
            //   or take actions here.
 
            // Any properties that are read only need to have the cache set and be invalidated
            // Settable DP's can be set directly (and should be, for validation) 
 
            //Set our internal change flag.
            //DP Invalidation callbacks can check for this flag to see if a change originated 
            //from our IDocumentScrollInfo object or not and take the appropriate action.
            //(Usually, if the IDSI caused the change to a DP, the invalidated callback won't need to
            //update the associated property on the IDSI.)
            _internalIDSIChange = true; 

            SetValue(ExtentWidthPropertyKey, _documentScrollInfo.ExtentWidth); 
            SetValue(ExtentHeightPropertyKey, _documentScrollInfo.ExtentHeight); 
            SetValue(ViewportWidthPropertyKey, _documentScrollInfo.ViewportWidth);
            SetValue(ViewportHeightPropertyKey, _documentScrollInfo.ViewportHeight); 

            if (HorizontalOffset != _documentScrollInfo.HorizontalOffset)
            {
                HorizontalOffset = _documentScrollInfo.HorizontalOffset; 
            }
 
            if (VerticalOffset != _documentScrollInfo.VerticalOffset) 
            {
                VerticalOffset = _documentScrollInfo.VerticalOffset; 
            }

            // IDSI is 0-indexed
            SetValue(MasterPageNumberPropertyKey, _documentScrollInfo.FirstVisiblePageNumber + 1); 

            // Convert IDocumentScrollInfo.Scale into 100-based percentage value for comparison. 
            double scrollZoom = ScaleToZoom(_documentScrollInfo.Scale); 
            if (Zoom != scrollZoom)
            { 
                Zoom = scrollZoom;
            }

            if (MaxPagesAcross != _documentScrollInfo.MaxPagesAcross) 
            {
                MaxPagesAcross = _documentScrollInfo.MaxPagesAcross; 
            } 

            //Reset our internal change flag. 
            _internalIDSIChange = false;
        }

        ///  
        /// Merely calls the base's InvalidatePageViews (which is protected).
        /// Used by our IDSI to keep the DPV collection in [....]. 
        ///  
        internal void InvalidatePageViewsInternal()
        { 
            //Our PageView collection has changed, set the flag.
            _pageViewCollectionChanged = true;
            InvalidatePageViews();
        } 

        ///  
        /// BringPointIntoView is called by the base if a selection goes outside of the bounds 
        /// of the current TextView.  If this happens it is necessary to scroll our content
        /// in an attempt to make that selection point visible, thus moving the scope of the TextView 
        /// and allowing selection to continue.
        /// 
        /// The point to be brought into view.
        /// Whether operation is pending or not. 
        internal bool BringPointIntoView(Point point)
        { 
            FrameworkElement grid = _documentScrollInfo as FrameworkElement; 

            if (grid != null) 
            {
                //Calculate the bounds of the DocumentGrid relative to the bounds of DocumentViewer
                Transform tr = this.TransformToDescendant(grid) as Transform;
                Rect gridRect = Rect.Transform(new Rect(grid.RenderSize), 
                                    tr.Value);
                double verticalOffset = VerticalOffset; 
                double horizontalOffset = HorizontalOffset; 

                //Scroll the point into view Vertically. 
                if (point.Y > gridRect.Y + gridRect.Height)
                {
                    verticalOffset += (point.Y - (gridRect.Y + gridRect.Height));
                } 
                else if (point.Y < gridRect.Y)
                { 
                    verticalOffset -= (gridRect.Y - point.Y); 
                }
 
                //Scroll the point into view Horizontally.
                if (point.X < gridRect.X)
                {
                    horizontalOffset -= (gridRect.X - point.X); 
                }
                else if (point.X > gridRect.X + gridRect.Width) 
                { 
                    horizontalOffset += (point.X - (gridRect.X + gridRect.Width));
                } 

                VerticalOffset = Math.Max(verticalOffset, 0.0);
                HorizontalOffset = Math.Max(horizontalOffset, 0.0);
            } 
            return false;
        } 
 
        #endregion Internal Methods
 
        #region Internal Properties

        /// 
        /// Internally exposes our TextEditor's Selection, for use 
        /// by Annotations code.
        ///  
        internal ITextSelection TextSelection 
        {
            get 
            {
                if (TextEditor != null)
                {
                    return TextEditor.Selection; 
                }
                else 
                { 
                    return null;
                } 
            }
        }

 
        /// 
        /// Internally exposes our IDocumentScrollInfo, for use 
        /// by Annotations code. 
        /// 
        internal IDocumentScrollInfo DocumentScrollInfo 
        {
            get
            {
                return _documentScrollInfo; 
            }
        } 
 
        /// 
        /// Internally exposes out ScrollViewer, for use in DocumentViewerAutomationPeer. 
        /// 
        internal ScrollViewer ScrollViewer
        {
            get 
            {
                return _scrollViewer; 
            } 
        }
 
        #endregion InternalProperties


 
        //-----------------------------------------------------
        // 
        //  Private Methods 
        //
        //------------------------------------------------------ 

        #region Private Methods

        #region Commands 
        /// 
        /// Set up our Command bindings 
        ///  
        /// 
        /// Set up our RoutedUICommand bindings 
        /// 
        ///
        /// Critical - creates a command binding.
        /// TAS - registering our own internal commands is considered safe. 
        ///
        [SecurityCritical , SecurityTreatAsSafe ] 
        private static void CreateCommandBindings() 
        {
            // Create our generic ExecutedRoutedEventHandler. 
            ExecutedRoutedEventHandler executeHandler = new ExecutedRoutedEventHandler(ExecutedRoutedEventHandler);

            // Create our generic QueryEnabledStatusHandler
            CanExecuteRoutedEventHandler queryEnabledHandler = new CanExecuteRoutedEventHandler(QueryEnabledHandler); 

            // 
            // Command: ViewThumbnails 
            //          Tells DocumentViewer to display thumbnails.
            _viewThumbnailsCommand = new RoutedUICommand(SR.Get(SRID.DocumentViewerViewThumbnailsCommandText), 
                "ViewThumbnailsCommand",
                typeof(DocumentViewer),
                null);
 
            CommandHelpers.RegisterCommandHandler( typeof(DocumentViewer),
                _viewThumbnailsCommand, 
                executeHandler, 
                queryEnabledHandler);
                //no key gesture 

            //
            // Command: FitToWidth
            //          Tells DocumentViewer to zoom to the document width. 
            _fitToWidthCommand = new RoutedUICommand(
                SR.Get(SRID.DocumentViewerViewFitToWidthCommandText), 
                "FitToWidthCommand", 
                typeof(DocumentViewer),
                null); 

            CommandHelpers.RegisterCommandHandler(typeof(DocumentViewer),
                _fitToWidthCommand,
                executeHandler, 
                queryEnabledHandler,
                new KeyGesture(Key.D2, ModifierKeys.Control)); 
 
            //
            // Command: FitToHeight 
            //          Tells DocumentViewer to zoom to the document height.
            _fitToHeightCommand = new RoutedUICommand(
                SR.Get(SRID.DocumentViewerViewFitToHeightCommandText),
                "FitToHeightCommand", 
                typeof(DocumentViewer),
                null); 
 
            CommandHelpers.RegisterCommandHandler(typeof(DocumentViewer),
                _fitToHeightCommand, 
                executeHandler,
                queryEnabledHandler);
                //no key gesture
 
            //
            // Command: MaxPagesAcross 
            //          Sets the MaxPagesAcross to the value provided. 
            _fitToMaxPagesAcrossCommand = new RoutedUICommand(
                SR.Get(SRID.DocumentViewerViewFitToMaxPagesAcrossCommandText), 
                "FitToMaxPagesAcrossCommand",
                typeof(DocumentViewer),
                null);
 
            CommandHelpers.RegisterCommandHandler(typeof(DocumentViewer),
                _fitToMaxPagesAcrossCommand, 
                executeHandler, 
                queryEnabledHandler);
                //no key gesture 

            #region Library Commands

            // Command: ApplicationCommands.Find - Ctrl+F 
            //          Invokes DocumentViewer's Find dialog.
            CommandHelpers.RegisterCommandHandler(typeof(DocumentViewer), 
                ApplicationCommands.Find, 
                executeHandler,
                queryEnabledHandler); 

            //
            // Command: ComponentCommands.ScrollPageUp - PageUp
            //          Causes DocumentViewer to scroll a Viewport up. 
            CommandHelpers.RegisterCommandHandler(typeof(DocumentViewer),
                ComponentCommands.ScrollPageUp, 
                executeHandler, 
                queryEnabledHandler,
                Key.PageUp); 

            //
            // Command: ComponentCommands.ScrollPageDown - PageDown
            //          Causes DocumentViewer to scroll a Viewport down. 
            CommandHelpers.RegisterCommandHandler(typeof(DocumentViewer),
                ComponentCommands.ScrollPageDown, 
                executeHandler, 
                queryEnabledHandler,
                Key.PageDown); 

            //
            // Command: ComponentCommands.ScrollPageLeft
            //          Causes DocumentViewer to scroll a Viewport to the left. 
            CommandHelpers.RegisterCommandHandler(typeof(DocumentViewer),
                ComponentCommands.ScrollPageLeft, 
                executeHandler, 
                queryEnabledHandler);
                //no key gesture 

            //
            // Command: ComponentCommands.ScrollPageRight
            //          Causes DocumentViewer to scroll a Viewport to the right. 
            CommandHelpers.RegisterCommandHandler(typeof(DocumentViewer),
                ComponentCommands.ScrollPageRight, 
                executeHandler, 
                queryEnabledHandler);
                //no key gesture 

            //
            // Command: ComponentCommands.MoveUp - Up
            //          Causes DocumentViewer to scroll the Viewport up by 16px. 
            CommandHelpers.RegisterCommandHandler(typeof(DocumentViewer),
                ComponentCommands.MoveUp, 
                executeHandler, 
                queryEnabledHandler,
                Key.Up); 

            //
            // Command: ComponentCommands.MoveDown - Down
            //          Causes DocumentViewer to scroll the Viewport down by 16px. 
            CommandHelpers.RegisterCommandHandler(typeof(DocumentViewer),
                ComponentCommands.MoveDown, 
                executeHandler, 
                queryEnabledHandler,
                Key.Down); 

            //
            // Command: ComponentCommands.MoveLeft - Left
            //          Causes DocumentViewer to scroll a Viewport left by 16px. 
            CommandHelpers.RegisterCommandHandler(typeof(DocumentViewer),
                ComponentCommands.MoveLeft, 
                executeHandler, 
                queryEnabledHandler,
                Key.Left); 

            //
            // Command: ComponentCommands.MoveRight - Right
            //          Causes DocumentViewer to scroll a Viewport right by 16px. 
            CommandHelpers.RegisterCommandHandler(typeof(DocumentViewer),
                ComponentCommands.MoveRight, 
                executeHandler, 
                queryEnabledHandler,
                Key.Right); 

            //
            // Command: NavigationCommands.Zoom
            //          Sets DocumentViewer's Zoom to the specified level. 
            CommandHelpers.RegisterCommandHandler(typeof(DocumentViewer),
                NavigationCommands.Zoom, 
                executeHandler, 
                queryEnabledHandler);
                //no key gesture 

            //
            // Command: NavigationCommands.IncreaseZoom
            //          Causes DocumentViewer to zoom in on the content. 
            CommandHelpers.RegisterCommandHandler(typeof(DocumentViewer),
                NavigationCommands.IncreaseZoom, 
                executeHandler, 
                queryEnabledHandler,
                // Ctrl+Numpad '+' 
                new KeyGesture(Key.Add, ModifierKeys.Control),
                // Ctrl+Numpad '+' (In case shift is held down)
                new KeyGesture(Key.Add, ModifierKeys.Shift | ModifierKeys.Control),
                // Ctrl+'+' 
                new KeyGesture(Key.OemPlus, ModifierKeys.Control),
                // Ctrl+'+' (In case shift is held down) 
                new KeyGesture(Key.OemPlus, ModifierKeys.Shift | ModifierKeys.Control)); 

            // 
            // Command: NavigationCommands.DecreaseZoom
            //          Causes DocumentViewer to zoom out of the content.
            CommandHelpers.RegisterCommandHandler(typeof(DocumentViewer),
                NavigationCommands.DecreaseZoom, 
                executeHandler,
                queryEnabledHandler, 
                // Ctrl+Numpad '-' 
                new KeyGesture(Key.Subtract, ModifierKeys.Control),
                // Ctrl+Numpad '-' (In case shift is held down) 
                new KeyGesture(Key.Subtract, ModifierKeys.Shift | ModifierKeys.Control),
                // Ctrl+'-'
                new KeyGesture(Key.OemMinus, ModifierKeys.Control),
                // Ctrl+'-' (In case shift is held down) 
                new KeyGesture(Key.OemMinus, ModifierKeys.Shift | ModifierKeys.Control));
 
            // Command: NavigationCommands.PreviousPage 
            CommandHelpers.RegisterCommandHandler(typeof(DocumentViewer),
                NavigationCommands.PreviousPage, 
                executeHandler,
                queryEnabledHandler,
                new KeyGesture(Key.PageUp, ModifierKeys.Control));
 
            // Command: NavigationCommands.NextPage
            CommandHelpers.RegisterCommandHandler(typeof(DocumentViewer), 
                NavigationCommands.NextPage, 
                executeHandler,
                queryEnabledHandler, 
                new KeyGesture(Key.PageDown, ModifierKeys.Control));

            // Command: NavigationCommands.FirstPage
            CommandHelpers.RegisterCommandHandler(typeof(DocumentViewer), 
                NavigationCommands.FirstPage,
                executeHandler, 
                queryEnabledHandler, 
                new KeyGesture(Key.Home, ModifierKeys.Control));
 
            // Command: NavigationCommands.FirstPage
            CommandHelpers.RegisterCommandHandler(typeof(DocumentViewer),
                NavigationCommands.LastPage,
                executeHandler, 
                queryEnabledHandler,
                new KeyGesture(Key.End, ModifierKeys.Control)); 
 
            #endregion Library Commands
 
            //Register input bindings for keyboard shortcuts that require
            //Command Parameters:

            //Zoom 100%: Requires a CommandParameter of 100.0 with the Zoom Command. 
            //Bound to Ctrl+1.
            InputBinding zoom100InputBinding = 
                new InputBinding(NavigationCommands.Zoom, 
                new KeyGesture(Key.D1, ModifierKeys.Control));
            zoom100InputBinding.CommandParameter = 100.0; 

            CommandManager.RegisterClassInputBinding(typeof(DocumentViewer),
                zoom100InputBinding);
 
            //Whole Page: Requires a CommandParameter of 1 with the FitToMaxPagesAcross Command.
            //Bound to Ctrl+3. 
            InputBinding wholePageInputBinding = 
                            new InputBinding(DocumentViewer.FitToMaxPagesAcrossCommand,
                            new KeyGesture(Key.D3, ModifierKeys.Control)); 
            wholePageInputBinding.CommandParameter = 1;

            CommandManager.RegisterClassInputBinding(typeof(DocumentViewer),
                wholePageInputBinding); 

            //Two Pages: Requires a CommandParameter of 2 with the FitToMaxPagesAcross Command. 
            //Bound to Ctrl+4. 
            InputBinding twoPagesInputBinding =
                            new InputBinding(DocumentViewer.FitToMaxPagesAcrossCommand, 
                            new KeyGesture(Key.D4, ModifierKeys.Control));
            twoPagesInputBinding.CommandParameter = 2;

            CommandManager.RegisterClassInputBinding(typeof(DocumentViewer), 
                twoPagesInputBinding);
 
 
        }
 
        /// 
        /// Central handler for QueryEnabled events fired by Commands directed at DocumentViewer.
        /// 
        /// Critical - Sets the critical Handled property on the RoutedEventArgs 
        /// TreatAsSafe - We are marking the event as handled only for the Commands that
        ///               DocumentViewer explicitly handles -- this cannot be used for spoofing. 
        ///  
        /// 
        /// The target of this Command, expected to be DocumentViewer 
        /// The event arguments for this event.
        [SecurityCritical, SecurityTreatAsSafe]
        private static void QueryEnabledHandler(object target, CanExecuteRoutedEventArgs args)
        { 
            DocumentViewer dv = target as DocumentViewer;
            Invariant.Assert(dv != null, "Target of QueryEnabledEvent must be DocumentViewer."); 
            Invariant.Assert(args != null, "args cannot be null."); 

            // If the target is not a DocumentViewer we silently return (but note that 
            // we have Asserted this above.)
            if (dv == null)
            {
                return; 
            }
 
            // Mark this event as handled so that the CanExecute handler on the base 
            // doesn't override our settings.
            args.Handled = true; 

            // Now we set the IsEnabled flag based on the Command that fired this event
            // and the current state of DocumentViewer.
            if (args.Command == ViewThumbnailsCommand || 
                args.Command == FitToWidthCommand ||
                args.Command == FitToHeightCommand || 
                args.Command == FitToMaxPagesAcrossCommand || 
                args.Command == NavigationCommands.Zoom)
            { 
                // Fit and Zoom operations are always enabled.
                args.CanExecute = true;
            }
            else if (args.Command == ApplicationCommands.Find) 
            {
                //Find can only operate if we have a TextEditor. 
                args.CanExecute = dv.TextEditor != null; 
            }
            else if (args.Command == ComponentCommands.ScrollPageUp || 
                args.Command == ComponentCommands.MoveUp)
            {
                // Enabling the Move/Scroll Up Commands is tied to the
                // state of the CanMoveUp property. 
                args.CanExecute = dv.CanMoveUp;
            } 
            else if (args.Command == ComponentCommands.ScrollPageDown || 
                args.Command == ComponentCommands.MoveDown)
            { 
                // Enabling the Move/Scroll Down Commands is tied to the
                // state of the CanMoveDown property.
                args.CanExecute = dv.CanMoveDown;
            } 
            else if (args.Command == ComponentCommands.ScrollPageLeft ||
                args.Command == ComponentCommands.MoveLeft) 
            { 
                // Enabling the Move/Scroll Left Commands is tied to the
                // state of the CanMoveLeft property. 
                args.CanExecute = dv.CanMoveLeft;
            }
            else if (args.Command == ComponentCommands.ScrollPageRight ||
                args.Command == ComponentCommands.MoveRight) 
            {
                // Enabling the Move/Scroll Right Commands is tied to the 
                // state of the CanMoveRight property. 
                args.CanExecute = dv.CanMoveRight;
            } 
            else if (args.Command == NavigationCommands.IncreaseZoom)
            {
                // Zooming in is only allowed if DocumentViewer has a valid Document assigned
                // and can increase zoom. 
                args.CanExecute = dv.CanIncreaseZoom;
            } 
            else if (args.Command == NavigationCommands.DecreaseZoom) 
            {
                // Zooming out is only allowed if DocumentViewer has a valid Document assigned 
                // and can decrease zoom.
                args.CanExecute = dv.CanDecreaseZoom;
            }
            else if (args.Command == NavigationCommands.PreviousPage 
                || args.Command == NavigationCommands.FirstPage)
            { 
                // Enabling the PreviousPage and FirstPage Commands is tied 
                // to the state of the CanGoToPreviousPage property.
                args.CanExecute = dv.CanGoToPreviousPage; 
            }
            else if (args.Command == NavigationCommands.NextPage
                || args.Command == NavigationCommands.LastPage)
            { 
                // Enabling the NextPage and LastPage Commands is tied
                // to the state of the CanGoToNextPage property. 
                args.CanExecute = dv.CanGoToNextPage; 
            }
            else if (args.Command == NavigationCommands.GoToPage) 
            {
                // This command is always enabled as long as there is a document loaded.
                args.CanExecute = (dv.Document != null);
            } 
            else
            { 
                args.Handled = false; 
                // If we get here then we missed a Command above.
                // We assert to indicate the failure. 
                Invariant.Assert(false, "Command not handled in QueryEnabledHandler.");
            }

        } 

        ///  
        /// Central handler for all ExecuteEvents fired by Commands directed at DocumentViewer. 
        /// 
        /// The target of this Command, expected to be DocumentViewer. 
        /// The event arguments associated with this event.
        private static void ExecutedRoutedEventHandler(object target, ExecutedRoutedEventArgs args)
        {
            DocumentViewer dv = target as DocumentViewer; 
            Invariant.Assert(dv != null, "Target of ExecuteEvent must be DocumentViewer.");
            Invariant.Assert(args != null, "args cannot be null."); 
 
            // If the target is not a DocumentViewer we silently return (but note that
            // we have Asserted this above.) 
            if (dv == null)
            {
                return;
            } 

            // Now we execute the method corresponding to the Command that fired this event; 
            // each Command has its own protected virtual method that performs the operation 
            // corresponding to the Command.
            if (args.Command == ViewThumbnailsCommand) 
            {
                dv.OnViewThumbnailsCommand();
            }
            else if (args.Command == FitToWidthCommand) 
            {
                dv.OnFitToWidthCommand(); 
            } 
            else if (args.Command == FitToHeightCommand)
            { 
                dv.OnFitToHeightCommand();
            }
            else if (args.Command == FitToMaxPagesAcrossCommand)
            { 
                DoFitToMaxPagesAcross(dv, args.Parameter);
            } 
            else if (args.Command == ApplicationCommands.Find) 
            {
                dv.OnFindCommand(); 
            }
            else if (args.Command == ComponentCommands.ScrollPageUp)
            {
                dv.OnScrollPageUpCommand(); 
            }
            else if (args.Command == ComponentCommands.ScrollPageDown) 
            { 
                dv.OnScrollPageDownCommand();
            } 
            else if (args.Command == ComponentCommands.ScrollPageLeft)
            {
                dv.OnScrollPageLeftCommand();
            } 
            else if (args.Command == ComponentCommands.ScrollPageRight)
            { 
                dv.OnScrollPageRightCommand(); 
            }
            else if (args.Command == ComponentCommands.MoveUp) 
            {
                dv.OnMoveUpCommand();
            }
            else if (args.Command == ComponentCommands.MoveDown) 
            {
                dv.OnMoveDownCommand(); 
            } 
            else if (args.Command == ComponentCommands.MoveLeft)
            { 
                dv.OnMoveLeftCommand();
            }
            else if (args.Command == ComponentCommands.MoveRight)
            { 
                dv.OnMoveRightCommand();
            } 
            else if (args.Command == NavigationCommands.Zoom) 
            {
                DoZoom(dv, args.Parameter); 
            }
            else if (args.Command == NavigationCommands.DecreaseZoom)
            {
                dv.DecreaseZoom(); 
            }
            else if (args.Command == NavigationCommands.IncreaseZoom) 
            { 
                dv.IncreaseZoom();
            } 
            else if (args.Command == NavigationCommands.PreviousPage)
            {
                dv.PreviousPage();
            } 
            else if (args.Command == NavigationCommands.NextPage)
            { 
                dv.NextPage(); 
            }
            else if (args.Command == NavigationCommands.FirstPage) 
            {
                dv.FirstPage();
            }
            else if (args.Command == NavigationCommands.LastPage) 
            {
                dv.LastPage(); 
            } 
            else
            { 
                Invariant.Assert(false, "Command not handled in ExecutedRoutedEventHandler.");
            }
        }
 
        /// 
        /// Helper for the FitToMaxPagesAcross Command, called from ExecutedRoutedEventHandler. 
        /// Verifies that the data passed into ExecutedRoutedEventHandler is valid for a column count 
        /// and sets the MaxPagesAcross property appropriately.
        ///  
        /// the DocumentViewer that received the command
        /// the data associated with this command
        private static void DoFitToMaxPagesAcross(DocumentViewer dv, object data)
        { 
            // Check that args is valid
            if (data != null) 
            { 
                int columnValue = 0;
                bool isValidArg = true; 

                // If data is an int, then cast
                if (data is int)
                { 
                    columnValue = (int)data;
                } 
                // If args.Data is a string, then parse 
                else if (data is string)
                { 
                    try
                    {
                        columnValue = System.Convert.ToInt32((string)data, CultureInfo.CurrentCulture);
                    } 
                    // Catch only the expected parse exceptions
                    catch (ArgumentNullException) 
                    { 
                        isValidArg = false;
                    } 
                    catch (FormatException)
                    {
                        isValidArg = false;
                    } 
                    catch (OverflowException)
                    { 
                        isValidArg = false; 
                    }
                } 

                // Argument wasn't a valid int, throw an exception.
                if (!isValidArg)
                { 
                    throw new ArgumentException(SR.Get(SRID.DocumentViewerArgumentMustBeInteger), "data");
                } 
 
                dv.OnFitToMaxPagesAcrossCommand(columnValue);
 
            }
            else
            {
                throw new ArgumentNullException("data"); 
            }
        } 
 
        /// 
        /// Helper for the Zoom Command, called from ExecutedRoutedEventHandler. 
        /// Verifies that the data passed into ExecutedRoutedEventHandler is valid for a zoom factor
        /// and sets the Zoom property appropriately.
        /// 
        /// The DocumentViewer that recieved the command 
        /// the data associated with this command
        private static void DoZoom(DocumentViewer dv, object data) 
        { 
            // Check that args is valid
            if (data != null) 
            {
                // If a ZoomConverter doesn't exist, create one.
                if (dv._zoomPercentageConverter == null)
                { 
                    dv._zoomPercentageConverter = new ZoomPercentageConverter();
                } 
 
                // Use ZoomConverter to convert argument to zoom value.
                // We use InvariantCulture because the Command arguments are typically 
                // defined in XAML or code, which is culture invariant.
                object zoomValue = dv._zoomPercentageConverter.ConvertBack(data, typeof(double),
                    null, CultureInfo.InvariantCulture);
 
                // Argument wasn't a valid percent, throw an exception.
                if (zoomValue == DependencyProperty.UnsetValue) 
                { 
                    throw new ArgumentException(SR.Get(SRID.DocumentViewerArgumentMustBePercentage), "data");
                } 
                dv.Zoom = (double)zoomValue;
            }
            else
            { 
                throw new ArgumentNullException("data");
            } 
        } 

        #endregion Commands 

        /// 
        /// Register our properties' metadata so that our DependencyProperties function.
        ///  
        private static void RegisterMetadata()
        { 
            DefaultStyleKeyProperty.OverrideMetadata(typeof(DocumentViewer), new FrameworkPropertyMetadata(typeof(DocumentViewer))); 
            _dType = DependencyObjectType.FromSystemTypeInternal(typeof(DocumentViewer));
        } 

        /// 
        /// Initializes our DocumentScrollInfo.
        ///  
        private void SetUp()
        { 
            // Enable selection. 
            IsSelectionEnabled = true;
 
            // Set the TextBox.AcceptsReturn flag -- this will disable the "select everything on focus"
            // behavior of the TextEditor.
            // We reset the TextBox.AcceptsTab property to keep the TextEditor from eating Tab.
            SetValue(TextBox.AcceptsTabProperty, false); 

            // Construct the DocumentGrid. 
            CreateIDocumentScrollInfo(); 
        }
 
        /// 
        /// CreateIDocumentScrollInfo instantiates our IDocumentScrollInfo control
        /// and sets/resets default properties.
        ///  
        private void CreateIDocumentScrollInfo()
        { 
            if (_documentScrollInfo == null) 
            {
                // Construct IDocumentScrollInfo (DocumentGrid). 
                _documentScrollInfo = new DocumentGrid();
                _documentScrollInfo.DocumentViewerOwner = this;

                //If IDocumentScrollInfo is a FrameworkElement we can give it a 
                //Name for automation.
                FrameworkElement fe = _documentScrollInfo as FrameworkElement; 
                if (fe != null) 
                {
                    fe.Name = "DocumentGrid"; 
                    fe.Focusable = false;

                    //We don't allow Tabbing to the IDocumentScrollInfo --
                    //The ScrollViewer parent is what is tabbed to. 
                    fe.SetValue(KeyboardNavigation.IsTabStopProperty, false);
 
                    TextEditorRenderScope = fe; 
                }
            } 

            //Assign our content to the IDSI.
            AttachContent();
 
            //Give the IDocumentScrollInfo object default values for important properties.
            _documentScrollInfo.VerticalPageSpacing = VerticalPageSpacing; 
            _documentScrollInfo.HorizontalPageSpacing = HorizontalPageSpacing; 
        }
 
        /// 
        /// Assigns our current Document to our IDSI and gives it a reference to our TextEditor.
        /// 
        private void AttachContent() 
        {
            _documentScrollInfo.Content = (Document != null) ? Document.DocumentPaginator as DynamicDocumentPaginator : null; 
            IsSelectionEnabled = true; 
        }
 
        /// 
        /// FindContentHost does 2 things:
        ///  - It finds "marked" elements (elements with ContentHost attached properties)
        ///    in the current Visual Tree. 
        ///  - It takes these elements and populates them with the proper UI (for Content)
        ///  
        /// There must be a ScrollViewer in 
        /// DocumentViewer's visual tree which has the Name PART_ContentHost.
        private void FindContentHost() 
        {
            // Find the "special" element in the tree marked as the
            //   ContentHost.  This element must exist or we throw.
            ScrollViewer contentHost = this.Template.FindName(_contentHostName, this) as ScrollViewer; 

            // Make sure contentHost exists.  This wouldn't be much of a DocumentViewer if it didn't, 
            //   since we need someplace to throw our IDocumentScrollInfo so we can display documents. 
            // Throw an exception if it doesn't exist.
            if (contentHost == null) 
            {
                throw new NotSupportedException(SR.Get(SRID.DocumentViewerStyleMustIncludeContentHost));
            }
 
            _scrollViewer = contentHost;
            _scrollViewer.Focusable = false; 
 
            Invariant.Assert(_documentScrollInfo != null, "IDocumentScrollInfo cannot be null.");
            //Make the IDSI the child of the ScrollViewer. 
            _scrollViewer.Content = _documentScrollInfo;
            _scrollViewer.ScrollInfo = _documentScrollInfo;

            // Set IDocumentScrollInfo's content if its content is invalid. 
            if (_documentScrollInfo.Content != Document)
            { 
                AttachContent(); 
            }
        } 

        #region Find

        ///  
        /// Instantiates the Find Toolbar and adds it to our Visual tree where appropriate.
        ///  
        ///  
        /// Critical: FindToolBar..ctor is defined in a non-APTCA assembly.
        /// TreatAsSafe: call to FindToolBar..ctor does not entail any risk. 
        /// 
        [SecurityCritical, SecurityTreatAsSafe]
        private void InstantiateFindToolBar()
        { 
            //First, find the correct place to insert toolbar.
 
            // Location is defined by named element, FindToolbarHost. 
            ContentControl findHost = this.Template.FindName(_findToolBarHostName, this) as ContentControl;
 
            // Only create and hook up the toolbar, if we found a place to put it.
            if (findHost != null)
            {
               if( _findToolbar == null ) 
               {
                    // create the new object 
                    _findToolbar = new FindToolBar(); 

                    // add the event handlers 
                    _findToolbar.FindClicked += new EventHandler(OnFindInvoked);

                    //set initial DocumentLoaded state.
                    _findToolbar.DocumentLoaded = (Document != null) ? true : false; 
                }
 
                // Now insert the toolbar, if it isn't already parented elsewhere. 
                // (It will have been disconnected from DocumentViewer on a Theme or
                // Template change.) 
                if (!_findToolbar.IsAncestorOf(this))
                {
                    ((IAddChild)findHost).AddChild(_findToolbar);
                } 
            }
        } 
 
        /// 
        /// Invoked when the "Find" button in the Find Toolbar is clicked. 
        /// This method invokes the actual Find process.
        /// 
        /// The object that sent this event
        /// The Click Events associated with this event 
        /// 
        /// Critical: get_SearchUp is defined in a non-APTCA assembly. 
        /// TreatAsSafe: call to get_SearchUp does not entail any risk. 
        /// 
        [SecurityCritical, SecurityTreatAsSafe] 
        private void OnFindInvoked(object sender, EventArgs e)
        {
            EventTrace.EasyTraceEvent(EventTrace.Keyword.KeywordXPS, EventTrace.Event.WClientDRXFindBegin);
            try 
            {
                if (_findToolbar != null && TextEditor != null) 
                { 
                    ITextRange findResult = Find(_findToolbar);
 
                    // If we found something, select it.
                    if ((findResult != null) && (!findResult.IsEmpty))
                    {
                        //Give ourselves focus, this ensures that the selection 
                        //will be made visible after it's made.
                        this.Focus(); 
 
                        if (_documentScrollInfo != null)
                        { 
                            _documentScrollInfo.MakeSelectionVisible();
                        }

                        //Put the focus back on the Find Toolbar's TextBox to search again. 
                        _findToolbar.GoToTextBox();
                    } 
                    else 
                    {
                        // No, we did not find anything.  Alert the user. 

                        // build our message string.
                        string messageString = _findToolbar.SearchUp ?
                            SR.Get(SRID.DocumentViewerSearchUpCompleteLabel) : 
                            SR.Get(SRID.DocumentViewerSearchDownCompleteLabel);
 
                        messageString = String.Format( 
                            CultureInfo.CurrentCulture,
                            messageString, 
                            _findToolbar.SearchText);

                        Window wnd = null;
                        if (Application.Current != null && Application.Current.CheckAccess()) 
                        {
                            wnd = Application.Current.MainWindow; 
                        } 

                        MS.Internal.PresentationFramework.SecurityHelper.ShowMessageBoxHelper( 
                            wnd,
                            messageString,
                            SR.Get(SRID.DocumentViewerSearchCompleteTitle),
                            MessageBoxButton.OK, 
                            MessageBoxImage.Asterisk);
                    } 
                } 
            }
            finally 
            {
                EventTrace.EasyTraceEvent(EventTrace.Keyword.KeywordXPS, EventTrace.Event.WClientDRXFindEnd);
            }
        } 

        ///  
        /// This is just a private convenience method for handling the Find command in a 
        /// localized place.
        ///  
        /// 
        /// Critical: GoToTextBox is defined in a non-APTCA assembly.
        /// TreatAsSafe: call to GoToTextBox does not entail any risk.
        ///  
        [SecurityCritical, SecurityTreatAsSafe]
        private void GoToFind() 
        { 
            if (_findToolbar != null)
            { 
                _findToolbar.GoToTextBox();
            }
        }
 

        ///  
        /// This is just a private convenience method to handle those keyboard 
        /// shortcuts related to the Find Command.
        /// localized place. 
        /// 
        /// 
        /// Critical: get_SearchUp is defined in a non-APTCA assembly.
        /// TreatAsSafe: call to get_SearchUp does not entail any risk. 
        /// 
        [SecurityCritical, SecurityTreatAsSafe] 
        private KeyEventArgs ProcessFindKeys(KeyEventArgs e) 
        {
            if (_findToolbar == null || Document == null) 
            {
                // Short-circuit. Find isn't enabled,
                // just exit.
                return e; 
            }
 
            // F3 -- Invoke Find 
            if (e.Key == Key.F3)
            { 
                e.Handled = true;

                //If the Shift key is also pressed, then search up.
                _findToolbar.SearchUp = ((e.KeyboardDevice.Modifiers & ModifierKeys.Shift) == ModifierKeys.Shift); 

                OnFindInvoked(this, EventArgs.Empty); 
            } 

            return e; 
        }

        #endregion Find
 
        /// 
        /// Find the location in the zoomLevelCollection such that it is the closest 
        ///  zoomLevel equal to or lower than the current zoom. 
        /// 
        private void FindZoomLevelIndex() 
        {
            // Ensure the list of zoom levels is created.
            if (_zoomLevelCollection != null)
            { 

                // If the index is not in a valid location, update it to the list start. 
                if ((_zoomLevelIndex < 0) || (_zoomLevelIndex >= _zoomLevelCollection.Length)) 
                {
                    _zoomLevelIndex = 0; 
                    _zoomLevelIndexValid = false;
                }

                // Check if the current index is in the correct location in the list. 
                if (!_zoomLevelIndexValid)
                { 
                    // Since the index is not in the correct location in the list 
                    //  (ie the Zoom was set by another means), then
                    //   search the list of possible zooms for the correct location. 
                    double currentZoom = Zoom;

                    // Currently this search is done using a linear method which is
                    // fine given the small size of the list.  If we increase the list 
                    // size, then a simple binary search could increaes performance.
 
                    // Search the list of zoom's from highest to lowest until the 
                    //   appropriate "floor" level (level equal to, or
                    //   lower than the current zoom) is found. 
                    int loopIndex;
                    for (loopIndex = 0; loopIndex < _zoomLevelCollection.Length - 1; loopIndex++)
                    {
                        if (currentZoom >= _zoomLevelCollection[loopIndex]) 
                        {
                            // Closest equal or lower match found 
                            break; 
                        }
                    } 
                    // Assign the current zoom level, and mark that our index is valid
                    //   (for future Increase / Decrease zoom calls).
                    _zoomLevelIndex = loopIndex;
                    _zoomLevelIndexValid = true; 
                }
            } 
        } 

        ///  
        /// Determines if the parameter represents a valid double (that is a value other
        /// than NaN, PositiveInfinity, or NegativeInfinity).
        /// 
        /// The double value to be checked 
        /// True if the double value is valid, false otherwise.
        private static bool DoubleValue_Validate(object value) 
        { 

            // 


            bool ok;
 
            // Ensure value is double
            if (value is double) 
            { 
                double checkValue = (double)value;
 
                // Check if double is within an assumed range
                if ((double.IsNaN(checkValue)) ||
                    (double.IsInfinity(checkValue)))
                { 
                    ok = false;
                } 
                else 
                {
                    ok = true; 
                }
            }
            else
            { 
                ok = false;
            } 
            return ok; 
        }
 
        /// 
        /// Converts an IDocumentScrollInfo's Scale value to a Zoom
        /// 
        /// A valid IDocumentScrollInfo.Scale value. 
        /// A Zoom value
        private static double ScaleToZoom(double scale) 
        { 
            return scale * 100.0;
        } 

        /// 
        /// Converts a Zoom value to an IDocumentScrollInfo.Scale value.
        ///  
        /// A valid Zoom value.
        /// An IDocumentScrollInfo.Scale value. 
        private static double ZoomToScale(double zoom) 
        {
            return zoom / 100.0; 
        }

        #region DependencyProperties
 
        #region HorizontalOffset
        ///  
        /// Validate the value passed in as a possible offset (either vertical or horizontal) 
        /// 
        /// A double representing the requested offset 
        /// True if the offset is valid, false otherwise.
        private static bool ValidateOffset(object value)
        {
            return DoubleValue_Validate(value) && ((double)value >= 0.0); 
        }
 
        ///  
        /// The HorizontalOffset has changed, and needs to be updated.
        ///  
        private static void OnHorizontalOffsetChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            DocumentViewer dv = (DocumentViewer)d;
            double newOffset = (double) e.NewValue; 

            // If the HorizontalOffset has changed and it isn't due to a change that originated 
            // from our IDocumentScrollInfo object, then set the new offset value on the IDocumentScrollInfo. 
            if (!dv._internalIDSIChange && (dv._documentScrollInfo != null))
            { 
                dv._documentScrollInfo.SetHorizontalOffset(newOffset);
            }
            dv.SetValue(CanMoveLeftPropertyKey, newOffset > 0.0);
            dv.SetValue(CanMoveRightPropertyKey, newOffset < (dv.ExtentWidth - dv.ViewportWidth)); 
        }
        #endregion HorizontalOffset 
 
        #region VerticalOffset
        ///  
        /// The VerticalOffset has changed, and needs to be updated.
        /// 
        private static void OnVerticalOffsetChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        { 
            DocumentViewer dv = (DocumentViewer)d;
            double newOffset = (double) e.NewValue; 
 
            // If the VerticalOffset has changed and it isn't due to a change that originated
            // from our IDocumentScrollInfo object, then set the new offset value on the IDocumentScrollInfo. 
            if ( !dv._internalIDSIChange && (dv._documentScrollInfo != null))
            {
                dv._documentScrollInfo.SetVerticalOffset(newOffset);
            } 
            dv.SetValue(CanMoveUpPropertyKey, newOffset > 0.0);
            dv.SetValue(CanMoveDownPropertyKey, newOffset < (dv.ExtentHeight - dv.ViewportHeight)); 
        } 
        #endregion VerticalOffset
 
        #region ExtentWidth
        private static void OnExtentWidthChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            DocumentViewer dv = (DocumentViewer)d; 
            dv.SetValue(CanMoveRightPropertyKey, dv.HorizontalOffset < ((double) e.NewValue - dv.ViewportWidth));
        } 
        #endregion ExtentWidth 

        #region ExtentHeight 
        private static void OnExtentHeightChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            DocumentViewer dv = (DocumentViewer)d;
            dv.SetValue(CanMoveDownPropertyKey, dv.VerticalOffset < ((double) e.NewValue - dv.ViewportHeight)); 
        }
        #endregion ExtentHeight 
 
        #region ViewportWidth
        private static void OnViewportWidthChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
        {
            DocumentViewer dv = (DocumentViewer)d;
            double newWidth = (double) e.NewValue;
            dv.SetValue(CanMoveRightPropertyKey, dv.HorizontalOffset < (dv.ExtentWidth - (double) e.NewValue)); 
        }
        #endregion ViewportWidth 
 
        #region ViewportHeight
        private static void OnViewportHeightChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
        {
            DocumentViewer dv = (DocumentViewer)d;
            double newHeight = (double) e.NewValue;
            dv.SetValue(CanMoveDownPropertyKey, dv.VerticalOffset < (dv.ExtentHeight - newHeight)); 
        }
        #endregion ViewportHeight 
 
        #region ShowPageBorders
        ///  
        /// ShowPageBorders has changed, and needs to be updated.
        /// 
        private static void OnShowPageBordersChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        { 
            DocumentViewer dv = (DocumentViewer) d;
 
            // If the ShowPageBorders has changed, then set the new value on the IDocumentScrollInfo. 
            if (dv._documentScrollInfo != null)
            { 
                dv._documentScrollInfo.ShowPageBorders = (bool) e.NewValue;
            }
        }
        #endregion ShowPageBorders 

        #region Zoom 
        private static object CoerceZoom(DependencyObject d, object value) 
        {
            double checkValue = (double) value; 
            if (checkValue < DocumentViewerConstants.MinimumZoom)
            {
                return DocumentViewerConstants.MinimumZoom;
            } 

            if (checkValue > DocumentViewerConstants.MaximumZoom) 
            { 
                return DocumentViewerConstants.MaximumZoom;
            } 

            return value;
        }
 
        /// 
        /// The Zoom has changed, and needs to be updated. 
        ///  
        private static void OnZoomChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        { 
            DocumentViewer dv = (DocumentViewer)d;

            // If the ZoomPercentage has changed, then update the IDocumentScrollInfo.
            if (dv._documentScrollInfo != null) 
            {
                double newZoom = (double) e.NewValue; 
                if (!dv._internalIDSIChange) 
                {
                    //Perf Tracing - Mark Zoom Change Start 
                    EventTrace.EasyTraceEvent(EventTrace.Keyword.KeywordXPS, EventTrace.Event.WClientDRXZoom, (int)newZoom);

                    // Set the new zoom scale on IDocumentScrollInfo
                    dv._documentScrollInfo.SetScale(DocumentViewer.ZoomToScale(newZoom)); 
                }
 
                dv.SetValue(CanIncreaseZoomPropertyKey, newZoom < DocumentViewerConstants.MaximumZoom); 
                dv.SetValue(CanDecreaseZoomPropertyKey, newZoom > DocumentViewerConstants.MinimumZoom);
 
                // If the zoom was not set by Increase / DecreaseZoom commands,
                //    then invalidate the zoom level index.
                if (!dv._updatingInternalZoomLevel)
                { 
                    dv._zoomLevelIndexValid = false;
                } 
            } 
        }
        #endregion ZoomPercentage 

        #region MaxPagesAcross

        ///  
        /// Validate the value passed in as a possible MaxPagesAcross
        ///  
        /// An int MaxPagesAcross value 
        /// True if the value is valid, false otherwise.
        private static bool ValidateMaxPagesAcross(object value) 
        {
            int checkValue = (int)value;

            return checkValue > 0 && checkValue <= DocumentViewerConstants.MaximumMaxPagesAcross; 
        }
 
        ///  
        /// The MaxPagesAcross has changed, and needs to be updated.
        ///  
        private static void OnMaxPagesAcrossChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            DocumentViewer dv = (DocumentViewer)d;
 
            //regardless of whether the value of MaxPagesAcross has actually changed.
            //Setting this property will cause content to reflow or rescale to fit and we 
            //want this to happen even if the same number of columns will be visible. 
            //As an example, if we're at 500% showing 1 page, setting MaxPagesAcross to 1 will
            //cause the Zoom to change to show precisely one column. 
            if (!dv._internalIDSIChange)
            {
                dv._documentScrollInfo.SetColumns((int) e.NewValue);
            } 

        } 
        #endregion GridColumnCount 

        #region VerticalPageSpacing 
        /// 
        /// Validate the value passed in as a possible PageSpacing, either vertical or horizontal
        /// 
        /// A value representing the requested page spacing 
        /// True if the offset is valid, false otherwise.
        private static bool ValidatePageSpacing(object value) 
        { 
            return DoubleValue_Validate(value) && ((double)value >= 0.0);
        } 

        /// 
        /// The VerticalPageSpacing has changed, and needs to be updated.
        ///  
        private static void OnVerticalPageSpacingChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        { 
            DocumentViewer dv = (DocumentViewer)d; 

            // If the VerticalPageSpacing has changed, then set the new value on IDocumentScrollInfo. 
            if (dv._documentScrollInfo != null)
            {
                dv._documentScrollInfo.VerticalPageSpacing = (double) e.NewValue;
            } 
        }
        #endregion VerticalPageSpacing 
 
        #region HorizontalPageSpacing
        ///  
        /// The HorizontalPageSpacing has changed, and needs to be updated.
        /// 
        private static void OnHorizontalPageSpacingChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        { 
            DocumentViewer dv = (DocumentViewer)d;
 
            // If the HorizontalPageSpacing has changed, then set the new value on IDocumentScrollInfo. 
            if (dv._documentScrollInfo != null)
            { 
                dv._documentScrollInfo.HorizontalPageSpacing = (double) e.NewValue;
            }
        }
        #endregion HorizontalPageSpacing 

        #endregion Dependency Properties 
 
        #endregion Private Methods
 
        //------------------------------------------------------
        //
        //  Private Fields
        // 
        //-----------------------------------------------------
        #region Private Fields 
 
        // UI Elements
        private IDocumentScrollInfo             _documentScrollInfo; 
        private ScrollViewer                    _scrollViewer;
        private ZoomPercentageConverter         _zoomPercentageConverter;

        //Find ToolBar 
        private FindToolBar _findToolbar;                           // The FindToolbar UI
 
        // Default values for DPs 
        private const double                    _horizontalOffsetDefault = 0.0;
        private const double                    _verticalOffsetDefault = 0.0; 
        private const double                    _extentWidthDefault = 0.0;
        private const double                    _extentHeightDefault = 0.0;
        private const double                    _viewportWidthDefault = 0.0;
        private const double                    _viewportHeightDefault = 0.0; 
        private const bool                      _showPageBordersDefault = true;
        private const double                    _zoomPercentageDefault = 100.0; 
        private const int                       _maxPagesAcrossDefault = 1; 
        private const double                    _verticalPageSpacingDefault = 10.0;
        private const double                    _horizontalPageSpacingDefault = 10.0; 
        private const bool                      _canMoveUpDefault = false;
        private const bool                      _canMoveDownDefault = false;
        private const bool                      _canMoveLeftDefault = false;
        private const bool                      _canMoveRightDefault = false; 
        private const bool                      _canIncreaseZoomDefault = true;
        private const bool                      _canDecreaseZoomDefault = true; 
 //       private const bool                      _isToolbarMaximizedDefault = true; 

        // Our Commands, instantiated on a pay-for-play basis 
        private static RoutedUICommand            _viewThumbnailsCommand;
        private static RoutedUICommand            _fitToWidthCommand;
        private static RoutedUICommand            _fitToHeightCommand;
        private static RoutedUICommand            _fitToMaxPagesAcrossCommand; 

        // This list is assumed to be in decreasing order. 
        private static double[] _zoomLevelCollection = {5000.0, 4000.0, 3200.0, 2400.0, 2000.0, 1600.0, 
                                                       1200.0, 800.0, 400.0, 300.0, 200.0, 175.0, 150.0,
                                                       125.0, 100.0, 75.0, 66.0, 50.0, 33.0, 25.0, 10.0, 5.0}; 
        private int                             _zoomLevelIndex; // = 0
        private bool                            _zoomLevelIndexValid; // = false
        private bool                            _updatingInternalZoomLevel; // = false
        private bool                            _internalIDSIChange; // = false 
        private bool                            _pageViewCollectionChanged; // = false
        private bool                            _firstDocumentAssignment = true; 
 
        private const string                    _findToolBarHostName  = "PART_FindToolBarHost";
        private const string                    _contentHostName = "PART_ContentHost"; 

        #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.
//  
//
// 
// Description: Control for displaying paginated content. 
//
// History: 
// 06/01/2002 - JerrySh - Created.
// 07/09/2003 - JDersch - Initial port to WCP tree
// 11/07/2003 - JDersch - VisualTree Styling overhaul
// 09/21/2004 - JDersch - Cut Annotations, RM & DigSig and Browser-Hosted Toolband 
// 09/23/2004 - JeremyNS - Cut INavigator, IUriContext, SourceProperty
// 10/21/2004 - JeremyNS - Overhauled, and renamed from PageViewer to DocumentViewer 
// 05/10/2005 - JDersch - Ported to DocumentViewerBase 
//
//--------------------------------------------------------------------------- 

using MS.Internal;                                      // For Invariant.Assert
using MS.Internal.Commands;
using MS.Internal.Documents; 
using MS.Utility;
using System; 
using System.Collections; 
using System.Collections.Generic;
using System.Collections.ObjectModel; 
using System.ComponentModel;                            // For DesignerSerializationVisibility
using System.Globalization;
using System.Reflection;
using System.Windows; 
using System.Windows.Automation;
using System.Windows.Automation.Peers; 
using System.Windows.Automation.Provider; 
using System.Windows.Controls;
using System.Windows.Controls.Primitives; 
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Navigation;                        // For HyperLink navigation event. 
using System.Windows.Markup;
using MS.Internal.Automation;                           // For TextAdaptor. 
using System.Security; 

 
namespace System.Windows.Controls
{

    ///  
    /// DocumentViewer is a control that allows developers to create a custom reading
    /// experience in their applications for digital documents. 
    ///  
    /// 
    /// http://d2/DRX/default.aspx 
    [TemplatePart(Name = "PART_FindToolBarHost", Type = typeof(ContentControl))]
    [TemplatePart(Name = "PART_ContentHost", Type = typeof(ScrollViewer))]
    public class DocumentViewer : DocumentViewerBase
    { 

        //----------------------------------------------------- 
        // 
        //  Constructors
        // 
        //-----------------------------------------------------

        #region Constructors
        ///  
        /// Initializes class-wide settings.
        ///  
        static DocumentViewer() 
        {
            // Create our CommandBindings 
            CreateCommandBindings();

            // Register property metadata
            RegisterMetadata(); 
        }
 
        ///  
        /// Instantiates a new instance of a DocumentViewer
        ///  
        public DocumentViewer() : base()
        {
            //Perf Tracing - DocumentViewer Construction
            EventTrace.EasyTraceEvent(EventTrace.Keyword.KeywordXPS, EventTrace.Event.WClientDRXInstantiated); 

            SetUp(); 
        } 

        #endregion Constructors 

        //------------------------------------------------------
        //
        //  Public Methods 
        //
        //----------------------------------------------------- 
 
        #region Public Methods
 
        #region Command convenience methods

        /// 
        /// Tells DocumentViewer to display a "thumbnail view" of pages.  This is analogous 
        /// to the ViewThumbnailsCommand.
        ///  
        public void ViewThumbnails() 
        {
            OnViewThumbnailsCommand(); 
        }

        /// 
        /// Tells DocumentViewer to fit a single page to the width of the current viewport. 
        /// This is analogous to the FitToWidthCommand.
        ///  
        public void FitToWidth() 
        {
            OnFitToWidthCommand(); 
        }

        /// 
        /// Tells DocumentViewer to fit a single page to the height of the current viewport. 
        /// This is analogous to the FitToHeightCommand.
        ///  
        public void FitToHeight() 
        {
            OnFitToHeightCommand(); 
        }

        /// 
        /// Tells DocumentViewer to fit the current MaxPagesAcross count to the current 
        /// viewport.  This is analogous to the FitToMaxPagesAcrossCommand.
        ///  
        public void FitToMaxPagesAcross() 
        {
            OnFitToMaxPagesAcrossCommand(); 
        }

        /// 
        /// Tells DocumentViewer to fit the specified number of pages across to the current viewport 
        /// and sets MaxPagesAcross to the passed in value.  This is analogous to the
        /// FitMaxPagesAcrossCommand. 
        ///  
        /// 
        public void FitToMaxPagesAcross(int pagesAcross) 
        {
            if (ValidateMaxPagesAcross(pagesAcross))
            {
                if (_documentScrollInfo != null) 
                {
                    _documentScrollInfo.FitColumns(pagesAcross); 
                } 
            }
            else 
            {
                throw new ArgumentOutOfRangeException("pagesAcross");
            }
        } 

        ///  
        /// Tells DocumentViewer to invoke the Find Dialog.  This is analogous to the 
        /// FindCommand.
        ///  
        public void Find()
        {
            OnFindCommand();
        } 

        ///  
        /// Tells DocumentViewer to scroll up by one viewport.  This is analogous to the 
        /// ScrollPageUpCommand.
        ///  
        public void ScrollPageUp()
        {
            OnScrollPageUpCommand();
        } 

        ///  
        /// Tells DocumentViewer to scroll down by one viewport.  This is analogous to the 
        /// ScrollPageDownCommand.
        ///  
        public void ScrollPageDown()
        {
            OnScrollPageDownCommand();
        } 

        ///  
        /// Tells DocumentViewer to scroll left by one viewport.  This is analogous to the 
        /// ScrollPageLeftCommand.
        ///  
        public void ScrollPageLeft()
        {
            OnScrollPageLeftCommand();
        } 

        ///  
        /// Tells DocumentViewer to scroll right by one viewport.  This is analogous to the 
        /// ScrollPageRightCommand.
        ///  
        public void ScrollPageRight()
        {
            OnScrollPageRightCommand();
        } 

        ///  
        /// Tells DocumentViewer to scroll up by one line (16px).  This is analogous to the 
        /// MoveUpCommand.
        ///  
        public void MoveUp()
        {
            OnMoveUpCommand();
        } 

        ///  
        /// Tells DocumentViewer to scroll down by one line (16px).  This is analogous to the 
        /// MoveDownCommand.
        ///  
        public void MoveDown()
        {
            OnMoveDownCommand();
        } 

        ///  
        /// Tells DocumentViewer to scroll left by one line (16px).  This is analogous to the 
        /// MoveLeftCommand.
        ///  
        public void MoveLeft()
        {
            OnMoveLeftCommand();
        } 

        ///  
        /// Tells DocumentViewer to scroll right by one line (16px).  This is analogous to the 
        /// MoveRightCommand.
        ///  
        public void MoveRight()
        {
            OnMoveRightCommand();
        } 

        ///  
        /// Tells DocumentViewer to increase Zoom by a predefined, nonlinear value.  This is 
        /// analogous to the IncreaseZoomCommand.
        ///  
        public void IncreaseZoom()
        {
            OnIncreaseZoomCommand();
        } 

        ///  
        /// Tells DocumentViewer to decrease Zoom by a predefined, nonlinear value.  This is 
        /// analogous to the DecreaseZoomCommand.
        ///  
        public void DecreaseZoom()
        {
            OnDecreaseZoomCommand();
        } 

        #endregion Command convenience methods 
 
        /// 
        /// Called when the Template's tree has been generated 
        /// 
        /// 
        /// This method is commonly used to check the status of the visual
        /// tree prior to rendering, so that elements of the tree can be 
        /// customized before they are shown.
        /// If a style is changed that affects the visual tree, the 
        /// ApplyTemplate method will expand the new visual tree and return 
        /// true. Otherwise, it will return false.
        /// When overriding this method, be sure to call the ApplyTemplate 
        /// method of the base class.
        /// 
        /// 
        /// True if the Visual Tree has been created 
        /// 
        /// There must be a ScrollViewer in 
        /// DocumentViewer's visual tree which has Name PART_ContentHost. 
        public override void OnApplyTemplate()
        { 
            base.OnApplyTemplate();

            // Walk the visual tree, locating those elements marked with the special
            // properties such as "I'm the Content area!" 
            FindContentHost();
 
            // Create the Find toolbar and add it to our Visual Tree when appropriate. 
            InstantiateFindToolBar();
 
            //Perf Tracing - DocumentViewer Visuals Created
            EventTrace.EasyTraceEvent(EventTrace.Keyword.KeywordXPS, EventTrace.Event.WClientDRXStyleCreated);

            // If unset, we will set the ContextMenu property to null -- this will prevent the TextEditor 
            // from overriding our ContextMenu with its own.  The TextEditor checks the UIScope (DocumentViewer)
            // not the RenderScope (DocumentGrid) for previously-set Context Menus, and if it finds one (or if 
            // it finds that ContextMenu has explicitly been set to null, it will not override it. 
            // Since DocumentViewer doesn't have a ContextMenu -- the ContextMenu is set on DocumentGrid which the
            // TextEditor won't find, we set ContextMenu to null here. 
            // Yes, this seems, on the surface, to be a bit redundant -- but there is a difference between an
            // "unset null" and an "explicitly set" null to the Property engine that the TextEditor looks for.
            // We check that the ContextMenu is null because we don't want to override any user-specified ContextMenus.
            if (this.ContextMenu == null) 
            {
                this.ContextMenu = null; 
            } 
        }
 
        #endregion Public Methods

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

        #region Public Properties 

        #region Commands

        ///  
        /// This command will invoke ViewThumbnails method, causing as many pages
        /// as feasible to be displayed in the current viewport. 
        ///  
        public static RoutedUICommand ViewThumbnailsCommand
        { 
             get
             {
                 return _viewThumbnailsCommand;
             } 
        }
 
        ///  
        /// This command will invoke the FitToWidth method,
        /// setting the layout to 1 page across, and zooming so that one page is displayed 
        /// at the width of the current viewport.
        /// 
        public static RoutedUICommand FitToWidthCommand
        { 
            get
            { 
                return _fitToWidthCommand; 
            }
        } 

        /// 
        /// This command will invoke the FitToWidth method,
        /// setting the layout to 1 page across, and zooming so that one page is displayed 
        /// at the height of the current viewport.
        ///  
        public static RoutedUICommand FitToHeightCommand 
        {
            get 
            {
                return _fitToHeightCommand;
            }
        } 

        ///  
        /// This command will invoke the FitToMaxPagesAcross method, 
        /// effectively setting MaxPagesAcross
        /// to the value of the parameter and fitting those pages into view. 
        /// 
        public static RoutedUICommand FitToMaxPagesAcrossCommand
        {
            get 
            {
                return _fitToMaxPagesAcrossCommand; 
            } 
        }
 
        #endregion Commands

        #region Dependency Properties
 
        #region HorizontalOffset
        ///  
        /// Reflects the current Horizontal position in the document in pixel units given 
        /// the current page layout.
        ///  
        public static readonly DependencyProperty HorizontalOffsetProperty =
                DependencyProperty.Register(
                        "HorizontalOffset",
                        typeof(double), 
                        typeof(DocumentViewer),
                        new FrameworkPropertyMetadata( 
                                _horizontalOffsetDefault, //default value 
                                FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, //MetaData flags
                                new PropertyChangedCallback(OnHorizontalOffsetChanged)), //changed callback 
                        new ValidateValueCallback(ValidateOffset)); //validate callback

        /// 
        /// Reflects the current Horizontal position in the document in pixel units given 
        /// the current page layout.
        ///  
        public double HorizontalOffset 
        {
            get { return (double) GetValue(HorizontalOffsetProperty); } 
            set
            {
                SetValue(HorizontalOffsetProperty, value);
            } 
        }
        #endregion HorizontalOffset 
 
        #region VerticalOffset
        ///  
        /// Reflects the current Vertical position in the document in pixel units given
        /// the current page layout.
        /// 
        public static readonly DependencyProperty VerticalOffsetProperty = 
                DependencyProperty.Register(
                        "VerticalOffset", 
                        typeof(double), 
                        typeof(DocumentViewer),
                        new FrameworkPropertyMetadata( 
                                _verticalOffsetDefault, //default value
                                FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, //MetaData flags
                                new PropertyChangedCallback(OnVerticalOffsetChanged)), //changed callback
                        new ValidateValueCallback(ValidateOffset)); //validate callback 

        ///  
        /// Reflects the current Vertical position in the document in pixel units given 
        /// the current page layout.
        ///  
        public double VerticalOffset
        {
            get { return (double) GetValue(VerticalOffsetProperty); }
            set 
            {
                SetValue(VerticalOffsetProperty, value); 
            } 
        }
        #endregion VerticalOffset 

        #region ExtentWidth
        /// 
        /// Reflects the current width of the document layout. 
        /// 
        private static readonly DependencyPropertyKey ExtentWidthPropertyKey = 
                DependencyProperty.RegisterReadOnly( 
                        "ExtentWidth",
                        typeof(double), 
                        typeof(DocumentViewer),
                        new FrameworkPropertyMetadata(
                                _extentWidthDefault,
                                new PropertyChangedCallback(OnExtentWidthChanged))); 

        ///  
        /// Reflects the current width of the document layout. 
        /// 
        public static readonly DependencyProperty ExtentWidthProperty = 
                ExtentWidthPropertyKey.DependencyProperty;

        /// 
        /// Reflects the current width of the document layout. 
        /// 
        public double ExtentWidth 
        { 
            get { return (double) GetValue(ExtentWidthProperty); }
        } 
        #endregion ExtentWidth

        #region ExtentHeight
        ///  
        /// Reflects the current height of the document layout.
        ///  
        private static readonly DependencyPropertyKey ExtentHeightPropertyKey = 
                DependencyProperty.RegisterReadOnly(
                        "ExtentHeight", 
                        typeof(double),
                        typeof(DocumentViewer),
                        new FrameworkPropertyMetadata(
                                _extentHeightDefault, 
                                new PropertyChangedCallback(OnExtentHeightChanged)));
 
        ///  
        /// Reflects the current height of the document layout.
        ///  
        public static readonly DependencyProperty ExtentHeightProperty =
                ExtentHeightPropertyKey.DependencyProperty;

        ///  
        /// Reflects the current height of the document layout.
        ///  
        public double ExtentHeight 
        {
            get { return (double) GetValue(ExtentHeightProperty); } 
        }
        #endregion ExtentHeight

        #region ViewportWidth 
        /// 
        /// Reflects the current width of the DocumentViewer's content area. 
        ///  
        private static readonly DependencyPropertyKey ViewportWidthPropertyKey =
                DependencyProperty.RegisterReadOnly( 
                        "ViewportWidth",
                        typeof(double),
                        typeof(DocumentViewer),
                        new FrameworkPropertyMetadata( 
                                _viewportWidthDefault,
                                new PropertyChangedCallback(OnViewportWidthChanged))); 
 

        ///  
        /// Reflects the current width of the DocumentViewer's content area.
        /// 
        public static readonly DependencyProperty ViewportWidthProperty =
                ViewportWidthPropertyKey.DependencyProperty; 

        ///  
        /// Reflects the current width of the DocumentViewer's content area. 
        /// 
        public double ViewportWidth 
        {
            get { return (double) GetValue(ViewportWidthProperty); }
        }
        #endregion ViewportWidth 

        #region ViewportHeight 
        ///  
        /// Reflects the current height of the DocumentViewer's content area.
        ///  
        private static readonly DependencyPropertyKey ViewportHeightPropertyKey =
                DependencyProperty.RegisterReadOnly(
                        "ViewportHeight",
                        typeof(double), 
                        typeof(DocumentViewer),
                        new FrameworkPropertyMetadata( 
                                _viewportHeightDefault, 
                                new PropertyChangedCallback(OnViewportHeightChanged)));
 
        /// 
        /// Reflects the current height of the DocumentViewer's content area.
        /// 
        public static readonly DependencyProperty ViewportHeightProperty = 
                ViewportHeightPropertyKey.DependencyProperty;
 
        ///  
        /// Reflects the current height of the DocumentViewer's content area.
        ///  
        public double ViewportHeight
        {
            get { return (double) GetValue(ViewportHeightProperty);  }
        } 
        #endregion ViewportHeight
 
        #region ShowPageBorders 
        /// 
        /// Reflects whether a "Drop Shadow" border should be shown around the pages being displayed. 
        /// 
        public static readonly DependencyProperty ShowPageBordersProperty =
                DependencyProperty.Register(
                        "ShowPageBorders", 
                        typeof(bool),
                        typeof(DocumentViewer), 
                        new FrameworkPropertyMetadata( 
                                _showPageBordersDefault, //default value
                                FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, //MetaData flags 
                                new PropertyChangedCallback(OnShowPageBordersChanged))); //changed callback

        /// 
        /// Reflects whether a "Drop Shadow" border should be shown around the pages being displayed. 
        /// 
        public bool ShowPageBorders 
        { 
            get { return (bool) GetValue(ShowPageBordersProperty); }
            set { SetValue(ShowPageBordersProperty, value); } 
        }
        #endregion ShowPageBorders

        #region Zoom 
        /// 
        /// Reflects the effective Zoom percentage based on the last layout related 
        /// property set or command issued. 
        /// If this was the last property set, or the Zoom command was last issued,
        /// then this will just be the last Zoom value set. 
        /// When another layout related property (ie MaxPagesAcross, etc) was set
        /// or a command (ie FitToMaxPagesAcross, FitToHeight, etc) was issued, then
        /// this value will be the resulting Zoom value from that layout adjustment.
        /// 
        /// Must be greater than 5.0 and less than 5000.0.  Invalid values will throw.
        ///  
        public static readonly DependencyProperty ZoomProperty = 
                DependencyProperty.Register(
                        "Zoom", 
                        typeof(double),
                        typeof(DocumentViewer),
                        new FrameworkPropertyMetadata(
                                _zoomPercentageDefault, //default value 
                                FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, //MetaData flags
                                new PropertyChangedCallback(OnZoomChanged),  //changed callback 
                                new CoerceValueCallback(CoerceZoom))); // coercion callback 

        ///  
        /// Reflects the effective Zoom percentage based on the last layout related
        /// property set or command issued.
        /// If this was the last property set, or the Zoom command was last issued,
        /// then this will just be the last Zoom value set. 
        /// When another layout related property (ie MaxPagesAcross, etc) was set
        /// or a command (ie FitToMaxPagesAcross, FitToHeight, etc) was issued, then 
        /// this value will be the resulting Zoom value from that layout adjustment. 
        ///
        /// Must be greater than 5.0 and less than 5000.0. 
        /// 
        public double Zoom
        {
            get { return (double) GetValue(ZoomProperty); } 
            set { SetValue(ZoomProperty, value); }
        } 
        #endregion Zoom 

        #region MaxPagesAcross 
        /// 
        /// Reflects the number of Columns of pages displayed, based on the last
        /// value set through this property, or a layout related command
        /// (ie FitToMaxPagesAcross, ViewThumbnails, etc..) 
        /// 
        public static readonly DependencyProperty MaxPagesAcrossProperty = 
                DependencyProperty.Register( 
                        "MaxPagesAcross",
                        typeof(int), 
                        typeof(DocumentViewer),
                        new FrameworkPropertyMetadata(
                                _maxPagesAcrossDefault, //default value
                                FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, //MetaData flags 
                                new PropertyChangedCallback(OnMaxPagesAcrossChanged)), //changed callback
                        new ValidateValueCallback(ValidateMaxPagesAcross)); //validation callback 
 
        /// 
        /// Reflects the number of Columns of pages displayed, based on the last 
        /// value set through this property, or a layout related command
        /// (ie FitToMaxPagesAcross, ViewThumbnails, etc..)
        /// Valid values are from 1 to 32, inclusive.
        ///  
        public int MaxPagesAcross
        { 
            get { return (int) GetValue(MaxPagesAcrossProperty); } 
            set { SetValue(MaxPagesAcrossProperty, value); }
        } 
        #endregion MaxPagesAcross

        #region VerticalPageSpacing
        ///  
        /// Reflects the vertical gap between Pages when laid out, in pixel units.
        ///  
        public static readonly DependencyProperty VerticalPageSpacingProperty = 
                DependencyProperty.Register(
                        "VerticalPageSpacing", 
                        typeof(double),
                        typeof(DocumentViewer),
                        new FrameworkPropertyMetadata(
                                _verticalPageSpacingDefault, //default value 
                                new PropertyChangedCallback(OnVerticalPageSpacingChanged)), //changed callback
                        new ValidateValueCallback(ValidatePageSpacing)); //validation callback 
 
        /// 
        /// Reflects the vertical gap between Pages when laid out, in pixel units. 
        /// 
        public double VerticalPageSpacing
        {
            get { return (double) GetValue(VerticalPageSpacingProperty); } 
            set { SetValue(VerticalPageSpacingProperty, value); }
        } 
        #endregion VerticalPageSpacing 

        #region HorizontalPageSpacing 
        /// 
        /// Reflects the horizontal gap between Pages when laid out, in pixel units.
        /// 
        public static readonly DependencyProperty HorizontalPageSpacingProperty = 
                DependencyProperty.Register(
                        "HorizontalPageSpacing", 
                        typeof(double), 
                        typeof(DocumentViewer),
                        new FrameworkPropertyMetadata( 
                                _horizontalPageSpacingDefault, //default value
                                new PropertyChangedCallback(OnHorizontalPageSpacingChanged)), //changed callback
                        new ValidateValueCallback(ValidatePageSpacing)); //validation callback
 
        /// 
        /// Reflects the horizontal gap between Pages when laid out, in pixel units. 
        ///  
        public double HorizontalPageSpacing
        { 
            get { return (double) GetValue(HorizontalPageSpacingProperty); }
            set { SetValue(HorizontalPageSpacingProperty, value); }
        }
        #endregion HorizontalPageSpacing 

        #region CanMoveUp 
        ///  
        /// Reflects whether the DocumentViewer is at the top of the current document.
        ///  
        private static readonly DependencyPropertyKey CanMoveUpPropertyKey =
                DependencyProperty.RegisterReadOnly(
                        "CanMoveUp",
                        typeof(bool), 
                        typeof(DocumentViewer),
                        new FrameworkPropertyMetadata(_canMoveUpDefault)); 
 
        /// 
        /// Reflects whether the DocumentViewer is at the top of the current document. 
        /// 
        public static readonly DependencyProperty CanMoveUpProperty =
                CanMoveUpPropertyKey.DependencyProperty;
 
        /// 
        /// Reflects whether the DocumentViewer is at the top of the current document. 
        ///  
        public bool CanMoveUp
        { 
            get { return (bool) GetValue(CanMoveUpProperty); }
        }
        #endregion CanMoveUp
 
        #region CanMoveDown
        ///  
        /// Reflects whether the DocumentViewer is at the bottom of the current document. 
        /// 
        private static readonly DependencyPropertyKey CanMoveDownPropertyKey = 
                DependencyProperty.RegisterReadOnly(
                        "CanMoveDown",
                        typeof(bool),
                        typeof(DocumentViewer), 
                        new FrameworkPropertyMetadata(_canMoveDownDefault));
 
        ///  
        /// Reflects whether the DocumentViewer is at the bottom of the current document.
        ///  
        public static readonly DependencyProperty CanMoveDownProperty =
                CanMoveDownPropertyKey.DependencyProperty;

        ///  
        /// Reflects whether the DocumentViewer is at the bottom of the current document.
        ///  
        public bool CanMoveDown 
        {
            get { return (bool) GetValue(CanMoveDownProperty); } 
        }
        #endregion CanMoveDown

        #region CanMoveLeft 
        /// 
        /// Reflects whether the DocumentViewer is at the leftmost extent of the current document. 
        ///  
        private static readonly DependencyPropertyKey CanMoveLeftPropertyKey =
                DependencyProperty.RegisterReadOnly( 
                        "CanMoveLeft",
                        typeof(bool),
                        typeof(DocumentViewer),
                        new FrameworkPropertyMetadata(_canMoveLeftDefault)); 

        ///  
        /// Reflects whether the DocumentViewer is at the leftmost extent of the current document. 
        /// 
        public static readonly DependencyProperty CanMoveLeftProperty = 
                CanMoveLeftPropertyKey.DependencyProperty;

        /// 
        /// Reflects whether the DocumentViewer is at the leftmost extent of the current document. 
        /// 
        public bool CanMoveLeft 
        { 
            get { return (bool) GetValue(CanMoveLeftProperty); }
        } 
        #endregion CanMoveLeft

        #region CanMoveRight
        ///  
        /// Reflects whether the DocumentViewer is at the rightmost extent of the current document.
        ///  
        private static readonly DependencyPropertyKey CanMoveRightPropertyKey = 
                DependencyProperty.RegisterReadOnly(
                        "CanMoveRight", 
                        typeof(bool),
                        typeof(DocumentViewer),
                        new FrameworkPropertyMetadata(_canMoveRightDefault));
 
        /// 
        /// Reflects whether the DocumentViewer is at the rightmost extent of the current document. 
        ///  
        public static readonly DependencyProperty CanMoveRightProperty =
                CanMoveRightPropertyKey.DependencyProperty; 

        /// 
        /// Reflects whether the DocumentViewer is at the rightmost extent of the current document.
        ///  
        public bool CanMoveRight
        { 
            get { return (bool) GetValue(CanMoveRightProperty); } 
        }
        #endregion CanMoveRight 

        #region CanIncreaseZoom
        /// 
        /// Reflects whether the DocumentViewer can zoom in any further 
        /// (ie not at the highest "zoom level") of the current document.
        ///  
        private static readonly DependencyPropertyKey CanIncreaseZoomPropertyKey = 
                DependencyProperty.RegisterReadOnly(
                        "CanIncreaseZoom", 
                        typeof(bool),
                        typeof(DocumentViewer),
                        new FrameworkPropertyMetadata(_canIncreaseZoomDefault));
 
        /// 
        /// Reflects whether the DocumentViewer can zoom in any further 
        /// (ie not at the highest "zoom level") of the current document. 
        /// 
        public static readonly DependencyProperty CanIncreaseZoomProperty = 
                CanIncreaseZoomPropertyKey.DependencyProperty;

        /// 
        /// Reflects whether the DocumentViewer can zoom in any further 
        /// (ie not at the highest "zoom level") of the current document.
        ///  
        public bool CanIncreaseZoom 
        {
            get { return (bool) GetValue(CanIncreaseZoomProperty); } 
        }
        #endregion CanIncreaseZoom

        #region CanDecreaseZoom 
        /// 
        /// Reflects whether the DocumentViewer can zoom out any further 
        /// (ie not at the lowest "zoom level") of the current document. 
        /// 
        private static readonly DependencyPropertyKey CanDecreaseZoomPropertyKey = 
                DependencyProperty.RegisterReadOnly(
                        "CanDecreaseZoom",
                        typeof(bool),
                        typeof(DocumentViewer), 
                        new FrameworkPropertyMetadata(_canDecreaseZoomDefault));
 
        ///  
        /// Reflects whether the DocumentViewer can zoom out any further
        /// (ie not at the lowest "zoom level") of the current document. 
        /// 
        public static readonly DependencyProperty CanDecreaseZoomProperty =
                CanDecreaseZoomPropertyKey.DependencyProperty;
 
        /// 
        /// Reflects whether the DocumentViewer can zoom out any further 
        /// (ie not at the lowest "zoom level") of the current document. 
        /// 
        public bool CanDecreaseZoom 
        {
            get { return (bool) GetValue(CanDecreaseZoomProperty); }
        }
        #endregion CanDecreaseZoom 

        #endregion Dependency Properties 
 
        #endregion Public Properties
 
        //-----------------------------------------------------
        //
        //  Public Operators
        // 
        //------------------------------------------------------
 
        //----------------------------------------------------- 
        //
        //  Public Events 
        //
        //-----------------------------------------------------

        //----------------------------------------------------- 
        //
        //  Protected Methods 
        // 
        //------------------------------------------------------
        #region Protected Methods 

        /// 
        /// Creates AutomationPeer ()
        ///  
        protected override AutomationPeer OnCreateAutomationPeer()
        { 
            return new DocumentViewerAutomationPeer(this); 
        }
 
        /// 
        /// Attaches DocumentGrid to our document when it changes.
        /// 
        ///  
        /// Critical: set_DocumentLoaded is defined in a non-APTCA assembly.
        /// TreatAsSafe: call to set_DocumentLoaded does not entail any risk. 
        ///  
        [SecurityCritical, SecurityTreatAsSafe]
        protected override void OnDocumentChanged() 
        {
            // Validate the new document type
            if (!(Document is FixedDocument) && !(Document is FixedDocumentSequence)
                && !(Document == null)) 
            {
                throw new NotSupportedException(SR.Get(SRID.DocumentViewerOnlySupportsFixedDocumentSequence)); 
            } 

            //Call the base so that TextEditors are attached. 
            base.OnDocumentChanged();

            //Assign the content to DocumentGrid.
            AttachContent(); 

            // Update the toolbar with our current document state. 
            if (_findToolbar != null) 
            {
                _findToolbar.DocumentLoaded = (Document != null) ? true : false; 
            }

            // We do not automatically go to the first page on the _first_ content
            // assignment, for two reasons: 
            //  1) If this is the first assignment, then we're already there by default.
            //  2) The user may have specified vertical or horizontal offsets in markup or 
            //     otherwise () and we need to honor 
            //     those settings.
            if (!_firstDocumentAssignment) 
            {
                // Go to the first page of new content.
                OnGoToPageCommand(1);
            } 
            _firstDocumentAssignment = false;
 
        } 

        ///  
        /// Called when a BringIntoView event is bubbled up from the Document.
        /// Base implementation will move the master page to the page
        /// on which the element occurs.
        ///  
        /// The object to make visible.
        /// The rectangular region in the object's coordinate space which should be made visible. 
        ///  
        protected override void OnBringIntoView(DependencyObject element, Rect rect, int pageNumber)
        { 
            // DVBase will give us a 1-indexed page number, we convert to 0-indexed.
            int zeroIndexed = pageNumber - 1;
            if (zeroIndexed >= 0 && zeroIndexed < PageCount)
            { 
                _documentScrollInfo.MakeVisible(element, rect, zeroIndexed);
            } 
        } 

        ///  
        /// Handler for the PreviousPage command.
        /// 
        protected override void OnPreviousPageCommand()
        { 
            //Scroll to the previous row.
            if (_documentScrollInfo != null) 
            { 
                _documentScrollInfo.ScrollToPreviousRow();
            } 
        }

        /// 
        /// Handler for the NextPage command. 
        /// 
        protected override void OnNextPageCommand() 
        { 
            //Scroll to the previous row.
            if (_documentScrollInfo != null) 
            {
                _documentScrollInfo.ScrollToNextRow();
            }
        } 

        ///  
        /// Handler for the FirstPage command. 
        /// 
        protected override void OnFirstPageCommand() 
        {
            //Scroll to the top of the document.
            if (_documentScrollInfo != null)
            { 
                _documentScrollInfo.MakePageVisible( 0 );
            } 
        } 

        ///  
        /// Handler for the LastPage command.
        /// 
        protected override void OnLastPageCommand()
        { 
            //Scroll to the bottom of the document.
            if (_documentScrollInfo != null) 
            { 
                _documentScrollInfo.MakePageVisible( PageCount - 1 );
            } 
        }

        /// 
        /// Handler for the GoToPage command. 
        /// 
        protected override void OnGoToPageCommand(int pageNumber) 
        { 
            // Check if we can go to the specified page.
            // and navigate there. 
            if (CanGoToPage(pageNumber))
            {
                //Scroll to the specified page in the document.
                if (_documentScrollInfo != null) 
                {
                    // CanGoToPage should have guaranteed that this assert is always true. 
                    Invariant.Assert(pageNumber > 0, "PageNumber must be positive."); 
                    _documentScrollInfo.MakePageVisible(pageNumber - 1);
                } 
            }
        }

        ///  
        /// Handler for the ViewThumbnails Command
        ///  
        protected virtual void OnViewThumbnailsCommand() 
        {
            if (_documentScrollInfo != null) 
            {
                _documentScrollInfo.ViewThumbnails();
            }
        } 

        ///  
        /// Handler for the FitToWidth Command 
        /// 
        protected virtual void OnFitToWidthCommand() 
        {
            if (_documentScrollInfo != null)
            {
                _documentScrollInfo.FitToPageWidth(); 
            }
        } 
 
        /// 
        /// Handler for the FitToHeight Command 
        /// 
        protected virtual void OnFitToHeightCommand()
        {
            if (_documentScrollInfo != null) 
            {
                _documentScrollInfo.FitToPageHeight(); 
            } 
        }
 
        /// 
        /// Handler for the FitToMaxPagesAcross Command
        /// 
        protected virtual void OnFitToMaxPagesAcrossCommand() 
        {
            if (_documentScrollInfo != null) 
            { 
                _documentScrollInfo.FitColumns(MaxPagesAcross);
            } 
        }

        /// 
        /// HAndler for the FitMaxPagesAcross Command 
        /// 
        ///  
        protected virtual void OnFitToMaxPagesAcrossCommand(int pagesAcross) 
        {
            if (ValidateMaxPagesAcross(pagesAcross)) 
            {
                if (_documentScrollInfo != null)
                {
                    _documentScrollInfo.FitColumns(pagesAcross); 
                }
            } 
            else 
            {
                throw new ArgumentOutOfRangeException("pagesAcross"); 
            }
        }

        ///  
        /// Handler for the Find Command
        ///  
        protected virtual void OnFindCommand() 
        {
            GoToFind(); 
        }

        /// 
        /// This is the method that responds to the KeyDown event. 
        /// 
        ///  
        protected override void OnKeyDown(KeyEventArgs e) 
        {
            // Look for Find specific key inputs and process them. 
            // If the key is processed, this event will be marked handled.
            e = ProcessFindKeys(e);

            base.OnKeyDown(e); 
        }
 
        ///  
        /// Handler for the ScrollPageUp Command
        ///  
        protected virtual void OnScrollPageUpCommand()
        {
            if (_documentScrollInfo != null)
            { 
                _documentScrollInfo.PageUp();
            } 
        } 

        ///  
        /// Handler for the ScrollPageDown Command
        /// 
        protected virtual void OnScrollPageDownCommand()
        { 
            if (_documentScrollInfo != null)
            { 
                _documentScrollInfo.PageDown(); 
            }
        } 

        /// 
        /// Handler for the ScrollPageLeft Command
        ///  
        protected virtual void OnScrollPageLeftCommand()
        { 
            if (_documentScrollInfo != null) 
            {
                _documentScrollInfo.PageLeft(); 
            }
        }

        ///  
        /// Handler for the ScrollPageRight Command
        ///  
        protected virtual void OnScrollPageRightCommand() 
        {
            if (_documentScrollInfo != null) 
            {
                _documentScrollInfo.PageRight();
            }
        } 

        ///  
        /// Handler for the MoveUp Command 
        /// 
        protected virtual void OnMoveUpCommand() 
        {
            if (_documentScrollInfo != null)
            {
                _documentScrollInfo.LineUp(); 
            }
        } 
 
        /// 
        /// Handler for the MoveDown Command 
        /// 
        protected virtual void OnMoveDownCommand()
        {
            if (_documentScrollInfo != null) 
            {
                _documentScrollInfo.LineDown(); 
            } 
        }
 
        /// 
        /// Handler for the MoveLeft Command
        /// 
        protected virtual void OnMoveLeftCommand() 
        {
            if (_documentScrollInfo != null) 
            { 
                _documentScrollInfo.LineLeft();
            } 
        }

        /// 
        /// Handler for the MoveRight Command 
        /// 
        protected virtual void OnMoveRightCommand() 
        { 
            if (_documentScrollInfo != null)
            { 
                _documentScrollInfo.LineRight();
            }
        }
 
        /// 
        /// Handler for the IncreaseZoom Command 
        ///  
        protected virtual void OnIncreaseZoomCommand()
        { 
            // Check if possible to zoom in
            if (CanIncreaseZoom)
            {
                // Update the zoom level index to the appropriate place. 
                double oldZoom = Zoom;
                FindZoomLevelIndex(); 
                // As long as more zoomLevel's exist, increase zoom. 
                if (_zoomLevelIndex > 0)
                { 
                    _zoomLevelIndex--;
                }

                // Set the zoom percentage, with _updatingInternalZoomLevel set to true to 
                //   avoid resetting the zoom level index.
                _updatingInternalZoomLevel = true; 
                Zoom = DocumentViewer._zoomLevelCollection[_zoomLevelIndex]; 
                _updatingInternalZoomLevel = false;
            } 
        }

        /// 
        /// Handler for the DecreaseZoom Command 
        /// 
        protected virtual void OnDecreaseZoomCommand() 
        { 
            // Check if possible to zoom out.
            if (CanDecreaseZoom) 
            {
                // Update the zoom level index to the appropriate place.
                double oldZoom = Zoom;
                FindZoomLevelIndex(); 
                // If the current zoom value exists in the zoomLevelCollection, and can
                //   still be zoomed out, then zoom out another level. 
                if ((oldZoom == DocumentViewer._zoomLevelCollection[_zoomLevelIndex]) && 
                    (_zoomLevelIndex < DocumentViewer._zoomLevelCollection.Length - 1))
               { 
                    _zoomLevelIndex++;
                }

                // Set the zoom percentage, with _updatingInternalZoomLevel set to true to 
                //   avoid resetting the zoom level index.
                _updatingInternalZoomLevel = true; 
                Zoom = _zoomLevelCollection[_zoomLevelIndex]; 
                _updatingInternalZoomLevel = false;
            } 
        }

        /// 
        /// Overrides the base implementation and returns the current collection of 
        /// DocumentPageViews being displayed in our IDSI.
        ///  
        ///  
        /// 
        protected override ReadOnlyCollection GetPageViewsCollection(out bool changed) 
        {
            ReadOnlyCollection pageViews = null;

            //Save off the current value of our PageView changed flag so we can 
            //return it to indicate if the collection has actually changed.
            changed = _pageViewCollectionChanged; 
 
            //Reset the flag so that if this is called again before InvalidatePageViews is called
            //it'll reflect the unchanged-ness of the collection. 
            _pageViewCollectionChanged = false;

            if (_documentScrollInfo != null && _documentScrollInfo.PageViews != null)
            { 
                //Return the current collection.
                pageViews = _documentScrollInfo.PageViews; 
            } 
            else
            { 
                //Return an empty collection (null is not valid).
                pageViews = new ReadOnlyCollection(new List(0));
            }
 
            return pageViews;
        } 
 
        /// 
        /// Overrides the OnMouseLeftButtonDown method so that we can take focus when clicked. 
        /// 
        /// The MouseButtonEventArgs associated with this mouse event.
        protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
        { 
            base.OnMouseLeftButtonDown(e);
 
            // If no other controls in our Template have handled the event, we'll 
            // take focus here.
            if (!e.Handled) 
            {
                Focus();
                e.Handled = true;
            } 
        }
 
        ///  
        /// OnPreviewMouseWheel Zooms in/out on the document when the
        /// mouse wheel is scrolled and the Ctrl key is depressed. 
        /// 
        /// Event Arguments
        protected override void OnPreviewMouseWheel(MouseWheelEventArgs e)
        { 
            if (e.Handled)
            { 
                return; 
            }
 
            //Get the state of the Ctrl key -- if it's pressed, we'll Zoom.
            //Otherwise we do nothing and let others handle this event.
            if (Keyboard.IsKeyDown(Key.LeftCtrl) ||
                Keyboard.IsKeyDown(Key.RightCtrl)) 
            {
                e.Handled = true; 
 
                //Zoom based on the direction of the wheel.
                if (e.Delta < 0) 
                {
                    DecreaseZoom();
                }
                else 
                {
                    IncreaseZoom(); 
                } 
            }
        } 

        #endregion Protected Methods

        #region Internal Methods 
        /// 
        /// Called when our IDocumentScrollInfo has new layout information to share with us. 
        ///  
        internal void InvalidateDocumentScrollInfo()
        { 
            // We need to see if any IDocumentScrollInfo properties that DocumentViewer
            //   either exposes or makes use of have changed.  If so we invalidate properties
            //   or take actions here.
 
            // Any properties that are read only need to have the cache set and be invalidated
            // Settable DP's can be set directly (and should be, for validation) 
 
            //Set our internal change flag.
            //DP Invalidation callbacks can check for this flag to see if a change originated 
            //from our IDocumentScrollInfo object or not and take the appropriate action.
            //(Usually, if the IDSI caused the change to a DP, the invalidated callback won't need to
            //update the associated property on the IDSI.)
            _internalIDSIChange = true; 

            SetValue(ExtentWidthPropertyKey, _documentScrollInfo.ExtentWidth); 
            SetValue(ExtentHeightPropertyKey, _documentScrollInfo.ExtentHeight); 
            SetValue(ViewportWidthPropertyKey, _documentScrollInfo.ViewportWidth);
            SetValue(ViewportHeightPropertyKey, _documentScrollInfo.ViewportHeight); 

            if (HorizontalOffset != _documentScrollInfo.HorizontalOffset)
            {
                HorizontalOffset = _documentScrollInfo.HorizontalOffset; 
            }
 
            if (VerticalOffset != _documentScrollInfo.VerticalOffset) 
            {
                VerticalOffset = _documentScrollInfo.VerticalOffset; 
            }

            // IDSI is 0-indexed
            SetValue(MasterPageNumberPropertyKey, _documentScrollInfo.FirstVisiblePageNumber + 1); 

            // Convert IDocumentScrollInfo.Scale into 100-based percentage value for comparison. 
            double scrollZoom = ScaleToZoom(_documentScrollInfo.Scale); 
            if (Zoom != scrollZoom)
            { 
                Zoom = scrollZoom;
            }

            if (MaxPagesAcross != _documentScrollInfo.MaxPagesAcross) 
            {
                MaxPagesAcross = _documentScrollInfo.MaxPagesAcross; 
            } 

            //Reset our internal change flag. 
            _internalIDSIChange = false;
        }

        ///  
        /// Merely calls the base's InvalidatePageViews (which is protected).
        /// Used by our IDSI to keep the DPV collection in [....]. 
        ///  
        internal void InvalidatePageViewsInternal()
        { 
            //Our PageView collection has changed, set the flag.
            _pageViewCollectionChanged = true;
            InvalidatePageViews();
        } 

        ///  
        /// BringPointIntoView is called by the base if a selection goes outside of the bounds 
        /// of the current TextView.  If this happens it is necessary to scroll our content
        /// in an attempt to make that selection point visible, thus moving the scope of the TextView 
        /// and allowing selection to continue.
        /// 
        /// The point to be brought into view.
        /// Whether operation is pending or not. 
        internal bool BringPointIntoView(Point point)
        { 
            FrameworkElement grid = _documentScrollInfo as FrameworkElement; 

            if (grid != null) 
            {
                //Calculate the bounds of the DocumentGrid relative to the bounds of DocumentViewer
                Transform tr = this.TransformToDescendant(grid) as Transform;
                Rect gridRect = Rect.Transform(new Rect(grid.RenderSize), 
                                    tr.Value);
                double verticalOffset = VerticalOffset; 
                double horizontalOffset = HorizontalOffset; 

                //Scroll the point into view Vertically. 
                if (point.Y > gridRect.Y + gridRect.Height)
                {
                    verticalOffset += (point.Y - (gridRect.Y + gridRect.Height));
                } 
                else if (point.Y < gridRect.Y)
                { 
                    verticalOffset -= (gridRect.Y - point.Y); 
                }
 
                //Scroll the point into view Horizontally.
                if (point.X < gridRect.X)
                {
                    horizontalOffset -= (gridRect.X - point.X); 
                }
                else if (point.X > gridRect.X + gridRect.Width) 
                { 
                    horizontalOffset += (point.X - (gridRect.X + gridRect.Width));
                } 

                VerticalOffset = Math.Max(verticalOffset, 0.0);
                HorizontalOffset = Math.Max(horizontalOffset, 0.0);
            } 
            return false;
        } 
 
        #endregion Internal Methods
 
        #region Internal Properties

        /// 
        /// Internally exposes our TextEditor's Selection, for use 
        /// by Annotations code.
        ///  
        internal ITextSelection TextSelection 
        {
            get 
            {
                if (TextEditor != null)
                {
                    return TextEditor.Selection; 
                }
                else 
                { 
                    return null;
                } 
            }
        }

 
        /// 
        /// Internally exposes our IDocumentScrollInfo, for use 
        /// by Annotations code. 
        /// 
        internal IDocumentScrollInfo DocumentScrollInfo 
        {
            get
            {
                return _documentScrollInfo; 
            }
        } 
 
        /// 
        /// Internally exposes out ScrollViewer, for use in DocumentViewerAutomationPeer. 
        /// 
        internal ScrollViewer ScrollViewer
        {
            get 
            {
                return _scrollViewer; 
            } 
        }
 
        #endregion InternalProperties


 
        //-----------------------------------------------------
        // 
        //  Private Methods 
        //
        //------------------------------------------------------ 

        #region Private Methods

        #region Commands 
        /// 
        /// Set up our Command bindings 
        ///  
        /// 
        /// Set up our RoutedUICommand bindings 
        /// 
        ///
        /// Critical - creates a command binding.
        /// TAS - registering our own internal commands is considered safe. 
        ///
        [SecurityCritical , SecurityTreatAsSafe ] 
        private static void CreateCommandBindings() 
        {
            // Create our generic ExecutedRoutedEventHandler. 
            ExecutedRoutedEventHandler executeHandler = new ExecutedRoutedEventHandler(ExecutedRoutedEventHandler);

            // Create our generic QueryEnabledStatusHandler
            CanExecuteRoutedEventHandler queryEnabledHandler = new CanExecuteRoutedEventHandler(QueryEnabledHandler); 

            // 
            // Command: ViewThumbnails 
            //          Tells DocumentViewer to display thumbnails.
            _viewThumbnailsCommand = new RoutedUICommand(SR.Get(SRID.DocumentViewerViewThumbnailsCommandText), 
                "ViewThumbnailsCommand",
                typeof(DocumentViewer),
                null);
 
            CommandHelpers.RegisterCommandHandler( typeof(DocumentViewer),
                _viewThumbnailsCommand, 
                executeHandler, 
                queryEnabledHandler);
                //no key gesture 

            //
            // Command: FitToWidth
            //          Tells DocumentViewer to zoom to the document width. 
            _fitToWidthCommand = new RoutedUICommand(
                SR.Get(SRID.DocumentViewerViewFitToWidthCommandText), 
                "FitToWidthCommand", 
                typeof(DocumentViewer),
                null); 

            CommandHelpers.RegisterCommandHandler(typeof(DocumentViewer),
                _fitToWidthCommand,
                executeHandler, 
                queryEnabledHandler,
                new KeyGesture(Key.D2, ModifierKeys.Control)); 
 
            //
            // Command: FitToHeight 
            //          Tells DocumentViewer to zoom to the document height.
            _fitToHeightCommand = new RoutedUICommand(
                SR.Get(SRID.DocumentViewerViewFitToHeightCommandText),
                "FitToHeightCommand", 
                typeof(DocumentViewer),
                null); 
 
            CommandHelpers.RegisterCommandHandler(typeof(DocumentViewer),
                _fitToHeightCommand, 
                executeHandler,
                queryEnabledHandler);
                //no key gesture
 
            //
            // Command: MaxPagesAcross 
            //          Sets the MaxPagesAcross to the value provided. 
            _fitToMaxPagesAcrossCommand = new RoutedUICommand(
                SR.Get(SRID.DocumentViewerViewFitToMaxPagesAcrossCommandText), 
                "FitToMaxPagesAcrossCommand",
                typeof(DocumentViewer),
                null);
 
            CommandHelpers.RegisterCommandHandler(typeof(DocumentViewer),
                _fitToMaxPagesAcrossCommand, 
                executeHandler, 
                queryEnabledHandler);
                //no key gesture 

            #region Library Commands

            // Command: ApplicationCommands.Find - Ctrl+F 
            //          Invokes DocumentViewer's Find dialog.
            CommandHelpers.RegisterCommandHandler(typeof(DocumentViewer), 
                ApplicationCommands.Find, 
                executeHandler,
                queryEnabledHandler); 

            //
            // Command: ComponentCommands.ScrollPageUp - PageUp
            //          Causes DocumentViewer to scroll a Viewport up. 
            CommandHelpers.RegisterCommandHandler(typeof(DocumentViewer),
                ComponentCommands.ScrollPageUp, 
                executeHandler, 
                queryEnabledHandler,
                Key.PageUp); 

            //
            // Command: ComponentCommands.ScrollPageDown - PageDown
            //          Causes DocumentViewer to scroll a Viewport down. 
            CommandHelpers.RegisterCommandHandler(typeof(DocumentViewer),
                ComponentCommands.ScrollPageDown, 
                executeHandler, 
                queryEnabledHandler,
                Key.PageDown); 

            //
            // Command: ComponentCommands.ScrollPageLeft
            //          Causes DocumentViewer to scroll a Viewport to the left. 
            CommandHelpers.RegisterCommandHandler(typeof(DocumentViewer),
                ComponentCommands.ScrollPageLeft, 
                executeHandler, 
                queryEnabledHandler);
                //no key gesture 

            //
            // Command: ComponentCommands.ScrollPageRight
            //          Causes DocumentViewer to scroll a Viewport to the right. 
            CommandHelpers.RegisterCommandHandler(typeof(DocumentViewer),
                ComponentCommands.ScrollPageRight, 
                executeHandler, 
                queryEnabledHandler);
                //no key gesture 

            //
            // Command: ComponentCommands.MoveUp - Up
            //          Causes DocumentViewer to scroll the Viewport up by 16px. 
            CommandHelpers.RegisterCommandHandler(typeof(DocumentViewer),
                ComponentCommands.MoveUp, 
                executeHandler, 
                queryEnabledHandler,
                Key.Up); 

            //
            // Command: ComponentCommands.MoveDown - Down
            //          Causes DocumentViewer to scroll the Viewport down by 16px. 
            CommandHelpers.RegisterCommandHandler(typeof(DocumentViewer),
                ComponentCommands.MoveDown, 
                executeHandler, 
                queryEnabledHandler,
                Key.Down); 

            //
            // Command: ComponentCommands.MoveLeft - Left
            //          Causes DocumentViewer to scroll a Viewport left by 16px. 
            CommandHelpers.RegisterCommandHandler(typeof(DocumentViewer),
                ComponentCommands.MoveLeft, 
                executeHandler, 
                queryEnabledHandler,
                Key.Left); 

            //
            // Command: ComponentCommands.MoveRight - Right
            //          Causes DocumentViewer to scroll a Viewport right by 16px. 
            CommandHelpers.RegisterCommandHandler(typeof(DocumentViewer),
                ComponentCommands.MoveRight, 
                executeHandler, 
                queryEnabledHandler,
                Key.Right); 

            //
            // Command: NavigationCommands.Zoom
            //          Sets DocumentViewer's Zoom to the specified level. 
            CommandHelpers.RegisterCommandHandler(typeof(DocumentViewer),
                NavigationCommands.Zoom, 
                executeHandler, 
                queryEnabledHandler);
                //no key gesture 

            //
            // Command: NavigationCommands.IncreaseZoom
            //          Causes DocumentViewer to zoom in on the content. 
            CommandHelpers.RegisterCommandHandler(typeof(DocumentViewer),
                NavigationCommands.IncreaseZoom, 
                executeHandler, 
                queryEnabledHandler,
                // Ctrl+Numpad '+' 
                new KeyGesture(Key.Add, ModifierKeys.Control),
                // Ctrl+Numpad '+' (In case shift is held down)
                new KeyGesture(Key.Add, ModifierKeys.Shift | ModifierKeys.Control),
                // Ctrl+'+' 
                new KeyGesture(Key.OemPlus, ModifierKeys.Control),
                // Ctrl+'+' (In case shift is held down) 
                new KeyGesture(Key.OemPlus, ModifierKeys.Shift | ModifierKeys.Control)); 

            // 
            // Command: NavigationCommands.DecreaseZoom
            //          Causes DocumentViewer to zoom out of the content.
            CommandHelpers.RegisterCommandHandler(typeof(DocumentViewer),
                NavigationCommands.DecreaseZoom, 
                executeHandler,
                queryEnabledHandler, 
                // Ctrl+Numpad '-' 
                new KeyGesture(Key.Subtract, ModifierKeys.Control),
                // Ctrl+Numpad '-' (In case shift is held down) 
                new KeyGesture(Key.Subtract, ModifierKeys.Shift | ModifierKeys.Control),
                // Ctrl+'-'
                new KeyGesture(Key.OemMinus, ModifierKeys.Control),
                // Ctrl+'-' (In case shift is held down) 
                new KeyGesture(Key.OemMinus, ModifierKeys.Shift | ModifierKeys.Control));
 
            // Command: NavigationCommands.PreviousPage 
            CommandHelpers.RegisterCommandHandler(typeof(DocumentViewer),
                NavigationCommands.PreviousPage, 
                executeHandler,
                queryEnabledHandler,
                new KeyGesture(Key.PageUp, ModifierKeys.Control));
 
            // Command: NavigationCommands.NextPage
            CommandHelpers.RegisterCommandHandler(typeof(DocumentViewer), 
                NavigationCommands.NextPage, 
                executeHandler,
                queryEnabledHandler, 
                new KeyGesture(Key.PageDown, ModifierKeys.Control));

            // Command: NavigationCommands.FirstPage
            CommandHelpers.RegisterCommandHandler(typeof(DocumentViewer), 
                NavigationCommands.FirstPage,
                executeHandler, 
                queryEnabledHandler, 
                new KeyGesture(Key.Home, ModifierKeys.Control));
 
            // Command: NavigationCommands.FirstPage
            CommandHelpers.RegisterCommandHandler(typeof(DocumentViewer),
                NavigationCommands.LastPage,
                executeHandler, 
                queryEnabledHandler,
                new KeyGesture(Key.End, ModifierKeys.Control)); 
 
            #endregion Library Commands
 
            //Register input bindings for keyboard shortcuts that require
            //Command Parameters:

            //Zoom 100%: Requires a CommandParameter of 100.0 with the Zoom Command. 
            //Bound to Ctrl+1.
            InputBinding zoom100InputBinding = 
                new InputBinding(NavigationCommands.Zoom, 
                new KeyGesture(Key.D1, ModifierKeys.Control));
            zoom100InputBinding.CommandParameter = 100.0; 

            CommandManager.RegisterClassInputBinding(typeof(DocumentViewer),
                zoom100InputBinding);
 
            //Whole Page: Requires a CommandParameter of 1 with the FitToMaxPagesAcross Command.
            //Bound to Ctrl+3. 
            InputBinding wholePageInputBinding = 
                            new InputBinding(DocumentViewer.FitToMaxPagesAcrossCommand,
                            new KeyGesture(Key.D3, ModifierKeys.Control)); 
            wholePageInputBinding.CommandParameter = 1;

            CommandManager.RegisterClassInputBinding(typeof(DocumentViewer),
                wholePageInputBinding); 

            //Two Pages: Requires a CommandParameter of 2 with the FitToMaxPagesAcross Command. 
            //Bound to Ctrl+4. 
            InputBinding twoPagesInputBinding =
                            new InputBinding(DocumentViewer.FitToMaxPagesAcrossCommand, 
                            new KeyGesture(Key.D4, ModifierKeys.Control));
            twoPagesInputBinding.CommandParameter = 2;

            CommandManager.RegisterClassInputBinding(typeof(DocumentViewer), 
                twoPagesInputBinding);
 
 
        }
 
        /// 
        /// Central handler for QueryEnabled events fired by Commands directed at DocumentViewer.
        /// 
        /// Critical - Sets the critical Handled property on the RoutedEventArgs 
        /// TreatAsSafe - We are marking the event as handled only for the Commands that
        ///               DocumentViewer explicitly handles -- this cannot be used for spoofing. 
        ///  
        /// 
        /// The target of this Command, expected to be DocumentViewer 
        /// The event arguments for this event.
        [SecurityCritical, SecurityTreatAsSafe]
        private static void QueryEnabledHandler(object target, CanExecuteRoutedEventArgs args)
        { 
            DocumentViewer dv = target as DocumentViewer;
            Invariant.Assert(dv != null, "Target of QueryEnabledEvent must be DocumentViewer."); 
            Invariant.Assert(args != null, "args cannot be null."); 

            // If the target is not a DocumentViewer we silently return (but note that 
            // we have Asserted this above.)
            if (dv == null)
            {
                return; 
            }
 
            // Mark this event as handled so that the CanExecute handler on the base 
            // doesn't override our settings.
            args.Handled = true; 

            // Now we set the IsEnabled flag based on the Command that fired this event
            // and the current state of DocumentViewer.
            if (args.Command == ViewThumbnailsCommand || 
                args.Command == FitToWidthCommand ||
                args.Command == FitToHeightCommand || 
                args.Command == FitToMaxPagesAcrossCommand || 
                args.Command == NavigationCommands.Zoom)
            { 
                // Fit and Zoom operations are always enabled.
                args.CanExecute = true;
            }
            else if (args.Command == ApplicationCommands.Find) 
            {
                //Find can only operate if we have a TextEditor. 
                args.CanExecute = dv.TextEditor != null; 
            }
            else if (args.Command == ComponentCommands.ScrollPageUp || 
                args.Command == ComponentCommands.MoveUp)
            {
                // Enabling the Move/Scroll Up Commands is tied to the
                // state of the CanMoveUp property. 
                args.CanExecute = dv.CanMoveUp;
            } 
            else if (args.Command == ComponentCommands.ScrollPageDown || 
                args.Command == ComponentCommands.MoveDown)
            { 
                // Enabling the Move/Scroll Down Commands is tied to the
                // state of the CanMoveDown property.
                args.CanExecute = dv.CanMoveDown;
            } 
            else if (args.Command == ComponentCommands.ScrollPageLeft ||
                args.Command == ComponentCommands.MoveLeft) 
            { 
                // Enabling the Move/Scroll Left Commands is tied to the
                // state of the CanMoveLeft property. 
                args.CanExecute = dv.CanMoveLeft;
            }
            else if (args.Command == ComponentCommands.ScrollPageRight ||
                args.Command == ComponentCommands.MoveRight) 
            {
                // Enabling the Move/Scroll Right Commands is tied to the 
                // state of the CanMoveRight property. 
                args.CanExecute = dv.CanMoveRight;
            } 
            else if (args.Command == NavigationCommands.IncreaseZoom)
            {
                // Zooming in is only allowed if DocumentViewer has a valid Document assigned
                // and can increase zoom. 
                args.CanExecute = dv.CanIncreaseZoom;
            } 
            else if (args.Command == NavigationCommands.DecreaseZoom) 
            {
                // Zooming out is only allowed if DocumentViewer has a valid Document assigned 
                // and can decrease zoom.
                args.CanExecute = dv.CanDecreaseZoom;
            }
            else if (args.Command == NavigationCommands.PreviousPage 
                || args.Command == NavigationCommands.FirstPage)
            { 
                // Enabling the PreviousPage and FirstPage Commands is tied 
                // to the state of the CanGoToPreviousPage property.
                args.CanExecute = dv.CanGoToPreviousPage; 
            }
            else if (args.Command == NavigationCommands.NextPage
                || args.Command == NavigationCommands.LastPage)
            { 
                // Enabling the NextPage and LastPage Commands is tied
                // to the state of the CanGoToNextPage property. 
                args.CanExecute = dv.CanGoToNextPage; 
            }
            else if (args.Command == NavigationCommands.GoToPage) 
            {
                // This command is always enabled as long as there is a document loaded.
                args.CanExecute = (dv.Document != null);
            } 
            else
            { 
                args.Handled = false; 
                // If we get here then we missed a Command above.
                // We assert to indicate the failure. 
                Invariant.Assert(false, "Command not handled in QueryEnabledHandler.");
            }

        } 

        ///  
        /// Central handler for all ExecuteEvents fired by Commands directed at DocumentViewer. 
        /// 
        /// The target of this Command, expected to be DocumentViewer. 
        /// The event arguments associated with this event.
        private static void ExecutedRoutedEventHandler(object target, ExecutedRoutedEventArgs args)
        {
            DocumentViewer dv = target as DocumentViewer; 
            Invariant.Assert(dv != null, "Target of ExecuteEvent must be DocumentViewer.");
            Invariant.Assert(args != null, "args cannot be null."); 
 
            // If the target is not a DocumentViewer we silently return (but note that
            // we have Asserted this above.) 
            if (dv == null)
            {
                return;
            } 

            // Now we execute the method corresponding to the Command that fired this event; 
            // each Command has its own protected virtual method that performs the operation 
            // corresponding to the Command.
            if (args.Command == ViewThumbnailsCommand) 
            {
                dv.OnViewThumbnailsCommand();
            }
            else if (args.Command == FitToWidthCommand) 
            {
                dv.OnFitToWidthCommand(); 
            } 
            else if (args.Command == FitToHeightCommand)
            { 
                dv.OnFitToHeightCommand();
            }
            else if (args.Command == FitToMaxPagesAcrossCommand)
            { 
                DoFitToMaxPagesAcross(dv, args.Parameter);
            } 
            else if (args.Command == ApplicationCommands.Find) 
            {
                dv.OnFindCommand(); 
            }
            else if (args.Command == ComponentCommands.ScrollPageUp)
            {
                dv.OnScrollPageUpCommand(); 
            }
            else if (args.Command == ComponentCommands.ScrollPageDown) 
            { 
                dv.OnScrollPageDownCommand();
            } 
            else if (args.Command == ComponentCommands.ScrollPageLeft)
            {
                dv.OnScrollPageLeftCommand();
            } 
            else if (args.Command == ComponentCommands.ScrollPageRight)
            { 
                dv.OnScrollPageRightCommand(); 
            }
            else if (args.Command == ComponentCommands.MoveUp) 
            {
                dv.OnMoveUpCommand();
            }
            else if (args.Command == ComponentCommands.MoveDown) 
            {
                dv.OnMoveDownCommand(); 
            } 
            else if (args.Command == ComponentCommands.MoveLeft)
            { 
                dv.OnMoveLeftCommand();
            }
            else if (args.Command == ComponentCommands.MoveRight)
            { 
                dv.OnMoveRightCommand();
            } 
            else if (args.Command == NavigationCommands.Zoom) 
            {
                DoZoom(dv, args.Parameter); 
            }
            else if (args.Command == NavigationCommands.DecreaseZoom)
            {
                dv.DecreaseZoom(); 
            }
            else if (args.Command == NavigationCommands.IncreaseZoom) 
            { 
                dv.IncreaseZoom();
            } 
            else if (args.Command == NavigationCommands.PreviousPage)
            {
                dv.PreviousPage();
            } 
            else if (args.Command == NavigationCommands.NextPage)
            { 
                dv.NextPage(); 
            }
            else if (args.Command == NavigationCommands.FirstPage) 
            {
                dv.FirstPage();
            }
            else if (args.Command == NavigationCommands.LastPage) 
            {
                dv.LastPage(); 
            } 
            else
            { 
                Invariant.Assert(false, "Command not handled in ExecutedRoutedEventHandler.");
            }
        }
 
        /// 
        /// Helper for the FitToMaxPagesAcross Command, called from ExecutedRoutedEventHandler. 
        /// Verifies that the data passed into ExecutedRoutedEventHandler is valid for a column count 
        /// and sets the MaxPagesAcross property appropriately.
        ///  
        /// the DocumentViewer that received the command
        /// the data associated with this command
        private static void DoFitToMaxPagesAcross(DocumentViewer dv, object data)
        { 
            // Check that args is valid
            if (data != null) 
            { 
                int columnValue = 0;
                bool isValidArg = true; 

                // If data is an int, then cast
                if (data is int)
                { 
                    columnValue = (int)data;
                } 
                // If args.Data is a string, then parse 
                else if (data is string)
                { 
                    try
                    {
                        columnValue = System.Convert.ToInt32((string)data, CultureInfo.CurrentCulture);
                    } 
                    // Catch only the expected parse exceptions
                    catch (ArgumentNullException) 
                    { 
                        isValidArg = false;
                    } 
                    catch (FormatException)
                    {
                        isValidArg = false;
                    } 
                    catch (OverflowException)
                    { 
                        isValidArg = false; 
                    }
                } 

                // Argument wasn't a valid int, throw an exception.
                if (!isValidArg)
                { 
                    throw new ArgumentException(SR.Get(SRID.DocumentViewerArgumentMustBeInteger), "data");
                } 
 
                dv.OnFitToMaxPagesAcrossCommand(columnValue);
 
            }
            else
            {
                throw new ArgumentNullException("data"); 
            }
        } 
 
        /// 
        /// Helper for the Zoom Command, called from ExecutedRoutedEventHandler. 
        /// Verifies that the data passed into ExecutedRoutedEventHandler is valid for a zoom factor
        /// and sets the Zoom property appropriately.
        /// 
        /// The DocumentViewer that recieved the command 
        /// the data associated with this command
        private static void DoZoom(DocumentViewer dv, object data) 
        { 
            // Check that args is valid
            if (data != null) 
            {
                // If a ZoomConverter doesn't exist, create one.
                if (dv._zoomPercentageConverter == null)
                { 
                    dv._zoomPercentageConverter = new ZoomPercentageConverter();
                } 
 
                // Use ZoomConverter to convert argument to zoom value.
                // We use InvariantCulture because the Command arguments are typically 
                // defined in XAML or code, which is culture invariant.
                object zoomValue = dv._zoomPercentageConverter.ConvertBack(data, typeof(double),
                    null, CultureInfo.InvariantCulture);
 
                // Argument wasn't a valid percent, throw an exception.
                if (zoomValue == DependencyProperty.UnsetValue) 
                { 
                    throw new ArgumentException(SR.Get(SRID.DocumentViewerArgumentMustBePercentage), "data");
                } 
                dv.Zoom = (double)zoomValue;
            }
            else
            { 
                throw new ArgumentNullException("data");
            } 
        } 

        #endregion Commands 

        /// 
        /// Register our properties' metadata so that our DependencyProperties function.
        ///  
        private static void RegisterMetadata()
        { 
            DefaultStyleKeyProperty.OverrideMetadata(typeof(DocumentViewer), new FrameworkPropertyMetadata(typeof(DocumentViewer))); 
            _dType = DependencyObjectType.FromSystemTypeInternal(typeof(DocumentViewer));
        } 

        /// 
        /// Initializes our DocumentScrollInfo.
        ///  
        private void SetUp()
        { 
            // Enable selection. 
            IsSelectionEnabled = true;
 
            // Set the TextBox.AcceptsReturn flag -- this will disable the "select everything on focus"
            // behavior of the TextEditor.
            // We reset the TextBox.AcceptsTab property to keep the TextEditor from eating Tab.
            SetValue(TextBox.AcceptsTabProperty, false); 

            // Construct the DocumentGrid. 
            CreateIDocumentScrollInfo(); 
        }
 
        /// 
        /// CreateIDocumentScrollInfo instantiates our IDocumentScrollInfo control
        /// and sets/resets default properties.
        ///  
        private void CreateIDocumentScrollInfo()
        { 
            if (_documentScrollInfo == null) 
            {
                // Construct IDocumentScrollInfo (DocumentGrid). 
                _documentScrollInfo = new DocumentGrid();
                _documentScrollInfo.DocumentViewerOwner = this;

                //If IDocumentScrollInfo is a FrameworkElement we can give it a 
                //Name for automation.
                FrameworkElement fe = _documentScrollInfo as FrameworkElement; 
                if (fe != null) 
                {
                    fe.Name = "DocumentGrid"; 
                    fe.Focusable = false;

                    //We don't allow Tabbing to the IDocumentScrollInfo --
                    //The ScrollViewer parent is what is tabbed to. 
                    fe.SetValue(KeyboardNavigation.IsTabStopProperty, false);
 
                    TextEditorRenderScope = fe; 
                }
            } 

            //Assign our content to the IDSI.
            AttachContent();
 
            //Give the IDocumentScrollInfo object default values for important properties.
            _documentScrollInfo.VerticalPageSpacing = VerticalPageSpacing; 
            _documentScrollInfo.HorizontalPageSpacing = HorizontalPageSpacing; 
        }
 
        /// 
        /// Assigns our current Document to our IDSI and gives it a reference to our TextEditor.
        /// 
        private void AttachContent() 
        {
            _documentScrollInfo.Content = (Document != null) ? Document.DocumentPaginator as DynamicDocumentPaginator : null; 
            IsSelectionEnabled = true; 
        }
 
        /// 
        /// FindContentHost does 2 things:
        ///  - It finds "marked" elements (elements with ContentHost attached properties)
        ///    in the current Visual Tree. 
        ///  - It takes these elements and populates them with the proper UI (for Content)
        ///  
        /// There must be a ScrollViewer in 
        /// DocumentViewer's visual tree which has the Name PART_ContentHost.
        private void FindContentHost() 
        {
            // Find the "special" element in the tree marked as the
            //   ContentHost.  This element must exist or we throw.
            ScrollViewer contentHost = this.Template.FindName(_contentHostName, this) as ScrollViewer; 

            // Make sure contentHost exists.  This wouldn't be much of a DocumentViewer if it didn't, 
            //   since we need someplace to throw our IDocumentScrollInfo so we can display documents. 
            // Throw an exception if it doesn't exist.
            if (contentHost == null) 
            {
                throw new NotSupportedException(SR.Get(SRID.DocumentViewerStyleMustIncludeContentHost));
            }
 
            _scrollViewer = contentHost;
            _scrollViewer.Focusable = false; 
 
            Invariant.Assert(_documentScrollInfo != null, "IDocumentScrollInfo cannot be null.");
            //Make the IDSI the child of the ScrollViewer. 
            _scrollViewer.Content = _documentScrollInfo;
            _scrollViewer.ScrollInfo = _documentScrollInfo;

            // Set IDocumentScrollInfo's content if its content is invalid. 
            if (_documentScrollInfo.Content != Document)
            { 
                AttachContent(); 
            }
        } 

        #region Find

        ///  
        /// Instantiates the Find Toolbar and adds it to our Visual tree where appropriate.
        ///  
        ///  
        /// Critical: FindToolBar..ctor is defined in a non-APTCA assembly.
        /// TreatAsSafe: call to FindToolBar..ctor does not entail any risk. 
        /// 
        [SecurityCritical, SecurityTreatAsSafe]
        private void InstantiateFindToolBar()
        { 
            //First, find the correct place to insert toolbar.
 
            // Location is defined by named element, FindToolbarHost. 
            ContentControl findHost = this.Template.FindName(_findToolBarHostName, this) as ContentControl;
 
            // Only create and hook up the toolbar, if we found a place to put it.
            if (findHost != null)
            {
               if( _findToolbar == null ) 
               {
                    // create the new object 
                    _findToolbar = new FindToolBar(); 

                    // add the event handlers 
                    _findToolbar.FindClicked += new EventHandler(OnFindInvoked);

                    //set initial DocumentLoaded state.
                    _findToolbar.DocumentLoaded = (Document != null) ? true : false; 
                }
 
                // Now insert the toolbar, if it isn't already parented elsewhere. 
                // (It will have been disconnected from DocumentViewer on a Theme or
                // Template change.) 
                if (!_findToolbar.IsAncestorOf(this))
                {
                    ((IAddChild)findHost).AddChild(_findToolbar);
                } 
            }
        } 
 
        /// 
        /// Invoked when the "Find" button in the Find Toolbar is clicked. 
        /// This method invokes the actual Find process.
        /// 
        /// The object that sent this event
        /// The Click Events associated with this event 
        /// 
        /// Critical: get_SearchUp is defined in a non-APTCA assembly. 
        /// TreatAsSafe: call to get_SearchUp does not entail any risk. 
        /// 
        [SecurityCritical, SecurityTreatAsSafe] 
        private void OnFindInvoked(object sender, EventArgs e)
        {
            EventTrace.EasyTraceEvent(EventTrace.Keyword.KeywordXPS, EventTrace.Event.WClientDRXFindBegin);
            try 
            {
                if (_findToolbar != null && TextEditor != null) 
                { 
                    ITextRange findResult = Find(_findToolbar);
 
                    // If we found something, select it.
                    if ((findResult != null) && (!findResult.IsEmpty))
                    {
                        //Give ourselves focus, this ensures that the selection 
                        //will be made visible after it's made.
                        this.Focus(); 
 
                        if (_documentScrollInfo != null)
                        { 
                            _documentScrollInfo.MakeSelectionVisible();
                        }

                        //Put the focus back on the Find Toolbar's TextBox to search again. 
                        _findToolbar.GoToTextBox();
                    } 
                    else 
                    {
                        // No, we did not find anything.  Alert the user. 

                        // build our message string.
                        string messageString = _findToolbar.SearchUp ?
                            SR.Get(SRID.DocumentViewerSearchUpCompleteLabel) : 
                            SR.Get(SRID.DocumentViewerSearchDownCompleteLabel);
 
                        messageString = String.Format( 
                            CultureInfo.CurrentCulture,
                            messageString, 
                            _findToolbar.SearchText);

                        Window wnd = null;
                        if (Application.Current != null && Application.Current.CheckAccess()) 
                        {
                            wnd = Application.Current.MainWindow; 
                        } 

                        MS.Internal.PresentationFramework.SecurityHelper.ShowMessageBoxHelper( 
                            wnd,
                            messageString,
                            SR.Get(SRID.DocumentViewerSearchCompleteTitle),
                            MessageBoxButton.OK, 
                            MessageBoxImage.Asterisk);
                    } 
                } 
            }
            finally 
            {
                EventTrace.EasyTraceEvent(EventTrace.Keyword.KeywordXPS, EventTrace.Event.WClientDRXFindEnd);
            }
        } 

        ///  
        /// This is just a private convenience method for handling the Find command in a 
        /// localized place.
        ///  
        /// 
        /// Critical: GoToTextBox is defined in a non-APTCA assembly.
        /// TreatAsSafe: call to GoToTextBox does not entail any risk.
        ///  
        [SecurityCritical, SecurityTreatAsSafe]
        private void GoToFind() 
        { 
            if (_findToolbar != null)
            { 
                _findToolbar.GoToTextBox();
            }
        }
 

        ///  
        /// This is just a private convenience method to handle those keyboard 
        /// shortcuts related to the Find Command.
        /// localized place. 
        /// 
        /// 
        /// Critical: get_SearchUp is defined in a non-APTCA assembly.
        /// TreatAsSafe: call to get_SearchUp does not entail any risk. 
        /// 
        [SecurityCritical, SecurityTreatAsSafe] 
        private KeyEventArgs ProcessFindKeys(KeyEventArgs e) 
        {
            if (_findToolbar == null || Document == null) 
            {
                // Short-circuit. Find isn't enabled,
                // just exit.
                return e; 
            }
 
            // F3 -- Invoke Find 
            if (e.Key == Key.F3)
            { 
                e.Handled = true;

                //If the Shift key is also pressed, then search up.
                _findToolbar.SearchUp = ((e.KeyboardDevice.Modifiers & ModifierKeys.Shift) == ModifierKeys.Shift); 

                OnFindInvoked(this, EventArgs.Empty); 
            } 

            return e; 
        }

        #endregion Find
 
        /// 
        /// Find the location in the zoomLevelCollection such that it is the closest 
        ///  zoomLevel equal to or lower than the current zoom. 
        /// 
        private void FindZoomLevelIndex() 
        {
            // Ensure the list of zoom levels is created.
            if (_zoomLevelCollection != null)
            { 

                // If the index is not in a valid location, update it to the list start. 
                if ((_zoomLevelIndex < 0) || (_zoomLevelIndex >= _zoomLevelCollection.Length)) 
                {
                    _zoomLevelIndex = 0; 
                    _zoomLevelIndexValid = false;
                }

                // Check if the current index is in the correct location in the list. 
                if (!_zoomLevelIndexValid)
                { 
                    // Since the index is not in the correct location in the list 
                    //  (ie the Zoom was set by another means), then
                    //   search the list of possible zooms for the correct location. 
                    double currentZoom = Zoom;

                    // Currently this search is done using a linear method which is
                    // fine given the small size of the list.  If we increase the list 
                    // size, then a simple binary search could increaes performance.
 
                    // Search the list of zoom's from highest to lowest until the 
                    //   appropriate "floor" level (level equal to, or
                    //   lower than the current zoom) is found. 
                    int loopIndex;
                    for (loopIndex = 0; loopIndex < _zoomLevelCollection.Length - 1; loopIndex++)
                    {
                        if (currentZoom >= _zoomLevelCollection[loopIndex]) 
                        {
                            // Closest equal or lower match found 
                            break; 
                        }
                    } 
                    // Assign the current zoom level, and mark that our index is valid
                    //   (for future Increase / Decrease zoom calls).
                    _zoomLevelIndex = loopIndex;
                    _zoomLevelIndexValid = true; 
                }
            } 
        } 

        ///  
        /// Determines if the parameter represents a valid double (that is a value other
        /// than NaN, PositiveInfinity, or NegativeInfinity).
        /// 
        /// The double value to be checked 
        /// True if the double value is valid, false otherwise.
        private static bool DoubleValue_Validate(object value) 
        { 

            // 


            bool ok;
 
            // Ensure value is double
            if (value is double) 
            { 
                double checkValue = (double)value;
 
                // Check if double is within an assumed range
                if ((double.IsNaN(checkValue)) ||
                    (double.IsInfinity(checkValue)))
                { 
                    ok = false;
                } 
                else 
                {
                    ok = true; 
                }
            }
            else
            { 
                ok = false;
            } 
            return ok; 
        }
 
        /// 
        /// Converts an IDocumentScrollInfo's Scale value to a Zoom
        /// 
        /// A valid IDocumentScrollInfo.Scale value. 
        /// A Zoom value
        private static double ScaleToZoom(double scale) 
        { 
            return scale * 100.0;
        } 

        /// 
        /// Converts a Zoom value to an IDocumentScrollInfo.Scale value.
        ///  
        /// A valid Zoom value.
        /// An IDocumentScrollInfo.Scale value. 
        private static double ZoomToScale(double zoom) 
        {
            return zoom / 100.0; 
        }

        #region DependencyProperties
 
        #region HorizontalOffset
        ///  
        /// Validate the value passed in as a possible offset (either vertical or horizontal) 
        /// 
        /// A double representing the requested offset 
        /// True if the offset is valid, false otherwise.
        private static bool ValidateOffset(object value)
        {
            return DoubleValue_Validate(value) && ((double)value >= 0.0); 
        }
 
        ///  
        /// The HorizontalOffset has changed, and needs to be updated.
        ///  
        private static void OnHorizontalOffsetChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            DocumentViewer dv = (DocumentViewer)d;
            double newOffset = (double) e.NewValue; 

            // If the HorizontalOffset has changed and it isn't due to a change that originated 
            // from our IDocumentScrollInfo object, then set the new offset value on the IDocumentScrollInfo. 
            if (!dv._internalIDSIChange && (dv._documentScrollInfo != null))
            { 
                dv._documentScrollInfo.SetHorizontalOffset(newOffset);
            }
            dv.SetValue(CanMoveLeftPropertyKey, newOffset > 0.0);
            dv.SetValue(CanMoveRightPropertyKey, newOffset < (dv.ExtentWidth - dv.ViewportWidth)); 
        }
        #endregion HorizontalOffset 
 
        #region VerticalOffset
        ///  
        /// The VerticalOffset has changed, and needs to be updated.
        /// 
        private static void OnVerticalOffsetChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        { 
            DocumentViewer dv = (DocumentViewer)d;
            double newOffset = (double) e.NewValue; 
 
            // If the VerticalOffset has changed and it isn't due to a change that originated
            // from our IDocumentScrollInfo object, then set the new offset value on the IDocumentScrollInfo. 
            if ( !dv._internalIDSIChange && (dv._documentScrollInfo != null))
            {
                dv._documentScrollInfo.SetVerticalOffset(newOffset);
            } 
            dv.SetValue(CanMoveUpPropertyKey, newOffset > 0.0);
            dv.SetValue(CanMoveDownPropertyKey, newOffset < (dv.ExtentHeight - dv.ViewportHeight)); 
        } 
        #endregion VerticalOffset
 
        #region ExtentWidth
        private static void OnExtentWidthChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            DocumentViewer dv = (DocumentViewer)d; 
            dv.SetValue(CanMoveRightPropertyKey, dv.HorizontalOffset < ((double) e.NewValue - dv.ViewportWidth));
        } 
        #endregion ExtentWidth 

        #region ExtentHeight 
        private static void OnExtentHeightChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            DocumentViewer dv = (DocumentViewer)d;
            dv.SetValue(CanMoveDownPropertyKey, dv.VerticalOffset < ((double) e.NewValue - dv.ViewportHeight)); 
        }
        #endregion ExtentHeight 
 
        #region ViewportWidth
        private static void OnViewportWidthChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
        {
            DocumentViewer dv = (DocumentViewer)d;
            double newWidth = (double) e.NewValue;
            dv.SetValue(CanMoveRightPropertyKey, dv.HorizontalOffset < (dv.ExtentWidth - (double) e.NewValue)); 
        }
        #endregion ViewportWidth 
 
        #region ViewportHeight
        private static void OnViewportHeightChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
        {
            DocumentViewer dv = (DocumentViewer)d;
            double newHeight = (double) e.NewValue;
            dv.SetValue(CanMoveDownPropertyKey, dv.VerticalOffset < (dv.ExtentHeight - newHeight)); 
        }
        #endregion ViewportHeight 
 
        #region ShowPageBorders
        ///  
        /// ShowPageBorders has changed, and needs to be updated.
        /// 
        private static void OnShowPageBordersChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        { 
            DocumentViewer dv = (DocumentViewer) d;
 
            // If the ShowPageBorders has changed, then set the new value on the IDocumentScrollInfo. 
            if (dv._documentScrollInfo != null)
            { 
                dv._documentScrollInfo.ShowPageBorders = (bool) e.NewValue;
            }
        }
        #endregion ShowPageBorders 

        #region Zoom 
        private static object CoerceZoom(DependencyObject d, object value) 
        {
            double checkValue = (double) value; 
            if (checkValue < DocumentViewerConstants.MinimumZoom)
            {
                return DocumentViewerConstants.MinimumZoom;
            } 

            if (checkValue > DocumentViewerConstants.MaximumZoom) 
            { 
                return DocumentViewerConstants.MaximumZoom;
            } 

            return value;
        }
 
        /// 
        /// The Zoom has changed, and needs to be updated. 
        ///  
        private static void OnZoomChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        { 
            DocumentViewer dv = (DocumentViewer)d;

            // If the ZoomPercentage has changed, then update the IDocumentScrollInfo.
            if (dv._documentScrollInfo != null) 
            {
                double newZoom = (double) e.NewValue; 
                if (!dv._internalIDSIChange) 
                {
                    //Perf Tracing - Mark Zoom Change Start 
                    EventTrace.EasyTraceEvent(EventTrace.Keyword.KeywordXPS, EventTrace.Event.WClientDRXZoom, (int)newZoom);

                    // Set the new zoom scale on IDocumentScrollInfo
                    dv._documentScrollInfo.SetScale(DocumentViewer.ZoomToScale(newZoom)); 
                }
 
                dv.SetValue(CanIncreaseZoomPropertyKey, newZoom < DocumentViewerConstants.MaximumZoom); 
                dv.SetValue(CanDecreaseZoomPropertyKey, newZoom > DocumentViewerConstants.MinimumZoom);
 
                // If the zoom was not set by Increase / DecreaseZoom commands,
                //    then invalidate the zoom level index.
                if (!dv._updatingInternalZoomLevel)
                { 
                    dv._zoomLevelIndexValid = false;
                } 
            } 
        }
        #endregion ZoomPercentage 

        #region MaxPagesAcross

        ///  
        /// Validate the value passed in as a possible MaxPagesAcross
        ///  
        /// An int MaxPagesAcross value 
        /// True if the value is valid, false otherwise.
        private static bool ValidateMaxPagesAcross(object value) 
        {
            int checkValue = (int)value;

            return checkValue > 0 && checkValue <= DocumentViewerConstants.MaximumMaxPagesAcross; 
        }
 
        ///  
        /// The MaxPagesAcross has changed, and needs to be updated.
        ///  
        private static void OnMaxPagesAcrossChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            DocumentViewer dv = (DocumentViewer)d;
 
            //regardless of whether the value of MaxPagesAcross has actually changed.
            //Setting this property will cause content to reflow or rescale to fit and we 
            //want this to happen even if the same number of columns will be visible. 
            //As an example, if we're at 500% showing 1 page, setting MaxPagesAcross to 1 will
            //cause the Zoom to change to show precisely one column. 
            if (!dv._internalIDSIChange)
            {
                dv._documentScrollInfo.SetColumns((int) e.NewValue);
            } 

        } 
        #endregion GridColumnCount 

        #region VerticalPageSpacing 
        /// 
        /// Validate the value passed in as a possible PageSpacing, either vertical or horizontal
        /// 
        /// A value representing the requested page spacing 
        /// True if the offset is valid, false otherwise.
        private static bool ValidatePageSpacing(object value) 
        { 
            return DoubleValue_Validate(value) && ((double)value >= 0.0);
        } 

        /// 
        /// The VerticalPageSpacing has changed, and needs to be updated.
        ///  
        private static void OnVerticalPageSpacingChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        { 
            DocumentViewer dv = (DocumentViewer)d; 

            // If the VerticalPageSpacing has changed, then set the new value on IDocumentScrollInfo. 
            if (dv._documentScrollInfo != null)
            {
                dv._documentScrollInfo.VerticalPageSpacing = (double) e.NewValue;
            } 
        }
        #endregion VerticalPageSpacing 
 
        #region HorizontalPageSpacing
        ///  
        /// The HorizontalPageSpacing has changed, and needs to be updated.
        /// 
        private static void OnHorizontalPageSpacingChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        { 
            DocumentViewer dv = (DocumentViewer)d;
 
            // If the HorizontalPageSpacing has changed, then set the new value on IDocumentScrollInfo. 
            if (dv._documentScrollInfo != null)
            { 
                dv._documentScrollInfo.HorizontalPageSpacing = (double) e.NewValue;
            }
        }
        #endregion HorizontalPageSpacing 

        #endregion Dependency Properties 
 
        #endregion Private Methods
 
        //------------------------------------------------------
        //
        //  Private Fields
        // 
        //-----------------------------------------------------
        #region Private Fields 
 
        // UI Elements
        private IDocumentScrollInfo             _documentScrollInfo; 
        private ScrollViewer                    _scrollViewer;
        private ZoomPercentageConverter         _zoomPercentageConverter;

        //Find ToolBar 
        private FindToolBar _findToolbar;                           // The FindToolbar UI
 
        // Default values for DPs 
        private const double                    _horizontalOffsetDefault = 0.0;
        private const double                    _verticalOffsetDefault = 0.0; 
        private const double                    _extentWidthDefault = 0.0;
        private const double                    _extentHeightDefault = 0.0;
        private const double                    _viewportWidthDefault = 0.0;
        private const double                    _viewportHeightDefault = 0.0; 
        private const bool                      _showPageBordersDefault = true;
        private const double                    _zoomPercentageDefault = 100.0; 
        private const int                       _maxPagesAcrossDefault = 1; 
        private const double                    _verticalPageSpacingDefault = 10.0;
        private const double                    _horizontalPageSpacingDefault = 10.0; 
        private const bool                      _canMoveUpDefault = false;
        private const bool                      _canMoveDownDefault = false;
        private const bool                      _canMoveLeftDefault = false;
        private const bool                      _canMoveRightDefault = false; 
        private const bool                      _canIncreaseZoomDefault = true;
        private const bool                      _canDecreaseZoomDefault = true; 
 //       private const bool                      _isToolbarMaximizedDefault = true; 

        // Our Commands, instantiated on a pay-for-play basis 
        private static RoutedUICommand            _viewThumbnailsCommand;
        private static RoutedUICommand            _fitToWidthCommand;
        private static RoutedUICommand            _fitToHeightCommand;
        private static RoutedUICommand            _fitToMaxPagesAcrossCommand; 

        // This list is assumed to be in decreasing order. 
        private static double[] _zoomLevelCollection = {5000.0, 4000.0, 3200.0, 2400.0, 2000.0, 1600.0, 
                                                       1200.0, 800.0, 400.0, 300.0, 200.0, 175.0, 150.0,
                                                       125.0, 100.0, 75.0, 66.0, 50.0, 33.0, 25.0, 10.0, 5.0}; 
        private int                             _zoomLevelIndex; // = 0
        private bool                            _zoomLevelIndexValid; // = false
        private bool                            _updatingInternalZoomLevel; // = false
        private bool                            _internalIDSIChange; // = false 
        private bool                            _pageViewCollectionChanged; // = false
        private bool                            _firstDocumentAssignment = true; 
 
        private const string                    _findToolBarHostName  = "PART_FindToolBarHost";
        private const string                    _contentHostName = "PART_ContentHost"; 

        #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