DocumentViewerBase.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Dotnetfx_Win7_3.5.1 / Dotnetfx_Win7_3.5.1 / 3.5.1 / DEVDIV / depot / DevDiv / releases / Orcas / NetFXw7 / wpf / src / Framework / System / Windows / Controls / Primitives / DocumentViewerBase.cs / 1 / DocumentViewerBase.cs

                            //---------------------------------------------------------------------------- 
//
// Copyright (C) Microsoft Corporation.  All rights reserved.
//
// File: DocumentViewerBase.cs 
//
// Description: DocumentViewerBase is a minimal base class, providing only 
//              the functionality common across document viewing scenarios. 
//              The base class provides no user interface, very few properties,
//              and minimal policy. Functionality included in the base class: 
//              BringIntoView support & Print API services
//              and Annotation support.
//
//--------------------------------------------------------------------------- 
#pragma warning disable 1634, 1691  // avoid generating warnings about unknown
                                    // message numbers and unknown pragmas for PRESharp contol 
 
using System.Collections;               // IEnumerator
using System.Collections.Generic;       // List 
using System.Collections.ObjectModel;   // ReadOnlyCollection
using System.Security.Permissions;      // SecurityPermission
using System.Windows.Annotations;       // AnnotationService
using System.Windows.Automation;        // AutomationPattern 
using System.Windows.Automation.Peers;  // AutomationPeer
using System.Windows.Documents;         // IDocumentPaginatorSource, ... 
using System.Windows.Documents.Serialization;  // WritingCompletedEventArgs 
using System.Windows.Input;             // UICommand
using System.Windows.Media;             // Visual 
using System.Windows.Markup;            // IAddChild, XamlSerializerUtil, ContentPropertyAttribute
using System.Windows.Threading;         // DispatcherPriority
using System.Printing;                  // PrintQueue
using System.Windows.Xps;               // XpsDocumentWriter 
using MS.Internal;                      // Invariant, DoubleUtil
using MS.Internal.KnownBoxes;           // BooleanBoxes 
using MS.Internal.Annotations;          // TextAnchor 
using MS.Internal.Annotations.Anchoring;// DataIdProcessor, FixedPageProcessor, ...
using MS.Internal.Automation;           // TextAdaptor 
using MS.Internal.Documents;            // MultiPageTextView
using MS.Internal.Controls;             // EmptyEnumerator
using MS.Internal.Commands;             // CommandHelpers
 
namespace System.Windows.Controls.Primitives
{ 
    ///  
    /// DocumentViewerBase is a minimal base class, providing only the functionality
    /// common across document viewing scenarios. The base class provides no user 
    /// interface, very few properties, and minimal policy. Functionality included in
    /// the base class: BringIntoView support and Print API services
    /// and Annotation support.
    ///  
    [ContentProperty("Document")]
    public abstract class DocumentViewerBase : Control, IAddChild, IServiceProvider 
    { 
        //-------------------------------------------------------------------
        // 
        //  Constructors
        //
        //-------------------------------------------------------------------
 
        #region Constructors
 
        ///  
        /// Initializes class-wide settings.
        ///  
        static DocumentViewerBase()
        {
            // Create our CommandBindings
            CreateCommandBindings(); 

            // Register event handlers 
            EventManager.RegisterClassHandler(typeof(DocumentViewerBase), RequestBringIntoViewEvent, new RequestBringIntoViewEventHandler(HandleRequestBringIntoView)); 

            // Default value for AutoWordSelection is false.  We want true. 
            TextBoxBase.AutoWordSelectionProperty.OverrideMetadata(typeof(DocumentViewerBase), new FrameworkPropertyMetadata(true));
        }

        ///  
        /// Instantiates a new instance of a DocumentViewerBase.
        ///  
        protected DocumentViewerBase() 
            : base()
        { 
            _pageViews = new ReadOnlyCollection(new List());
            // By default text selection is enabled.
            SetFlags(true, Flags.IsSelectionEnabled);
        } 

        #endregion Constructors 
 
        //--------------------------------------------------------------------
        // 
        //  Public Methods
        //
        //-------------------------------------------------------------------
 
        #region Public Methods
 
        ///  
        /// Called when the Template's tree has been generated
        ///  
        /// Whether Visuals were added to the tree.
        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate(); 

            // Update collection of DocumentPageViews if the Visual tree has 
            // been updated through control template 
            UpdatePageViews();
        } 

        /// 
        /// Moves the master page to the previous page.
        ///  
        public void PreviousPage()
        { 
            OnPreviousPageCommand(); 
        }
 
        /// 
        /// Moves the master page to the next page.
        /// 
        public void NextPage() 
        {
            OnNextPageCommand(); 
        } 

        ///  
        /// Moves the master page to the first page.
        /// 
        public void FirstPage()
        { 
            OnFirstPageCommand();
        } 
 
        /// 
        /// Moves the master page to the last page. 
        /// 
        public void LastPage()
        {
            OnLastPageCommand(); 
        }
 
        ///  
        /// Moves the master page to the specified page.
        ///  
        /// 
        public void GoToPage(int pageNumber)
        {
            OnGoToPageCommand(pageNumber); 
        }
 
        ///  
        /// Invokes the Print Dialog. This is analogous to the ApplicationCommands.Print.
        ///  
        public void Print()
        {
            OnPrintCommand();
        } 

        ///  
        /// Cancels current printing job. This is analogous to the ApplicationCommands.CancelPrint. 
        /// 
        public void CancelPrint() 
        {
            OnCancelPrintCommand();
        }
 
        /// 
        /// Whether the master page can be moved to the specified page. 
        ///  
        /// Page number.
        public virtual bool CanGoToPage(int pageNumber) 
        {
            // Can navigate to a page, if:
            // a) the number is in valid range between 1 and PageCount, or
            // b) Paginator is set and pageNumber is PageCount+1. 
            return (pageNumber > 0 && pageNumber <= this.PageCount) ||
                ((_document != null) && (pageNumber - 1 == this.PageCount) && !_document.DocumentPaginator.IsPageCountValid); 
        } 

        #endregion Public Methods 

        //--------------------------------------------------------------------
        //
        //  Public Properties 
        //
        //-------------------------------------------------------------------- 
 
        #region Public Properties
 
        /// 
        /// The IDocumentPaginatorSource to be paginated and viewed.
        /// 
        public IDocumentPaginatorSource Document 
        {
            get { return _document; } 
            set { SetValue(DocumentProperty, value); } 
        }
 
        /// 
        /// The number of pages currently available for viewing. This value
        /// is updated as content is paginated, and will change dramatically
        /// when the content is resized, or edited. 
        /// 
        public int PageCount 
        { 
            get { return (int) GetValue(PageCountProperty); }
        } 

        /// 
        /// The one-based page number of the page being displayed on the master
        /// page DocumentPageView. If there is no content, this value will be 0. 
        /// 
        public virtual int MasterPageNumber 
        { 
            get { return (int) GetValue(MasterPageNumberProperty); }
        } 

        /// 
        /// Whether the viewer can move the master page to the previous page.
        ///  
        public virtual bool CanGoToPreviousPage
        { 
            get { return (bool) GetValue(CanGoToPreviousPageProperty); } 
        }
 
        /// 
        /// Whether the viewer can advance the master page to the next page.
        /// 
        public virtual bool CanGoToNextPage 
        {
            get { return (bool) GetValue(CanGoToNextPageProperty); } 
        } 

        ///  
        /// A read-only collection of the DocumentPageView objects contained
        /// within the viewer. These objects are manipulated by the viewer
        /// in order to display content.
        ///  
        [CLSCompliant(false)]
        public ReadOnlyCollection PageViews 
        { 
            get { return _pageViews; }
        } 

        #region Public Dynamic Properties

        /// \ 
        /// 
        ///  
        public static readonly DependencyProperty DocumentProperty = 
                DependencyProperty.Register(
                        "Document", 
                        typeof(IDocumentPaginatorSource),
                        typeof(DocumentViewerBase),
                        new FrameworkPropertyMetadata(
                                null, 
                                new PropertyChangedCallback(DocumentChanged)));
 
        ///  
        /// 
        ///  
        protected static readonly DependencyPropertyKey PageCountPropertyKey =
                DependencyProperty.RegisterReadOnly(
                        "PageCount",
                        typeof(int), 
                        typeof(DocumentViewerBase),
                        new FrameworkPropertyMetadata(0)); 
 
        /// 
        ///  
        /// 
        public static readonly DependencyProperty PageCountProperty =
                PageCountPropertyKey.DependencyProperty;
 
        /// 
        ///  
        ///  
        protected static readonly DependencyPropertyKey MasterPageNumberPropertyKey =
                DependencyProperty.RegisterReadOnly( 
                        "MasterPageNumber",
                        typeof(int),
                        typeof(DocumentViewerBase),
                        new FrameworkPropertyMetadata(0)); 

        ///  
        ///  
        /// 
        public static readonly DependencyProperty MasterPageNumberProperty = 
                MasterPageNumberPropertyKey.DependencyProperty;

        /// 
        ///  
        /// 
        protected static readonly DependencyPropertyKey CanGoToPreviousPagePropertyKey = 
                DependencyProperty.RegisterReadOnly( 
                        "CanGoToPreviousPage",
                        typeof(bool), 
                        typeof(DocumentViewerBase),
                        new FrameworkPropertyMetadata(BooleanBoxes.FalseBox));

        ///  
        /// 
        ///  
        public static readonly DependencyProperty CanGoToPreviousPageProperty = 
                CanGoToPreviousPagePropertyKey.DependencyProperty;
 
        /// 
        /// 
        /// 
        protected static readonly DependencyPropertyKey CanGoToNextPagePropertyKey = 
                DependencyProperty.RegisterReadOnly(
                        "CanGoToNextPage", 
                        typeof(bool), 
                        typeof(DocumentViewerBase),
                        new FrameworkPropertyMetadata(BooleanBoxes.FalseBox)); 

        /// 
        /// 
        ///  
        public static readonly DependencyProperty CanGoToNextPageProperty =
                CanGoToNextPagePropertyKey.DependencyProperty; 
 
        /// 
        /// Attached property used to signify which of the child DocumentPageView objects 
        /// is the master page. If more than one DocumentPageView has this value set,
        /// then the first tagged DocumentPageView in the tree (depth-first) is designated
        /// the master. If none of the children have this property set, then the depth-first
        /// PageView is designated the master. 
        /// 
        public static readonly DependencyProperty IsMasterPageProperty = 
                DependencyProperty.RegisterAttached( 
                        "IsMasterPage",
                        typeof(bool), 
                        typeof(DocumentViewerBase),
                        new FrameworkPropertyMetadata(BooleanBoxes.FalseBox));

        ///  
        /// DependencyProperty getter for  property.
        ///  
        /// The element from which to read the attached property. 
        public static bool GetIsMasterPage(DependencyObject element)
        { 
            if (element == null)
            {
                throw new ArgumentNullException("element");
            } 
            return (bool)element.GetValue(IsMasterPageProperty);
        } 
 
        /// 
        /// DependencyProperty setter for  property. 
        /// 
        /// The element to which to write the attached property.
        /// The property value to set
        public static void SetIsMasterPage(DependencyObject element, bool value) 
        {
            if (element == null) 
            { 
                throw new ArgumentNullException("element");
            } 
            element.SetValue(IsMasterPageProperty, value);
        }

        #endregion Public Dynamic Properties 

        #endregion Public Properties 
 
        //-------------------------------------------------------------------
        // 
        //  Public Events
        //
        //--------------------------------------------------------------------
 
        #region Public Events
 
        ///  
        /// Fired when collection of DocumentPageViews is changed.
        ///  
        public event EventHandler PageViewsChanged;

        #endregion Public Events
 
        //-------------------------------------------------------------------
        // 
        //  Protected Methods 
        //
        //------------------------------------------------------------------- 

        #region Protected Methods

        ///  
        /// Creates AutomationPeer ()
        ///  
        protected override AutomationPeer OnCreateAutomationPeer() 
        {
            return new DocumentViewerBaseAutomationPeer(this); 
        }

        /// 
        /// Invalidates the PageViews collection, triggering a call to GetPageViews. 
        /// 
        protected void InvalidatePageViews() 
        { 
            // Update collection of DocumentPageViews if  the collection has
            // been explicitly invalidated. 
            UpdatePageViews();
            InvalidateMeasure();
        }
 
        /// 
        /// Returns the master DocumentPageView. 
        ///  
        protected DocumentPageView GetMasterPageView()
        { 
            int index;
            DocumentPageView masterPageView = null;

            // Search for the first element with IsMasterPage property set. 
            for (index = 0; index < _pageViews.Count; index++)
            { 
                if (GetIsMasterPage(_pageViews[index])) 
                {
                    masterPageView = _pageViews[index]; 
                    break;
                }
            }
            // If none of the DocumentPageViews have this property set, 
            // then use the first one in the collection.
            if (masterPageView == null) 
            { 
                masterPageView = _pageViews.Count > 0 ? _pageViews[0] : null;
            } 
            return masterPageView;
        }

        ///  
        /// Creates a collection of DocumentPageView objects used to display Document.
        ///  
        /// True if the collection is different than the public PageViews collection. 
        /// Collection of DocumentPageView objects used to display Document.
        protected virtual ReadOnlyCollection GetPageViewsCollection(out bool changed) 
        {
            List pageViewList;
            AdornerDecorator adornerDecorator;
 
            // By default retrieve all DocumentPageViews from style.
            pageViewList = new List(1/* simplest case has just one element */); 
            FindDocumentPageViews(this, pageViewList); 

            // By default use AdornerDecorator.Child as RenderScope for TextEditor. Retieve 
            // AdornerDecorator from the style.
            adornerDecorator = FindAdornerDecorator(this);
            this.TextEditorRenderScope = (adornerDecorator != null) ? (adornerDecorator.Child as FrameworkElement) : null;
 
            // Since existing DocumentPageViews are being replaced, need to disconnect
            // them from the Document. 
            for (int index = 0; index < _pageViews.Count; index++) 
            {
                _pageViews[index].DocumentPaginator = null; 
            }

            changed = true;
            return new ReadOnlyCollection(pageViewList); 
        }
 
        ///  
        /// Called when the PageViews collection is modified; this occurs when GetPageViews
        /// returns True or if the control's template is modified. 
        /// 
        protected virtual void OnPageViewsChanged()
        {
            // Raise notification about change to DocumentPageView collection. 
            if (this.PageViewsChanged != null)
            { 
                this.PageViewsChanged(this, EventArgs.Empty); 
            }
            // Change of DocumentPageView collection may cause invalidation of content 
            // represented by DocumentPageViews.
            OnMasterPageNumberChanged();
        }
 
        /// 
        /// Called when the MasterPageNumber property is changed, this occurs when the 
        /// developer manually sets the property, or when the FirstPage, NextPage, 
        /// etc commands are executed.
        ///  
        protected virtual void OnMasterPageNumberChanged()
        {
            // Invalidation of MasterPage invalidates following properties:
            //      - MasterPageNumber 
            //      - CanGoToPreviousPage
            //      - CanGoToNextPage 
            UpdateReadOnlyProperties(true, true); 
        }
 
        /// 
        /// 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 virtual void OnBringIntoView(DependencyObject element, Rect rect, int pageNumber) 
        {
            if (element == null)
            {
                throw new ArgumentNullException("element"); 
            }
            OnGoToPageCommand(pageNumber); 
        } 

        ///  
        /// Handler for the PreviousPage command.
        /// 
        protected virtual void OnPreviousPageCommand()
        { 
            // If can go to the previous page, shift all pages
            // by decrementing page number by 1. 
            if (this.CanGoToPreviousPage) 
            {
                ShiftPagesByOffset(-1); 
            }
        }

        ///  
        /// Handler for the NextPage command.
        ///  
        protected virtual void OnNextPageCommand() 
        {
            // If can go to the next page, shift all pages 
            // by incrementing page number by 1.
            if (this.CanGoToNextPage)
            {
                ShiftPagesByOffset(1); 
            }
        } 
 
        /// 
        /// Handler for the FirstPage command. 
        /// 
        protected virtual void OnFirstPageCommand()
        {
            // Navigate the master page to the first one and shift 
            // all remaining pages by delta.
            ShiftPagesByOffset(1 - this.MasterPageNumber); 
        } 

        ///  
        /// Handler for the LastPage command.
        /// 
        protected virtual void OnLastPageCommand()
        { 
            // Navigate the master page to the last one and shift
            // all remaining pages by delta. 
            ShiftPagesByOffset(this.PageCount - this.MasterPageNumber); 
        }
 
        /// 
        /// Handler for the GoToPage command.
        /// 
        ///  
        protected virtual void OnGoToPageCommand(int pageNumber)
        { 
            // Check if can go to the specified page. 
            // Navigate the master page to specified page number and shift
            // all remaining pages by delta. 
            if (CanGoToPage(pageNumber))
            {
                ShiftPagesByOffset(pageNumber - this.MasterPageNumber);
            } 
        }
 
        ///  
        /// Handler for the Print command.
        ///  
        protected virtual void OnPrintCommand()
        {
#if !DONOTREFPRINTINGASMMETA
            XpsDocumentWriter docWriter; 
            PrintDocumentImageableArea ia = null;
 
            // Only one printing job is allowed. 
            if (_documentWriter != null)
            { 
                return;
            }

            if (_document != null) 
            {
                // Show print dialog. 
                docWriter = PrintQueue.CreateXpsDocumentWriter(ref ia); 
                if (docWriter != null && ia != null)
                { 
                    // Register for WritingCompleted event.
                    _documentWriter = docWriter;
                    _documentWriter.WritingCompleted += new WritingCompletedEventHandler(HandlePrintCompleted);
                    _documentWriter.WritingCancelled += new WritingCancelledEventHandler(HandlePrintCancelled); 

                    // Since _documentWriter value is used to determine CanExecute state, we must invalidate that state. 
                    CommandManager.InvalidateRequerySuggested(); 

                    // Write to the PrintQueue 
                    if( _document is FixedDocumentSequence )
                    {
                        docWriter.WriteAsync(_document as FixedDocumentSequence);
                    } 
                    else if( _document is FixedDocument )
                    { 
                        docWriter.WriteAsync(_document as FixedDocument); 
                    }
                    else 
                    {
                        docWriter.WriteAsync(_document.DocumentPaginator);
                    }
                } 
            }
#endif // DONOTREFPRINTINGASMMETA 
        } 

        ///  
        /// Handler for the CancelPrint command.
        /// 
        protected virtual void OnCancelPrintCommand()
        { 
#if !DONOTREFPRINTINGASMMETA
            if (_documentWriter != null) 
            { 
                _documentWriter.CancelAsync();
            } 
#endif // DONOTREFPRINTINGASMMETA
        }

        ///  
        /// Called when the Document property is changed.
        ///  
        protected virtual void OnDocumentChanged() 
        {
            int index; 

            // Document has been changed. Update existing DocumentPageViews to point them to the new Document.
            for (index = 0; index < _pageViews.Count; index++)
            { 
                _pageViews[index].DocumentPaginator = (_document != null) ? _document.DocumentPaginator : null;
            } 
 
            // Document invalidation invalidates following properties:
            //      - PageCount 
            //      - MasterPageNumber
            //      - CanGoToPreviousPage
            //      - CanGoToNextPage
            UpdateReadOnlyProperties(true, true); 

            // Attach TextEditor, if content supports it. This method will also 
            // detach TextEditor from old content. 
            AttachTextEditor();
        } 

        #endregion Protected Methods

        //------------------------------------------------------------------- 
        //
        //  Protected Properties 
        // 
        //--------------------------------------------------------------------
 
        #region Protected Properties

        /// 
        /// Returns enumerator to logical children. 
        /// 
        protected internal override IEnumerator LogicalChildren 
        { 
            get
            { 
                if (this.HasLogicalChildren && _document != null)
                {
                    return new SingleChildEnumerator(_document);
                } 
                return EmptyEnumerator.Instance;
            } 
        } 

        #endregion Protected Properties 

        //-------------------------------------------------------------------
        //
        //  Internal Methods 
        //
        //-------------------------------------------------------------------- 
 
        #region Internal Methods
 
        /// 
        /// Determines whether DocumentPageView is a master page.
        /// 
        /// Instance of DocumentPageView. 
        /// Whether given instance of DocumentPageView is a master page.
        internal bool IsMasterPageView(DocumentPageView pageView) 
        { 
            Invariant.Assert(pageView != null);
            return (pageView == GetMasterPageView()); 
        }

        /// 
        /// Invoked when the "Find" button in the Find Toolbar is clicked. 
        /// This method invokes the actual Find process.
        ///  
        internal ITextRange Find(FindToolBar findToolBar) 
        {
            ITextView masterPageTextView = null; 
            DocumentPageView masterPage = GetMasterPageView();
            if (masterPage != null && masterPage is IServiceProvider)
            {
                masterPageTextView = ((IServiceProvider)masterPage).GetService(typeof(ITextView)) as ITextView; 
            }
            return DocumentViewerHelper.Find(findToolBar, _textEditor, _textView, masterPageTextView); 
        } 

        #endregion Internal Methods 

        //--------------------------------------------------------------------
        //
        //  Internal Properties 
        //
        //------------------------------------------------------------------- 
 
        #region Internal Properties
 
        /// 
        /// Whether text selection is enabled or disabled.
        /// 
        internal bool IsSelectionEnabled 
        {
            get { return CheckFlags(Flags.IsSelectionEnabled); } 
            set 
            {
                SetFlags(value, Flags.IsSelectionEnabled); 
                AttachTextEditor();
            }
        }
 
        /// 
        /// TextEditor instance. 
        ///  
        internal TextEditor TextEditor
        { 
            get { return _textEditor; }
        }

        ///  
        /// Allows overriding the RenderScope used by the TextEditor.
        ///  
        internal FrameworkElement TextEditorRenderScope 
        {
            get 
            {
                return _textEditorRenderScope;
            }
            set 
            {
                _textEditorRenderScope = value; 
                AttachTextEditor(); 
            }
        } 

        #endregion Internal Properties

        //-------------------------------------------------------------------- 
        //
        //  Private Methods 
        // 
        //-------------------------------------------------------------------
 
        #region Private Methods

        /// 
        /// Retrieves an ITextPointer from the MasterPage. 
        /// If startOfPage is true, then we will retreive the first
        /// TextPointer in the first TextSegment in the DocumentPageTextView. 
        /// Else, we will retreive the last TextPointer in the last TextSegment 
        /// of the MasterPage DocumentPageTextView.
        ///  
        /// 
        /// 
        private ITextPointer GetMasterPageTextPointer(bool startOfPage)
        { 
            ITextPointer masterPointer = null;
            ITextView textView = null; 
            DocumentPageView masterPage = GetMasterPageView(); 

            if (masterPage != null && masterPage is IServiceProvider) 
            {
                textView = ((IServiceProvider)masterPage).GetService(typeof(ITextView)) as ITextView;
                if (textView != null && textView.IsValid)
                { 
                    // Find the very first/(last) text pointer in this textView.
                    foreach (TextSegment textSegment in textView.TextSegments) 
                    { 
                        if (textSegment.IsNull)
                        { 
                            continue;
                        }

                        if (masterPointer == null) 
                        {
                            // Set initial masterPointer value. 
                            masterPointer = startOfPage ? textSegment.Start : textSegment.End; 
                        }
                        else 
                        {
                            if (startOfPage)
                            {
                                if (textSegment.Start.CompareTo(masterPointer) < 0) 
                                {
                                    // Start is before the current masterPointer 
                                    masterPointer = textSegment.Start; 
                                }
                            } 
                            else
                            {
                                // end is after than the current masterPointer
                                if (textSegment.End.CompareTo(masterPointer) > 0) 
                                {
                                    masterPointer = textSegment.End; 
                                } 
                            }
                        } 
                    }
                }
            }
 
            return masterPointer;
        } 
 
        /// 
        /// Update collection of DocumentPageViews in responce to Visual tree changes. 
        /// 
        /// Whether collection of DocumentPageViews has been updated.
        private void UpdatePageViews()
        { 
            int index;
            bool changed; 
            ReadOnlyCollection pageViews; 

            // Get collection of new DocumentPageViews. 
            pageViews = GetPageViewsCollection(out changed);

            // If DocumentPageViews collection has not been changed, there is nothing to update.
            if (changed) 
            {
                // Verify collection of DocumentPageViews. It needs to meet following conditions: 
                // a) at least one DocumentPageView, 
                // b) only one page has IsMasterPage property set to true,
                // c) unique PageNumbers for each active DocumentPageView, 
                VerifyDocumentPageViews(pageViews);

                // New collection of DocumentPageViews is replacing the old one. Point new
                // DocumentPageViews to the Document. 
                _pageViews = pageViews;
                for (index = 0; index < _pageViews.Count; index++) 
                { 
                    _pageViews[index].DocumentPaginator = (_document != null) ? _document.DocumentPaginator : null;
                } 

                // Collection of DocumentPageView has been changed. Need to update
                // TextView, if one already exists.
                if (_textView != null) 
                {
                    _textView.OnPagesUpdated(); 
                } 

                // DocumentPageViews collection has been changed. Notify all listeners 
                // and/or derived classes about this fact.
                OnPageViewsChanged();
            }
        } 

        ///  
        /// Verify collection of DocumentPageViews. It needs to meet following conditions: 
        /// a) collection is not null,
        /// b) only one page has IsMasterPage property set to true, 
        /// c) unique PageNumbers for each active DocumentPageView,
        /// 
        /// Collection of DocumentPageViews to validate.
        private void VerifyDocumentPageViews(ReadOnlyCollection pageViews) 
        {
            int index; 
            bool hasMasterPage = false; 

            // At least one DocumentPageView is required. 
            if (pageViews == null)
            {
                throw new ArgumentException(SR.Get(SRID.DocumentViewerPageViewsCollectionEmpty));
            } 

            // Expecting only one DocumentPageView with IsMasterPage property set to true. 
            for (index = 0; index < pageViews.Count; index++) 
            {
                if (GetIsMasterPage(pageViews[index])) 
                {
                    if (hasMasterPage)
                    {
                        throw new ArgumentException(SR.Get(SRID.DocumentViewerOneMasterPage)); 
                    }
                    hasMasterPage = true; 
                } 
            }
 
            // Unique PageNumbers for each active DocumentPageView.
        }

        ///  
        /// Does deep Visual tree walk to retrieve all DocumentPageViews.
        /// It stops recursing down into visual tree in following situations: 
        /// a) Visual is UIElement and it is not part of Contol Template, 
        /// b) Visual is DocumentPageView.
        ///  
        /// FrameworkElement that is part of Control Template.
        /// Collection of DocumentPageViews; found elements are appended here.
        /// Whether collection of DocumentPageViews has been updated.
        private void FindDocumentPageViews(Visual root, List pageViews) 
        {
            Invariant.Assert(root != null); 
            Invariant.Assert(pageViews != null); 

            FrameworkElement fe; 
            // Do deep tree walk to retrieve all DocumentPageViews.
            // It stops recursing down into visual tree in following situations:
            // a) Visual is UIElement and it is not part of Contol Template,
            // b) Visual is DocumentPageView. 
            // Add to collection any DocumentPageViews found in the Control Template.
            int count = root.InternalVisualChildrenCount; 
            for(int i = 0; i < count; i++) 
            {
                Visual child = root.InternalGetVisualChild(i); 
                fe = child as FrameworkElement;
                if (fe != null)
                {
                    if (fe.TemplatedParent != null) 
                    {
                        if (fe is DocumentPageView) 
                        { 
                            pageViews.Add(fe as DocumentPageView);
                        } 
                        else
                        {
                            FindDocumentPageViews(fe, pageViews);
                        } 
                    }
                } 
                else 
                {
                    FindDocumentPageViews(child, pageViews); 
                }
            }
        }
 
        /// 
        /// Does deep Visual tree walk to retrieve an AdornerDecorator. Because 
        /// AdornerDecorator is supposed to cover all DocumentPageViews, it stops 
        /// recursing down into visual tree in following situations:
        /// a) Visual is UIElement and it is not part of Contol Template, 
        /// b) Visual is DocumentPageView.
        /// c) Visual is AdornerDecorator.
        /// 
        /// FrameworkElement that is part of Control Template. 
        /// AdornerDecorator, if found.
        private AdornerDecorator FindAdornerDecorator(Visual root) 
        { 
            Invariant.Assert(root != null);
 
            FrameworkElement fe;
            AdornerDecorator adornerDecorator = null;

            // Do deep Visual tree walk to retrieve an AdornerDecorator. Because 
            // AdornerDecorator is supposed to cover all DocumentPageViews, it stops
            // recursing down into visual tree in following situations: 
            // a) Visual is UIElement and it is not part of Contol Template, 
            // b) Visual is DocumentPageView.
            // c) Visual is AdornerDecorator. 
            int count = root.InternalVisualChildrenCount;
            for(int i = 0; i < count; i++)
            {
                Visual child = root.InternalGetVisualChild(i); 
                fe = child as FrameworkElement;
                if (fe != null) 
                { 
                    if (fe.TemplatedParent != null)
                    { 
                        if (fe is AdornerDecorator)
                        {
                            adornerDecorator = (AdornerDecorator)fe;
                        } 
                        else if (!(fe is DocumentPageView))
                        { 
                            adornerDecorator = FindAdornerDecorator(fe); 
                        }
                        // else stop on DocumentPageView 
                    }
                }
                else
                { 
                    adornerDecorator = FindAdornerDecorator(child);
                } 
                if (adornerDecorator != null) 
                {
                    break; 
                }
            }
            return adornerDecorator;
        } 

        ///  
        /// Attach TextEditor to Document, if supports text. 
        /// 
        private void AttachTextEditor() 
        {
            AnnotationService service = AnnotationService.GetService(this);
            ITextContainer textContainer;
 
            // This method is called when Document is changing, so need
            // to clear old TextEditor data. 
            if (_textEditor != null) 
            {
                _textEditor.OnDetach(); 
                _textEditor = null;
                if (_textView.TextContainer.TextView == _textView)
                {
                    _textView.TextContainer.TextView = null; 
                }
                _textView = null; 
            } 

            if (service != null) 
            {
                // Must be enabled - otherwise it won't be on the tree
                service.Disable();
            } 

            // If new Document supports TextEditor, create one. 
            // If the Document is already attached to TextEditor (TextSelection != null), 
            // do not create TextEditor for this instance of the viewer. (This situation may happen
            // when the same instance of Document is attached to more than one viewer). 
            textContainer = this.TextContainer;
            if (textContainer != null && this.TextEditorRenderScope != null && textContainer.TextSelection == null)
            {
                _textView = new MultiPageTextView(this, this.TextEditorRenderScope, textContainer); 
                _textEditor = new TextEditor(textContainer, this, false);
                _textEditor.IsReadOnly = !IsEditingEnabled; 
                _textEditor.TextView = _textView; 
                textContainer.TextView = _textView;
            } 

            // Re-enable the service in order to register on the new TextView
            if (service != null)
            { 
                service.Enable(service.Store);
            } 
        } 

        ///  
        /// Called when WritingCompleted event raised by a DocumentWriter (during printing).
        /// 
        /// Sender of the event.
        /// Event arguments. 
        private void HandlePrintCompleted(object sender, WritingCompletedEventArgs e)
        { 
            CleanUpPrintOperation(); 
        }
 
        /// 
        /// Called when WritingCancelled event raised by a DocumentWriter (during printing).
        /// 
        /// Sender of the event. 
        /// Event arguments.
        private void HandlePrintCancelled(object sender, WritingCancelledEventArgs e) 
        { 
            CleanUpPrintOperation();
        } 

        /// 
        /// Handler for PaginationCompleted event raised by the Document.
        ///  
        private void HandlePaginationCompleted(object sender, EventArgs e)
        { 
            // PaginationCompleted may invalidate following properties: 
            //      - PageCount
            //      - CanGoToNextPage 
            UpdateReadOnlyProperties(true, false);
        }

        ///  
        /// Handler for PaginationProgress event raised by the Document.
        ///  
        private void HandlePaginationProgress(object sender, EventArgs e) 
        {
            // PaginationProgress may invalidate following properties: 
            //      - PageCount
            //      - CanGoToNextPage
            UpdateReadOnlyProperties(true, false);
        } 

        ///  
        /// Handler for GetPageNumberCompleted event raised by the Document. 
        /// 
        private void HandleGetPageNumberCompleted(object sender, GetPageNumberCompletedEventArgs e) 
        {
            BringIntoViewState bringIntoViewState;

            // At this point the Document's page count might have changed, 
            // so update properties accordingly.
            UpdateReadOnlyProperties(true, false); 
 
            if (_document != null && sender == _document.DocumentPaginator && e != null)
            { 
                if (!e.Cancelled && (e.Error == null))
                {
                    bringIntoViewState = e.UserState as BringIntoViewState;
                    if (bringIntoViewState != null && bringIntoViewState.Source == this) 
                    {
                        OnBringIntoView(bringIntoViewState.TargetObject, bringIntoViewState.TargetRect, e.PageNumber + 1); 
                    } 
                }
            } 
        }

        /// 
        /// Makes sure the target is visible in the client area. May cause navigation 
        /// to a different page.
        ///  
        /// RequestBringIntoViewEventArgs indicates the element and region to scroll into view. 
        private void HandleRequestBringIntoView(RequestBringIntoViewEventArgs args)
        { 
            DependencyObject child;
            DependencyObject parent;
            ContentPosition contentPosition;
            BringIntoViewState bringIntoViewState; 
            DynamicDocumentPaginator documentPaginator;
            Rect targetRect = Rect.Empty; 
 
            if (args != null && args.TargetObject != null && _document is DependencyObject)
            { 
                // If the passed in object is a logical child of DocumentViewer's Document,
                // attempt to make it visible now.
                // Special case: TargetObject is the document itself. Then scroll to the top (page 1).
                // This supports navigating from baseURI#anchor to just baseURI. 
                parent = _document as DependencyObject;
                if (args.TargetObject == _document) 
                { 
                    OnGoToPageCommand(1);
                    args.Handled = true; // Mark the event as handled. 
                }
                else
                {
                    // Verify if TargetObject is in fact a child of Document. 
                    child = args.TargetObject;
                    while (child != null && child != parent) 
                    { 
                        // Skip elements in the control's template (if such exists) and
                        // walk up logical tree to find if the focused element is within 
                        // the document.
                        FrameworkElement fe = child as FrameworkElement;
                        if (fe != null && fe.TemplatedParent != null)
                        { 
                            child = fe.TemplatedParent;
                        } 
                        else 
                        {
                            child = LogicalTreeHelper.GetParent(child); 
                        }
                    }

                    if (child != null) 
                    {
                        // Special case UIElements already connected to visual tree. 
                        if (args.TargetObject is UIElement) 
                        {
                            UIElement targetObject = (UIElement)args.TargetObject; 
                            if (VisualTreeHelper.IsAncestorOf(this, targetObject))
                            {
                                targetRect = args.TargetRect;
                                if (targetRect.IsEmpty) 
                                {
                                    targetRect = new Rect(targetObject.RenderSize); 
                                } 
                                GeneralTransform transform = targetObject.TransformToAncestor(this);
                                targetRect = transform.TransformBounds(targetRect); 
                                targetRect.IntersectsWith(new Rect(this.RenderSize));
                            }
                        }
 
                        // If target is not already visible, bring appropriate page into view.
                        if (targetRect.IsEmpty) 
                        { 
                            // Get content position for given target.
                            documentPaginator = _document.DocumentPaginator as DynamicDocumentPaginator; 
                            if (documentPaginator != null)
                            {
                                contentPosition = documentPaginator.GetObjectPosition(args.TargetObject);
                                if (contentPosition != null && contentPosition != ContentPosition.Missing) 
                                {
                                    // Asynchronously retrieve PageNumber for given ContentPosition. 
                                    bringIntoViewState = new BringIntoViewState(this, contentPosition, args.TargetObject, args.TargetRect); 
                                    documentPaginator.GetPageNumberAsync(contentPosition, bringIntoViewState);
                                } 
                            }
                        }
                        args.Handled = true; // Mark the event as handled.
                    } 
                }
                if (args.Handled) 
                { 
                    // Create new BringIntoView request for this element, so
                    // if there is an ancestor handling BringIntoView, it can 
                    // react appropriately and bring this element into view.
                    if (targetRect.IsEmpty)
                    {
                        BringIntoView(); 
                    }
                    else 
                    { 
                        BringIntoView(targetRect);
                    } 
                }
            }
        }
 
        /// 
        /// Update values for readonly properties. 
        ///  
        /// Whether PageCount has been changed.
        /// Whether MasterPageNumber has been changed. 
        private void UpdateReadOnlyProperties(bool pageCountChanged, bool masterPageChanged)
        {
            if (pageCountChanged)
            { 
                SetValue(PageCountPropertyKey, (_document != null) ? _document.DocumentPaginator.PageCount : 0);
            } 
 
            bool invalidateRequery = false;
 
            if (masterPageChanged)
            {
                int masterPageNumber = 0;
                DocumentPageView masterPageView; 
                if (_document != null && _pageViews.Count > 0)
                { 
                    masterPageView = GetMasterPageView(); 
                    if (masterPageView != null)
                    { 
                        masterPageNumber = masterPageView.PageNumber + 1;
                    }
                }
 
                SetValue(MasterPageNumberPropertyKey, masterPageNumber);
                SetValue(CanGoToPreviousPagePropertyKey, MasterPageNumber > 1); 
 
                invalidateRequery = true;
            } 

            if (pageCountChanged || masterPageChanged)
            {
                bool canGoToNextPage = false; 
                if (_document != null)
                { 
                    canGoToNextPage = (MasterPageNumber < _document.DocumentPaginator.PageCount) || !_document.DocumentPaginator.IsPageCountValid; 
                }
                SetValue(CanGoToNextPagePropertyKey, canGoToNextPage); 

                invalidateRequery = true;
            }
 
            if(invalidateRequery)
            { 
                CommandManager.InvalidateRequerySuggested(); 
            }
        } 

        /// 
        /// Shift all pages by specified offset.
        ///  
        private void ShiftPagesByOffset(int offset)
        { 
            int index; 
            if (offset != 0)
            { 
                for (index = 0; index < _pageViews.Count; index++)
                {
                    _pageViews[index].PageNumber += offset;
                } 
                // Change of PageNumber property on DocumentPageViews will cause
                // invalidation of content represented by DocumentPageViews. 
                OnMasterPageNumberChanged(); 
            }
        } 

        /// 
        /// Sets or unsets one or multiple flags.
        ///  
        /// Whether flag or flags are set or cleared.
        /// Combination of flags to change. 
        private void SetFlags(bool value, Flags flags) 
        {
            _flags = value ? (_flags | flags) : (_flags & (~flags)); 
        }

        /// 
        /// Returns true if all of passed flags in the bitmask are set. 
        /// 
        /// Combination of flags to get the value. 
        /// Returns true if all of passed flags in the bitmask are set. 
        private bool CheckFlags(Flags flags)
        { 
            return ((_flags & flags) == flags);
        }

        ///  
        /// The Document has changed and needs to be updated.
        ///  
        private void DocumentChanged(IDocumentPaginatorSource oldDocument, IDocumentPaginatorSource newDocument) 
        {
            DependencyObject doDocument; 
            DynamicDocumentPaginator dynamicDocumentPaginator;
            _document = newDocument;

            // Cleanup state associated with the old document. 
            if (oldDocument != null)
            { 
                // If Document was added to logical tree of DocumentViewer before, remove it. 
                if (CheckFlags(Flags.DocumentAsLogicalChild))
                { 
                    RemoveLogicalChild(oldDocument);
                }
                // Unregister from PaginationProgress and PaginationCompleted events.
                dynamicDocumentPaginator = oldDocument.DocumentPaginator as DynamicDocumentPaginator; 
                if (dynamicDocumentPaginator != null)
                { 
                    dynamicDocumentPaginator.PaginationProgress -= new PaginationProgressEventHandler(HandlePaginationProgress); 
                    dynamicDocumentPaginator.PaginationCompleted -= new EventHandler(HandlePaginationCompleted);
                    dynamicDocumentPaginator.GetPageNumberCompleted -= new GetPageNumberCompletedEventHandler(HandleGetPageNumberCompleted); 
                }

                DependencyObject depObj = oldDocument as DependencyObject;
                if (depObj != null) 
                {
                    depObj.ClearValue(PathNode.HiddenParentProperty); 
                } 
            }
 
            // If DocumentViewer was created through style, then do not modify
            // the logical tree. Instead, set "core parent" for the Document.
            doDocument = _document as DependencyObject;
 	        if (doDocument != null && LogicalTreeHelper.GetParent(doDocument) != null && doDocument is ContentElement) 
            {
                // Set the "core parent" back to us. 
                ContentOperations.SetParent((ContentElement)doDocument, this); 
                SetFlags(false, Flags.DocumentAsLogicalChild);
            } 
            else
            {
                SetFlags(true, Flags.DocumentAsLogicalChild);
            } 

            // Initialize state associated with the new document. 
            if (_document != null) 
            {
                // If Document should be part of DocumentViewer's logical tree, add it. 
                if (CheckFlags(Flags.DocumentAsLogicalChild))
                {
                    AddLogicalChild(_document);
                } 
                // Register for PaginationProgress and PaginationCompleted events.
                dynamicDocumentPaginator = _document.DocumentPaginator as DynamicDocumentPaginator; 
                if (dynamicDocumentPaginator != null) 
                {
                    dynamicDocumentPaginator.PaginationProgress += new PaginationProgressEventHandler(HandlePaginationProgress); 
                    dynamicDocumentPaginator.PaginationCompleted += new EventHandler(HandlePaginationCompleted);
                    dynamicDocumentPaginator.GetPageNumberCompleted += new GetPageNumberCompletedEventHandler(HandleGetPageNumberCompleted);
                }
 
                // Setup DPs and processors for annotation handling.  If the service isn't already
                // enabled the processors will be registered by the service when it is enabled. 
                FlowDocument flowDocument; 
                DependencyObject doc = _document as DependencyObject;
                if (_document is FixedDocument || _document is FixedDocumentSequence) 
                {
                    // Clear properties that aren't needed for FixedDocument
                    this.ClearValue(AnnotationService.DataIdProperty);
                    // Setup service to look for FixedPages in the content 
                    AnnotationService.SetSubTreeProcessorId(this, FixedPageProcessor.Id);
                    // Tell the content how to get to its parent DocumentViewer 
                    doc.SetValue(PathNode.HiddenParentProperty, this); 
                    // If the service is already registered, set it up for fixed content
                    AnnotationService service = AnnotationService.GetService(this); 
                    if (service != null)
                    {
                        service.LocatorManager.RegisterSelectionProcessor(new FixedTextSelectionProcessor(), typeof(TextRange));
                        service.LocatorManager.RegisterSelectionProcessor(new FixedTextSelectionProcessor(), typeof(TextAnchor)); 
                    }
                } 
                else if ((flowDocument = _document as FlowDocument) != null) 
                {
                    // Tell the content how to get to its parent DocumentViewer 
                    flowDocument.SetValue(PathNode.HiddenParentProperty, this);
                    // If the service is already registered, set it up for fixed content
                    AnnotationService service = AnnotationService.GetService(this);
                    if (service != null) 
                    {
                        service.LocatorManager.RegisterSelectionProcessor(new TextSelectionProcessor(), typeof(TextRange)); 
                        service.LocatorManager.RegisterSelectionProcessor(new TextSelectionProcessor(), typeof(TextAnchor)); 
                        service.LocatorManager.RegisterSelectionProcessor(new TextViewSelectionProcessor(), typeof(DocumentViewerBase));
                    } 
                    // Setup service to use DataID processor
                    AnnotationService.SetDataId(this, "FlowDocument");
                }
                else 
                {
                    // Clear values that were set directly on the tree - only valid for Fixed or Flow Documents 
                    this.ClearValue(AnnotationService.SubTreeProcessorIdProperty); 
                    this.ClearValue(AnnotationService.DataIdProperty);
                } 
            }

            // Document is also represented as Automation child. Need to invalidate peer to force update.
            DocumentViewerBaseAutomationPeer peer = UIElementAutomationPeer.FromElement(this) as DocumentViewerBaseAutomationPeer; 
            if (peer != null)
            { 
                peer.InvalidatePeer(); 
            }
 
            // Respond to Document change - update state that is affected by this change.
            OnDocumentChanged();
        }
 
        /// 
        /// Cleans up after a print operation by unregistering for events and re-enabling buttons. 
        ///  
        private void CleanUpPrintOperation()
        { 
#if !DONOTREFPRINTINGASMMETA
            if (_documentWriter != null)
            {
                _documentWriter.WritingCompleted -= new WritingCompletedEventHandler(HandlePrintCompleted); 
                _documentWriter.WritingCancelled -= new WritingCancelledEventHandler(HandlePrintCancelled);
                _documentWriter = null; 
 
                // Since _documentWriter value is used to determine CanExecute state, we must invalidate that state.
                CommandManager.InvalidateRequerySuggested(); 
            }
#endif // DONOTREFPRINTINGASMMETA
        }
 
        #region Commands
 
        ///  
        /// Set up Command and RoutedCommand bindings.
        ///  
        private static void CreateCommandBindings()
        {
            ExecutedRoutedEventHandler executedHandler;
            CanExecuteRoutedEventHandler canExecuteHandler; 

            // Create our generic ExecutedRoutedEventHandler. 
            executedHandler = new ExecutedRoutedEventHandler(ExecutedRoutedEventHandler); 
            // Create our generic QueryEnabledStatusHandler
            canExecuteHandler = new CanExecuteRoutedEventHandler(CanExecuteRoutedEventHandler); 

            // Command: NavigationCommands.PreviousPage
            CommandHelpers.RegisterCommandHandler(typeof(DocumentViewerBase), NavigationCommands.PreviousPage,
                executedHandler, canExecuteHandler); // no key gesture 

            // Command: NavigationCommands.NextPage 
            CommandHelpers.RegisterCommandHandler(typeof(DocumentViewerBase), NavigationCommands.NextPage, 
                executedHandler, canExecuteHandler); // no key gesture
 
            // Command: NavigationCommands.FirstPage
            CommandHelpers.RegisterCommandHandler(typeof(DocumentViewerBase), NavigationCommands.FirstPage,
                executedHandler, canExecuteHandler); // no key gesture
 
            // Command: NavigationCommands.LastPage
            CommandHelpers.RegisterCommandHandler(typeof(DocumentViewerBase), NavigationCommands.LastPage, 
                executedHandler, canExecuteHandler); // no key gesture 

            // Command: NavigationCommands.GoToPage 
            CommandHelpers.RegisterCommandHandler(typeof(DocumentViewerBase), NavigationCommands.GoToPage,
                executedHandler, canExecuteHandler); // no key gesture

            // Command: ApplicationCommands.Print 
            CommandHelpers.RegisterCommandHandler(typeof(DocumentViewerBase), ApplicationCommands.Print,
                executedHandler, canExecuteHandler, new KeyGesture(Key.P, ModifierKeys.Control)); 
 
            // Command: ApplicationCommands.CancelPrint
            CommandHelpers.RegisterCommandHandler(typeof(DocumentViewerBase), ApplicationCommands.CancelPrint, 
                executedHandler, canExecuteHandler); // no key gesture

            // Register editing command handlers - After our commands to let editor handle them first
            TextEditor.RegisterCommandHandlers(typeof(DocumentViewerBase), /*acceptsRichContent:*/true, /*readOnly:*/!IsEditingEnabled, /*registerEventListeners*/true); 
        }
 
        ///  
        /// Central handler for CanExecuteRouted events fired by Commands directed at DocumentViewerBase.
        ///  
        /// The target of this Command, expected to be DocumentViewerBase
        /// The event arguments for this event.
        private static void CanExecuteRoutedEventHandler(object target, CanExecuteRoutedEventArgs args)
        { 
            DocumentViewerBase dv = target as DocumentViewerBase;
            Invariant.Assert(dv != null, "Target of CanExecuteRoutedEventHandler must be DocumentViewerBase."); 
            Invariant.Assert(args != null, "args cannot be null."); 

            // DocumentViewerBase is capable of execution of the majority of its commands. 
            // Special rules:
            // a) Print command is enabled when Document is attached and printing is not in progress.
            // b) CancelPrint command is enabled only during printing.
            if (args.Command == ApplicationCommands.Print) 
            {
                args.CanExecute = (dv.Document != null) && (dv._documentWriter == null); 
                args.Handled = true; 
            }
            else if (args.Command == ApplicationCommands.CancelPrint) 
            {
                args.CanExecute = (dv._documentWriter != null);
            }
            else 
            {
                args.CanExecute = true; 
            } 
        }
 
        /// 
        /// Central handler for all ExecutedRouted events fired by Commands directed at DocumentViewerBase.
        /// 
        /// The target of this Command, expected to be DocumentViewerBase. 
        /// The event arguments associated with this event.
        private static void ExecutedRoutedEventHandler(object target, ExecutedRoutedEventArgs args) 
        { 
            DocumentViewerBase dv = target as DocumentViewerBase;
            Invariant.Assert(dv != null, "Target of ExecuteEvent must be DocumentViewerBase."); 
            Invariant.Assert(args != null, "args cannot be null.");

            // 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 == NavigationCommands.PreviousPage) 
            { 
                dv.OnPreviousPageCommand();
            } 
            else if (args.Command == NavigationCommands.NextPage)
            {
                dv.OnNextPageCommand();
            } 
            else if (args.Command == NavigationCommands.FirstPage)
            { 
                dv.OnFirstPageCommand(); 
            }
            else if (args.Command == NavigationCommands.LastPage) 
            {
                dv.OnLastPageCommand();
            }
            else if (args.Command == NavigationCommands.GoToPage) 
            {
                // Ignore GoToPageCommand, if: 
                //  a) there is no value for the page number. 
                //  b) the value cannot be converted to Int32.
                if (args.Parameter != null) 
                {
                    int pageNumber = -1;
                    try
                    { 
                        pageNumber = Convert.ToInt32(args.Parameter, System.Globalization.CultureInfo.CurrentCulture);
                    } 
#pragma warning disable 56502 // Allow empty catch statements. 
                    catch (InvalidCastException) { }
                    catch (OverflowException) { } 
                    catch (FormatException) { }
#pragma warning restore 56502

                    if (pageNumber >= 0) 
                    {
                        dv.OnGoToPageCommand(pageNumber); 
                    } 
                }
            } 
            else if (args.Command == ApplicationCommands.Print)
            {
                dv.OnPrintCommand();
            } 
            else if (args.Command == ApplicationCommands.CancelPrint)
            { 
                dv.OnCancelPrintCommand(); 
            }
            else 
            {
                Invariant.Assert(false, "Command not handled in ExecutedRoutedEventHandler.");
            }
        } 

        #endregion Commands 
 
        #region Static Methods
 
        /// 
        /// Called from the event handler to make sure the target is visible in the client
        /// area. May cause navigation to a different page.
        ///  
        /// The instance handling the event.
        /// RequestBringIntoViewEventArgs indicates the element and region to scroll into view. 
        private static void HandleRequestBringIntoView(object sender, RequestBringIntoViewEventArgs args) 
        {
            if (sender != null && sender is DocumentViewerBase) 
            {
                ((DocumentViewerBase)sender).HandleRequestBringIntoView(args);
            }
        } 

        ///  
        /// The Document has changed and needs to be updated. 
        /// 
        private static void DocumentChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
        {
            Invariant.Assert(d != null && d is DocumentViewerBase);
            ((DocumentViewerBase) d).DocumentChanged((IDocumentPaginatorSource) e.OldValue, (IDocumentPaginatorSource) e.NewValue);
 
            // Since Document state is used to determine CanExecute state, we must invalidate that state.
            CommandManager.InvalidateRequerySuggested(); 
        } 

        #endregion Static Methods 

        #endregion Private Methods

        //------------------------------------------------------------------- 
        //
        //  Private Properties 
        // 
        //-------------------------------------------------------------------
 
        #region Private Properties

        /// 
        /// ITextContainer associated with Document. 
        /// 
        private ITextContainer TextContainer 
        { 
            get
            { 
                ITextContainer textContainer = null;
                if (_document != null)
                {
                    if (_document is IServiceProvider && CheckFlags(Flags.IsSelectionEnabled)) 
                    {
                        textContainer = ((IServiceProvider)_document).GetService(typeof(ITextContainer)) as ITextContainer; 
                    } 
                }
                return textContainer; 
            }
        }

        #endregion Private Properties 

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

        #region Private Fields
 
        private ReadOnlyCollection _pageViews;    // Collection of DocumentPageViews presenting paginated Document.
        private FrameworkElement _textEditorRenderScope;            // RenderScope associated with the TextEditor. 
        private MultiPageTextView _textView;                        // ITextView associated with DocumentViewer. 
        private TextEditor _textEditor;                             // TextEditor associated with DocumentViewer.
        private IDocumentPaginatorSource _document;                 // IDocumentPaginatorSource representing Document. 
        private Flags _flags;                                       // Flags reflecting various aspects of object's state.
#if !DONOTREFPRINTINGASMMETA
        private XpsDocumentWriter _documentWriter;                  // DocumentWriter used for printing.
#endif // DONOTREFPRINTINGASMMETA 

        private static bool IsEditingEnabled = false;               // A flag enabling text editing within a document viewer 
                                                                    // accessible only through reflection. 

        #endregion Private Fields 

        //--------------------------------------------------------------------
        //
        //  Private Types 
        //
        //-------------------------------------------------------------------- 
 
        #region Private Types
 
        /// 
        /// Flags reflecting various aspects of viewer's state.
        /// 
        [System.Flags] 
        private enum Flags
        { 
            // free bit                 = 0x10, 
            IsSelectionEnabled          = 0x20,     // Is text selection enabled.
            DocumentAsLogicalChild      = 0x40,     // Is Document part of logical tree. 
        }

        /// 
        /// State of BringIntoView operation. 
        /// 
        private class BringIntoViewState 
        { 
            internal BringIntoViewState(DocumentViewerBase source, ContentPosition contentPosition, DependencyObject targetObject, Rect targetRect)
            { 
                this.Source = source;
                this.ContentPosition = contentPosition;
                this.TargetObject = targetObject;
                this.TargetRect = targetRect; 
            }
            internal DocumentViewerBase Source; 
            internal ContentPosition ContentPosition; 
            internal DependencyObject TargetObject;
            internal Rect TargetRect; 
        }

        #endregion Private Types
 
        //-------------------------------------------------------------------
        // 
        //  IAddChild 
        //
        //-------------------------------------------------------------------- 

        #region IAddChild

        ///  
        /// Called to add the object as a Child.
        ///  
        /// Object to add as a child. 
        /// DocumentViewerBase only supports a single child of type IDocumentPaginatorSource.
        void IAddChild.AddChild(Object value) 
        {
            if (value == null)
            {
                throw new ArgumentNullException("value"); 
            }
            // Check if Content has already been set. 
            if (this.Document != null) 
            {
                throw new InvalidOperationException(SR.Get(SRID.DocumentViewerCanHaveOnlyOneChild)); 
            }
            // Only IDocumentPaginatorSource is a valid content.
            IDocumentPaginatorSource document = value as IDocumentPaginatorSource;
            if (document == null) 
            {
                throw new ArgumentException(SR.Get(SRID.DocumentViewerChildMustImplementIDocumentPaginatorSource), "value"); 
            } 
            this.Document = document;
        } 

        /// 
        /// Called when text appears under the tag in markup
        ///  
        /// Text to add to the Object.
        /// DocumentViewer does not support Text children. 
        void IAddChild.AddText(string text) 
        {
            XamlSerializerUtil.ThrowIfNonWhiteSpaceInAddText(text, this); 
        }

        #endregion IAddChild
 
        //-------------------------------------------------------------------
        // 
        //  IServiceProvider 
        //
        //------------------------------------------------------------------- 

        #region IServiceProvider

        ///  
        /// Returns service objects associated with this control.
        ///  
        /// Specifies the type of service object to get. 
        object IServiceProvider.GetService(Type serviceType)
        { 
            object service = null;
            if (serviceType == null)
            {
                throw new ArgumentNullException("serviceType"); 
            }
 
            // Following services are available: 
            // (1) TextView - wrapper for TextViews exposed by PageViews.
            // (2) TextContainer - the service object is retrieved from Document. 
            if (serviceType == typeof(ITextView))
            {
                service = _textView;
            } 
            else if (serviceType == typeof(TextContainer) || serviceType == typeof(ITextContainer))
            { 
                service = this.TextContainer; 
            }
            return service; 
        }

        #endregion IServiceProvider
    } 
}
#pragma warning enable 1634, 1691 
 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
//---------------------------------------------------------------------------- 
//
// Copyright (C) Microsoft Corporation.  All rights reserved.
//
// File: DocumentViewerBase.cs 
//
// Description: DocumentViewerBase is a minimal base class, providing only 
//              the functionality common across document viewing scenarios. 
//              The base class provides no user interface, very few properties,
//              and minimal policy. Functionality included in the base class: 
//              BringIntoView support & Print API services
//              and Annotation support.
//
//--------------------------------------------------------------------------- 
#pragma warning disable 1634, 1691  // avoid generating warnings about unknown
                                    // message numbers and unknown pragmas for PRESharp contol 
 
using System.Collections;               // IEnumerator
using System.Collections.Generic;       // List 
using System.Collections.ObjectModel;   // ReadOnlyCollection
using System.Security.Permissions;      // SecurityPermission
using System.Windows.Annotations;       // AnnotationService
using System.Windows.Automation;        // AutomationPattern 
using System.Windows.Automation.Peers;  // AutomationPeer
using System.Windows.Documents;         // IDocumentPaginatorSource, ... 
using System.Windows.Documents.Serialization;  // WritingCompletedEventArgs 
using System.Windows.Input;             // UICommand
using System.Windows.Media;             // Visual 
using System.Windows.Markup;            // IAddChild, XamlSerializerUtil, ContentPropertyAttribute
using System.Windows.Threading;         // DispatcherPriority
using System.Printing;                  // PrintQueue
using System.Windows.Xps;               // XpsDocumentWriter 
using MS.Internal;                      // Invariant, DoubleUtil
using MS.Internal.KnownBoxes;           // BooleanBoxes 
using MS.Internal.Annotations;          // TextAnchor 
using MS.Internal.Annotations.Anchoring;// DataIdProcessor, FixedPageProcessor, ...
using MS.Internal.Automation;           // TextAdaptor 
using MS.Internal.Documents;            // MultiPageTextView
using MS.Internal.Controls;             // EmptyEnumerator
using MS.Internal.Commands;             // CommandHelpers
 
namespace System.Windows.Controls.Primitives
{ 
    ///  
    /// DocumentViewerBase is a minimal base class, providing only the functionality
    /// common across document viewing scenarios. The base class provides no user 
    /// interface, very few properties, and minimal policy. Functionality included in
    /// the base class: BringIntoView support and Print API services
    /// and Annotation support.
    ///  
    [ContentProperty("Document")]
    public abstract class DocumentViewerBase : Control, IAddChild, IServiceProvider 
    { 
        //-------------------------------------------------------------------
        // 
        //  Constructors
        //
        //-------------------------------------------------------------------
 
        #region Constructors
 
        ///  
        /// Initializes class-wide settings.
        ///  
        static DocumentViewerBase()
        {
            // Create our CommandBindings
            CreateCommandBindings(); 

            // Register event handlers 
            EventManager.RegisterClassHandler(typeof(DocumentViewerBase), RequestBringIntoViewEvent, new RequestBringIntoViewEventHandler(HandleRequestBringIntoView)); 

            // Default value for AutoWordSelection is false.  We want true. 
            TextBoxBase.AutoWordSelectionProperty.OverrideMetadata(typeof(DocumentViewerBase), new FrameworkPropertyMetadata(true));
        }

        ///  
        /// Instantiates a new instance of a DocumentViewerBase.
        ///  
        protected DocumentViewerBase() 
            : base()
        { 
            _pageViews = new ReadOnlyCollection(new List());
            // By default text selection is enabled.
            SetFlags(true, Flags.IsSelectionEnabled);
        } 

        #endregion Constructors 
 
        //--------------------------------------------------------------------
        // 
        //  Public Methods
        //
        //-------------------------------------------------------------------
 
        #region Public Methods
 
        ///  
        /// Called when the Template's tree has been generated
        ///  
        /// Whether Visuals were added to the tree.
        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate(); 

            // Update collection of DocumentPageViews if the Visual tree has 
            // been updated through control template 
            UpdatePageViews();
        } 

        /// 
        /// Moves the master page to the previous page.
        ///  
        public void PreviousPage()
        { 
            OnPreviousPageCommand(); 
        }
 
        /// 
        /// Moves the master page to the next page.
        /// 
        public void NextPage() 
        {
            OnNextPageCommand(); 
        } 

        ///  
        /// Moves the master page to the first page.
        /// 
        public void FirstPage()
        { 
            OnFirstPageCommand();
        } 
 
        /// 
        /// Moves the master page to the last page. 
        /// 
        public void LastPage()
        {
            OnLastPageCommand(); 
        }
 
        ///  
        /// Moves the master page to the specified page.
        ///  
        /// 
        public void GoToPage(int pageNumber)
        {
            OnGoToPageCommand(pageNumber); 
        }
 
        ///  
        /// Invokes the Print Dialog. This is analogous to the ApplicationCommands.Print.
        ///  
        public void Print()
        {
            OnPrintCommand();
        } 

        ///  
        /// Cancels current printing job. This is analogous to the ApplicationCommands.CancelPrint. 
        /// 
        public void CancelPrint() 
        {
            OnCancelPrintCommand();
        }
 
        /// 
        /// Whether the master page can be moved to the specified page. 
        ///  
        /// Page number.
        public virtual bool CanGoToPage(int pageNumber) 
        {
            // Can navigate to a page, if:
            // a) the number is in valid range between 1 and PageCount, or
            // b) Paginator is set and pageNumber is PageCount+1. 
            return (pageNumber > 0 && pageNumber <= this.PageCount) ||
                ((_document != null) && (pageNumber - 1 == this.PageCount) && !_document.DocumentPaginator.IsPageCountValid); 
        } 

        #endregion Public Methods 

        //--------------------------------------------------------------------
        //
        //  Public Properties 
        //
        //-------------------------------------------------------------------- 
 
        #region Public Properties
 
        /// 
        /// The IDocumentPaginatorSource to be paginated and viewed.
        /// 
        public IDocumentPaginatorSource Document 
        {
            get { return _document; } 
            set { SetValue(DocumentProperty, value); } 
        }
 
        /// 
        /// The number of pages currently available for viewing. This value
        /// is updated as content is paginated, and will change dramatically
        /// when the content is resized, or edited. 
        /// 
        public int PageCount 
        { 
            get { return (int) GetValue(PageCountProperty); }
        } 

        /// 
        /// The one-based page number of the page being displayed on the master
        /// page DocumentPageView. If there is no content, this value will be 0. 
        /// 
        public virtual int MasterPageNumber 
        { 
            get { return (int) GetValue(MasterPageNumberProperty); }
        } 

        /// 
        /// Whether the viewer can move the master page to the previous page.
        ///  
        public virtual bool CanGoToPreviousPage
        { 
            get { return (bool) GetValue(CanGoToPreviousPageProperty); } 
        }
 
        /// 
        /// Whether the viewer can advance the master page to the next page.
        /// 
        public virtual bool CanGoToNextPage 
        {
            get { return (bool) GetValue(CanGoToNextPageProperty); } 
        } 

        ///  
        /// A read-only collection of the DocumentPageView objects contained
        /// within the viewer. These objects are manipulated by the viewer
        /// in order to display content.
        ///  
        [CLSCompliant(false)]
        public ReadOnlyCollection PageViews 
        { 
            get { return _pageViews; }
        } 

        #region Public Dynamic Properties

        /// \ 
        /// 
        ///  
        public static readonly DependencyProperty DocumentProperty = 
                DependencyProperty.Register(
                        "Document", 
                        typeof(IDocumentPaginatorSource),
                        typeof(DocumentViewerBase),
                        new FrameworkPropertyMetadata(
                                null, 
                                new PropertyChangedCallback(DocumentChanged)));
 
        ///  
        /// 
        ///  
        protected static readonly DependencyPropertyKey PageCountPropertyKey =
                DependencyProperty.RegisterReadOnly(
                        "PageCount",
                        typeof(int), 
                        typeof(DocumentViewerBase),
                        new FrameworkPropertyMetadata(0)); 
 
        /// 
        ///  
        /// 
        public static readonly DependencyProperty PageCountProperty =
                PageCountPropertyKey.DependencyProperty;
 
        /// 
        ///  
        ///  
        protected static readonly DependencyPropertyKey MasterPageNumberPropertyKey =
                DependencyProperty.RegisterReadOnly( 
                        "MasterPageNumber",
                        typeof(int),
                        typeof(DocumentViewerBase),
                        new FrameworkPropertyMetadata(0)); 

        ///  
        ///  
        /// 
        public static readonly DependencyProperty MasterPageNumberProperty = 
                MasterPageNumberPropertyKey.DependencyProperty;

        /// 
        ///  
        /// 
        protected static readonly DependencyPropertyKey CanGoToPreviousPagePropertyKey = 
                DependencyProperty.RegisterReadOnly( 
                        "CanGoToPreviousPage",
                        typeof(bool), 
                        typeof(DocumentViewerBase),
                        new FrameworkPropertyMetadata(BooleanBoxes.FalseBox));

        ///  
        /// 
        ///  
        public static readonly DependencyProperty CanGoToPreviousPageProperty = 
                CanGoToPreviousPagePropertyKey.DependencyProperty;
 
        /// 
        /// 
        /// 
        protected static readonly DependencyPropertyKey CanGoToNextPagePropertyKey = 
                DependencyProperty.RegisterReadOnly(
                        "CanGoToNextPage", 
                        typeof(bool), 
                        typeof(DocumentViewerBase),
                        new FrameworkPropertyMetadata(BooleanBoxes.FalseBox)); 

        /// 
        /// 
        ///  
        public static readonly DependencyProperty CanGoToNextPageProperty =
                CanGoToNextPagePropertyKey.DependencyProperty; 
 
        /// 
        /// Attached property used to signify which of the child DocumentPageView objects 
        /// is the master page. If more than one DocumentPageView has this value set,
        /// then the first tagged DocumentPageView in the tree (depth-first) is designated
        /// the master. If none of the children have this property set, then the depth-first
        /// PageView is designated the master. 
        /// 
        public static readonly DependencyProperty IsMasterPageProperty = 
                DependencyProperty.RegisterAttached( 
                        "IsMasterPage",
                        typeof(bool), 
                        typeof(DocumentViewerBase),
                        new FrameworkPropertyMetadata(BooleanBoxes.FalseBox));

        ///  
        /// DependencyProperty getter for  property.
        ///  
        /// The element from which to read the attached property. 
        public static bool GetIsMasterPage(DependencyObject element)
        { 
            if (element == null)
            {
                throw new ArgumentNullException("element");
            } 
            return (bool)element.GetValue(IsMasterPageProperty);
        } 
 
        /// 
        /// DependencyProperty setter for  property. 
        /// 
        /// The element to which to write the attached property.
        /// The property value to set
        public static void SetIsMasterPage(DependencyObject element, bool value) 
        {
            if (element == null) 
            { 
                throw new ArgumentNullException("element");
            } 
            element.SetValue(IsMasterPageProperty, value);
        }

        #endregion Public Dynamic Properties 

        #endregion Public Properties 
 
        //-------------------------------------------------------------------
        // 
        //  Public Events
        //
        //--------------------------------------------------------------------
 
        #region Public Events
 
        ///  
        /// Fired when collection of DocumentPageViews is changed.
        ///  
        public event EventHandler PageViewsChanged;

        #endregion Public Events
 
        //-------------------------------------------------------------------
        // 
        //  Protected Methods 
        //
        //------------------------------------------------------------------- 

        #region Protected Methods

        ///  
        /// Creates AutomationPeer ()
        ///  
        protected override AutomationPeer OnCreateAutomationPeer() 
        {
            return new DocumentViewerBaseAutomationPeer(this); 
        }

        /// 
        /// Invalidates the PageViews collection, triggering a call to GetPageViews. 
        /// 
        protected void InvalidatePageViews() 
        { 
            // Update collection of DocumentPageViews if  the collection has
            // been explicitly invalidated. 
            UpdatePageViews();
            InvalidateMeasure();
        }
 
        /// 
        /// Returns the master DocumentPageView. 
        ///  
        protected DocumentPageView GetMasterPageView()
        { 
            int index;
            DocumentPageView masterPageView = null;

            // Search for the first element with IsMasterPage property set. 
            for (index = 0; index < _pageViews.Count; index++)
            { 
                if (GetIsMasterPage(_pageViews[index])) 
                {
                    masterPageView = _pageViews[index]; 
                    break;
                }
            }
            // If none of the DocumentPageViews have this property set, 
            // then use the first one in the collection.
            if (masterPageView == null) 
            { 
                masterPageView = _pageViews.Count > 0 ? _pageViews[0] : null;
            } 
            return masterPageView;
        }

        ///  
        /// Creates a collection of DocumentPageView objects used to display Document.
        ///  
        /// True if the collection is different than the public PageViews collection. 
        /// Collection of DocumentPageView objects used to display Document.
        protected virtual ReadOnlyCollection GetPageViewsCollection(out bool changed) 
        {
            List pageViewList;
            AdornerDecorator adornerDecorator;
 
            // By default retrieve all DocumentPageViews from style.
            pageViewList = new List(1/* simplest case has just one element */); 
            FindDocumentPageViews(this, pageViewList); 

            // By default use AdornerDecorator.Child as RenderScope for TextEditor. Retieve 
            // AdornerDecorator from the style.
            adornerDecorator = FindAdornerDecorator(this);
            this.TextEditorRenderScope = (adornerDecorator != null) ? (adornerDecorator.Child as FrameworkElement) : null;
 
            // Since existing DocumentPageViews are being replaced, need to disconnect
            // them from the Document. 
            for (int index = 0; index < _pageViews.Count; index++) 
            {
                _pageViews[index].DocumentPaginator = null; 
            }

            changed = true;
            return new ReadOnlyCollection(pageViewList); 
        }
 
        ///  
        /// Called when the PageViews collection is modified; this occurs when GetPageViews
        /// returns True or if the control's template is modified. 
        /// 
        protected virtual void OnPageViewsChanged()
        {
            // Raise notification about change to DocumentPageView collection. 
            if (this.PageViewsChanged != null)
            { 
                this.PageViewsChanged(this, EventArgs.Empty); 
            }
            // Change of DocumentPageView collection may cause invalidation of content 
            // represented by DocumentPageViews.
            OnMasterPageNumberChanged();
        }
 
        /// 
        /// Called when the MasterPageNumber property is changed, this occurs when the 
        /// developer manually sets the property, or when the FirstPage, NextPage, 
        /// etc commands are executed.
        ///  
        protected virtual void OnMasterPageNumberChanged()
        {
            // Invalidation of MasterPage invalidates following properties:
            //      - MasterPageNumber 
            //      - CanGoToPreviousPage
            //      - CanGoToNextPage 
            UpdateReadOnlyProperties(true, true); 
        }
 
        /// 
        /// 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 virtual void OnBringIntoView(DependencyObject element, Rect rect, int pageNumber) 
        {
            if (element == null)
            {
                throw new ArgumentNullException("element"); 
            }
            OnGoToPageCommand(pageNumber); 
        } 

        ///  
        /// Handler for the PreviousPage command.
        /// 
        protected virtual void OnPreviousPageCommand()
        { 
            // If can go to the previous page, shift all pages
            // by decrementing page number by 1. 
            if (this.CanGoToPreviousPage) 
            {
                ShiftPagesByOffset(-1); 
            }
        }

        ///  
        /// Handler for the NextPage command.
        ///  
        protected virtual void OnNextPageCommand() 
        {
            // If can go to the next page, shift all pages 
            // by incrementing page number by 1.
            if (this.CanGoToNextPage)
            {
                ShiftPagesByOffset(1); 
            }
        } 
 
        /// 
        /// Handler for the FirstPage command. 
        /// 
        protected virtual void OnFirstPageCommand()
        {
            // Navigate the master page to the first one and shift 
            // all remaining pages by delta.
            ShiftPagesByOffset(1 - this.MasterPageNumber); 
        } 

        ///  
        /// Handler for the LastPage command.
        /// 
        protected virtual void OnLastPageCommand()
        { 
            // Navigate the master page to the last one and shift
            // all remaining pages by delta. 
            ShiftPagesByOffset(this.PageCount - this.MasterPageNumber); 
        }
 
        /// 
        /// Handler for the GoToPage command.
        /// 
        ///  
        protected virtual void OnGoToPageCommand(int pageNumber)
        { 
            // Check if can go to the specified page. 
            // Navigate the master page to specified page number and shift
            // all remaining pages by delta. 
            if (CanGoToPage(pageNumber))
            {
                ShiftPagesByOffset(pageNumber - this.MasterPageNumber);
            } 
        }
 
        ///  
        /// Handler for the Print command.
        ///  
        protected virtual void OnPrintCommand()
        {
#if !DONOTREFPRINTINGASMMETA
            XpsDocumentWriter docWriter; 
            PrintDocumentImageableArea ia = null;
 
            // Only one printing job is allowed. 
            if (_documentWriter != null)
            { 
                return;
            }

            if (_document != null) 
            {
                // Show print dialog. 
                docWriter = PrintQueue.CreateXpsDocumentWriter(ref ia); 
                if (docWriter != null && ia != null)
                { 
                    // Register for WritingCompleted event.
                    _documentWriter = docWriter;
                    _documentWriter.WritingCompleted += new WritingCompletedEventHandler(HandlePrintCompleted);
                    _documentWriter.WritingCancelled += new WritingCancelledEventHandler(HandlePrintCancelled); 

                    // Since _documentWriter value is used to determine CanExecute state, we must invalidate that state. 
                    CommandManager.InvalidateRequerySuggested(); 

                    // Write to the PrintQueue 
                    if( _document is FixedDocumentSequence )
                    {
                        docWriter.WriteAsync(_document as FixedDocumentSequence);
                    } 
                    else if( _document is FixedDocument )
                    { 
                        docWriter.WriteAsync(_document as FixedDocument); 
                    }
                    else 
                    {
                        docWriter.WriteAsync(_document.DocumentPaginator);
                    }
                } 
            }
#endif // DONOTREFPRINTINGASMMETA 
        } 

        ///  
        /// Handler for the CancelPrint command.
        /// 
        protected virtual void OnCancelPrintCommand()
        { 
#if !DONOTREFPRINTINGASMMETA
            if (_documentWriter != null) 
            { 
                _documentWriter.CancelAsync();
            } 
#endif // DONOTREFPRINTINGASMMETA
        }

        ///  
        /// Called when the Document property is changed.
        ///  
        protected virtual void OnDocumentChanged() 
        {
            int index; 

            // Document has been changed. Update existing DocumentPageViews to point them to the new Document.
            for (index = 0; index < _pageViews.Count; index++)
            { 
                _pageViews[index].DocumentPaginator = (_document != null) ? _document.DocumentPaginator : null;
            } 
 
            // Document invalidation invalidates following properties:
            //      - PageCount 
            //      - MasterPageNumber
            //      - CanGoToPreviousPage
            //      - CanGoToNextPage
            UpdateReadOnlyProperties(true, true); 

            // Attach TextEditor, if content supports it. This method will also 
            // detach TextEditor from old content. 
            AttachTextEditor();
        } 

        #endregion Protected Methods

        //------------------------------------------------------------------- 
        //
        //  Protected Properties 
        // 
        //--------------------------------------------------------------------
 
        #region Protected Properties

        /// 
        /// Returns enumerator to logical children. 
        /// 
        protected internal override IEnumerator LogicalChildren 
        { 
            get
            { 
                if (this.HasLogicalChildren && _document != null)
                {
                    return new SingleChildEnumerator(_document);
                } 
                return EmptyEnumerator.Instance;
            } 
        } 

        #endregion Protected Properties 

        //-------------------------------------------------------------------
        //
        //  Internal Methods 
        //
        //-------------------------------------------------------------------- 
 
        #region Internal Methods
 
        /// 
        /// Determines whether DocumentPageView is a master page.
        /// 
        /// Instance of DocumentPageView. 
        /// Whether given instance of DocumentPageView is a master page.
        internal bool IsMasterPageView(DocumentPageView pageView) 
        { 
            Invariant.Assert(pageView != null);
            return (pageView == GetMasterPageView()); 
        }

        /// 
        /// Invoked when the "Find" button in the Find Toolbar is clicked. 
        /// This method invokes the actual Find process.
        ///  
        internal ITextRange Find(FindToolBar findToolBar) 
        {
            ITextView masterPageTextView = null; 
            DocumentPageView masterPage = GetMasterPageView();
            if (masterPage != null && masterPage is IServiceProvider)
            {
                masterPageTextView = ((IServiceProvider)masterPage).GetService(typeof(ITextView)) as ITextView; 
            }
            return DocumentViewerHelper.Find(findToolBar, _textEditor, _textView, masterPageTextView); 
        } 

        #endregion Internal Methods 

        //--------------------------------------------------------------------
        //
        //  Internal Properties 
        //
        //------------------------------------------------------------------- 
 
        #region Internal Properties
 
        /// 
        /// Whether text selection is enabled or disabled.
        /// 
        internal bool IsSelectionEnabled 
        {
            get { return CheckFlags(Flags.IsSelectionEnabled); } 
            set 
            {
                SetFlags(value, Flags.IsSelectionEnabled); 
                AttachTextEditor();
            }
        }
 
        /// 
        /// TextEditor instance. 
        ///  
        internal TextEditor TextEditor
        { 
            get { return _textEditor; }
        }

        ///  
        /// Allows overriding the RenderScope used by the TextEditor.
        ///  
        internal FrameworkElement TextEditorRenderScope 
        {
            get 
            {
                return _textEditorRenderScope;
            }
            set 
            {
                _textEditorRenderScope = value; 
                AttachTextEditor(); 
            }
        } 

        #endregion Internal Properties

        //-------------------------------------------------------------------- 
        //
        //  Private Methods 
        // 
        //-------------------------------------------------------------------
 
        #region Private Methods

        /// 
        /// Retrieves an ITextPointer from the MasterPage. 
        /// If startOfPage is true, then we will retreive the first
        /// TextPointer in the first TextSegment in the DocumentPageTextView. 
        /// Else, we will retreive the last TextPointer in the last TextSegment 
        /// of the MasterPage DocumentPageTextView.
        ///  
        /// 
        /// 
        private ITextPointer GetMasterPageTextPointer(bool startOfPage)
        { 
            ITextPointer masterPointer = null;
            ITextView textView = null; 
            DocumentPageView masterPage = GetMasterPageView(); 

            if (masterPage != null && masterPage is IServiceProvider) 
            {
                textView = ((IServiceProvider)masterPage).GetService(typeof(ITextView)) as ITextView;
                if (textView != null && textView.IsValid)
                { 
                    // Find the very first/(last) text pointer in this textView.
                    foreach (TextSegment textSegment in textView.TextSegments) 
                    { 
                        if (textSegment.IsNull)
                        { 
                            continue;
                        }

                        if (masterPointer == null) 
                        {
                            // Set initial masterPointer value. 
                            masterPointer = startOfPage ? textSegment.Start : textSegment.End; 
                        }
                        else 
                        {
                            if (startOfPage)
                            {
                                if (textSegment.Start.CompareTo(masterPointer) < 0) 
                                {
                                    // Start is before the current masterPointer 
                                    masterPointer = textSegment.Start; 
                                }
                            } 
                            else
                            {
                                // end is after than the current masterPointer
                                if (textSegment.End.CompareTo(masterPointer) > 0) 
                                {
                                    masterPointer = textSegment.End; 
                                } 
                            }
                        } 
                    }
                }
            }
 
            return masterPointer;
        } 
 
        /// 
        /// Update collection of DocumentPageViews in responce to Visual tree changes. 
        /// 
        /// Whether collection of DocumentPageViews has been updated.
        private void UpdatePageViews()
        { 
            int index;
            bool changed; 
            ReadOnlyCollection pageViews; 

            // Get collection of new DocumentPageViews. 
            pageViews = GetPageViewsCollection(out changed);

            // If DocumentPageViews collection has not been changed, there is nothing to update.
            if (changed) 
            {
                // Verify collection of DocumentPageViews. It needs to meet following conditions: 
                // a) at least one DocumentPageView, 
                // b) only one page has IsMasterPage property set to true,
                // c) unique PageNumbers for each active DocumentPageView, 
                VerifyDocumentPageViews(pageViews);

                // New collection of DocumentPageViews is replacing the old one. Point new
                // DocumentPageViews to the Document. 
                _pageViews = pageViews;
                for (index = 0; index < _pageViews.Count; index++) 
                { 
                    _pageViews[index].DocumentPaginator = (_document != null) ? _document.DocumentPaginator : null;
                } 

                // Collection of DocumentPageView has been changed. Need to update
                // TextView, if one already exists.
                if (_textView != null) 
                {
                    _textView.OnPagesUpdated(); 
                } 

                // DocumentPageViews collection has been changed. Notify all listeners 
                // and/or derived classes about this fact.
                OnPageViewsChanged();
            }
        } 

        ///  
        /// Verify collection of DocumentPageViews. It needs to meet following conditions: 
        /// a) collection is not null,
        /// b) only one page has IsMasterPage property set to true, 
        /// c) unique PageNumbers for each active DocumentPageView,
        /// 
        /// Collection of DocumentPageViews to validate.
        private void VerifyDocumentPageViews(ReadOnlyCollection pageViews) 
        {
            int index; 
            bool hasMasterPage = false; 

            // At least one DocumentPageView is required. 
            if (pageViews == null)
            {
                throw new ArgumentException(SR.Get(SRID.DocumentViewerPageViewsCollectionEmpty));
            } 

            // Expecting only one DocumentPageView with IsMasterPage property set to true. 
            for (index = 0; index < pageViews.Count; index++) 
            {
                if (GetIsMasterPage(pageViews[index])) 
                {
                    if (hasMasterPage)
                    {
                        throw new ArgumentException(SR.Get(SRID.DocumentViewerOneMasterPage)); 
                    }
                    hasMasterPage = true; 
                } 
            }
 
            // Unique PageNumbers for each active DocumentPageView.
        }

        ///  
        /// Does deep Visual tree walk to retrieve all DocumentPageViews.
        /// It stops recursing down into visual tree in following situations: 
        /// a) Visual is UIElement and it is not part of Contol Template, 
        /// b) Visual is DocumentPageView.
        ///  
        /// FrameworkElement that is part of Control Template.
        /// Collection of DocumentPageViews; found elements are appended here.
        /// Whether collection of DocumentPageViews has been updated.
        private void FindDocumentPageViews(Visual root, List pageViews) 
        {
            Invariant.Assert(root != null); 
            Invariant.Assert(pageViews != null); 

            FrameworkElement fe; 
            // Do deep tree walk to retrieve all DocumentPageViews.
            // It stops recursing down into visual tree in following situations:
            // a) Visual is UIElement and it is not part of Contol Template,
            // b) Visual is DocumentPageView. 
            // Add to collection any DocumentPageViews found in the Control Template.
            int count = root.InternalVisualChildrenCount; 
            for(int i = 0; i < count; i++) 
            {
                Visual child = root.InternalGetVisualChild(i); 
                fe = child as FrameworkElement;
                if (fe != null)
                {
                    if (fe.TemplatedParent != null) 
                    {
                        if (fe is DocumentPageView) 
                        { 
                            pageViews.Add(fe as DocumentPageView);
                        } 
                        else
                        {
                            FindDocumentPageViews(fe, pageViews);
                        } 
                    }
                } 
                else 
                {
                    FindDocumentPageViews(child, pageViews); 
                }
            }
        }
 
        /// 
        /// Does deep Visual tree walk to retrieve an AdornerDecorator. Because 
        /// AdornerDecorator is supposed to cover all DocumentPageViews, it stops 
        /// recursing down into visual tree in following situations:
        /// a) Visual is UIElement and it is not part of Contol Template, 
        /// b) Visual is DocumentPageView.
        /// c) Visual is AdornerDecorator.
        /// 
        /// FrameworkElement that is part of Control Template. 
        /// AdornerDecorator, if found.
        private AdornerDecorator FindAdornerDecorator(Visual root) 
        { 
            Invariant.Assert(root != null);
 
            FrameworkElement fe;
            AdornerDecorator adornerDecorator = null;

            // Do deep Visual tree walk to retrieve an AdornerDecorator. Because 
            // AdornerDecorator is supposed to cover all DocumentPageViews, it stops
            // recursing down into visual tree in following situations: 
            // a) Visual is UIElement and it is not part of Contol Template, 
            // b) Visual is DocumentPageView.
            // c) Visual is AdornerDecorator. 
            int count = root.InternalVisualChildrenCount;
            for(int i = 0; i < count; i++)
            {
                Visual child = root.InternalGetVisualChild(i); 
                fe = child as FrameworkElement;
                if (fe != null) 
                { 
                    if (fe.TemplatedParent != null)
                    { 
                        if (fe is AdornerDecorator)
                        {
                            adornerDecorator = (AdornerDecorator)fe;
                        } 
                        else if (!(fe is DocumentPageView))
                        { 
                            adornerDecorator = FindAdornerDecorator(fe); 
                        }
                        // else stop on DocumentPageView 
                    }
                }
                else
                { 
                    adornerDecorator = FindAdornerDecorator(child);
                } 
                if (adornerDecorator != null) 
                {
                    break; 
                }
            }
            return adornerDecorator;
        } 

        ///  
        /// Attach TextEditor to Document, if supports text. 
        /// 
        private void AttachTextEditor() 
        {
            AnnotationService service = AnnotationService.GetService(this);
            ITextContainer textContainer;
 
            // This method is called when Document is changing, so need
            // to clear old TextEditor data. 
            if (_textEditor != null) 
            {
                _textEditor.OnDetach(); 
                _textEditor = null;
                if (_textView.TextContainer.TextView == _textView)
                {
                    _textView.TextContainer.TextView = null; 
                }
                _textView = null; 
            } 

            if (service != null) 
            {
                // Must be enabled - otherwise it won't be on the tree
                service.Disable();
            } 

            // If new Document supports TextEditor, create one. 
            // If the Document is already attached to TextEditor (TextSelection != null), 
            // do not create TextEditor for this instance of the viewer. (This situation may happen
            // when the same instance of Document is attached to more than one viewer). 
            textContainer = this.TextContainer;
            if (textContainer != null && this.TextEditorRenderScope != null && textContainer.TextSelection == null)
            {
                _textView = new MultiPageTextView(this, this.TextEditorRenderScope, textContainer); 
                _textEditor = new TextEditor(textContainer, this, false);
                _textEditor.IsReadOnly = !IsEditingEnabled; 
                _textEditor.TextView = _textView; 
                textContainer.TextView = _textView;
            } 

            // Re-enable the service in order to register on the new TextView
            if (service != null)
            { 
                service.Enable(service.Store);
            } 
        } 

        ///  
        /// Called when WritingCompleted event raised by a DocumentWriter (during printing).
        /// 
        /// Sender of the event.
        /// Event arguments. 
        private void HandlePrintCompleted(object sender, WritingCompletedEventArgs e)
        { 
            CleanUpPrintOperation(); 
        }
 
        /// 
        /// Called when WritingCancelled event raised by a DocumentWriter (during printing).
        /// 
        /// Sender of the event. 
        /// Event arguments.
        private void HandlePrintCancelled(object sender, WritingCancelledEventArgs e) 
        { 
            CleanUpPrintOperation();
        } 

        /// 
        /// Handler for PaginationCompleted event raised by the Document.
        ///  
        private void HandlePaginationCompleted(object sender, EventArgs e)
        { 
            // PaginationCompleted may invalidate following properties: 
            //      - PageCount
            //      - CanGoToNextPage 
            UpdateReadOnlyProperties(true, false);
        }

        ///  
        /// Handler for PaginationProgress event raised by the Document.
        ///  
        private void HandlePaginationProgress(object sender, EventArgs e) 
        {
            // PaginationProgress may invalidate following properties: 
            //      - PageCount
            //      - CanGoToNextPage
            UpdateReadOnlyProperties(true, false);
        } 

        ///  
        /// Handler for GetPageNumberCompleted event raised by the Document. 
        /// 
        private void HandleGetPageNumberCompleted(object sender, GetPageNumberCompletedEventArgs e) 
        {
            BringIntoViewState bringIntoViewState;

            // At this point the Document's page count might have changed, 
            // so update properties accordingly.
            UpdateReadOnlyProperties(true, false); 
 
            if (_document != null && sender == _document.DocumentPaginator && e != null)
            { 
                if (!e.Cancelled && (e.Error == null))
                {
                    bringIntoViewState = e.UserState as BringIntoViewState;
                    if (bringIntoViewState != null && bringIntoViewState.Source == this) 
                    {
                        OnBringIntoView(bringIntoViewState.TargetObject, bringIntoViewState.TargetRect, e.PageNumber + 1); 
                    } 
                }
            } 
        }

        /// 
        /// Makes sure the target is visible in the client area. May cause navigation 
        /// to a different page.
        ///  
        /// RequestBringIntoViewEventArgs indicates the element and region to scroll into view. 
        private void HandleRequestBringIntoView(RequestBringIntoViewEventArgs args)
        { 
            DependencyObject child;
            DependencyObject parent;
            ContentPosition contentPosition;
            BringIntoViewState bringIntoViewState; 
            DynamicDocumentPaginator documentPaginator;
            Rect targetRect = Rect.Empty; 
 
            if (args != null && args.TargetObject != null && _document is DependencyObject)
            { 
                // If the passed in object is a logical child of DocumentViewer's Document,
                // attempt to make it visible now.
                // Special case: TargetObject is the document itself. Then scroll to the top (page 1).
                // This supports navigating from baseURI#anchor to just baseURI. 
                parent = _document as DependencyObject;
                if (args.TargetObject == _document) 
                { 
                    OnGoToPageCommand(1);
                    args.Handled = true; // Mark the event as handled. 
                }
                else
                {
                    // Verify if TargetObject is in fact a child of Document. 
                    child = args.TargetObject;
                    while (child != null && child != parent) 
                    { 
                        // Skip elements in the control's template (if such exists) and
                        // walk up logical tree to find if the focused element is within 
                        // the document.
                        FrameworkElement fe = child as FrameworkElement;
                        if (fe != null && fe.TemplatedParent != null)
                        { 
                            child = fe.TemplatedParent;
                        } 
                        else 
                        {
                            child = LogicalTreeHelper.GetParent(child); 
                        }
                    }

                    if (child != null) 
                    {
                        // Special case UIElements already connected to visual tree. 
                        if (args.TargetObject is UIElement) 
                        {
                            UIElement targetObject = (UIElement)args.TargetObject; 
                            if (VisualTreeHelper.IsAncestorOf(this, targetObject))
                            {
                                targetRect = args.TargetRect;
                                if (targetRect.IsEmpty) 
                                {
                                    targetRect = new Rect(targetObject.RenderSize); 
                                } 
                                GeneralTransform transform = targetObject.TransformToAncestor(this);
                                targetRect = transform.TransformBounds(targetRect); 
                                targetRect.IntersectsWith(new Rect(this.RenderSize));
                            }
                        }
 
                        // If target is not already visible, bring appropriate page into view.
                        if (targetRect.IsEmpty) 
                        { 
                            // Get content position for given target.
                            documentPaginator = _document.DocumentPaginator as DynamicDocumentPaginator; 
                            if (documentPaginator != null)
                            {
                                contentPosition = documentPaginator.GetObjectPosition(args.TargetObject);
                                if (contentPosition != null && contentPosition != ContentPosition.Missing) 
                                {
                                    // Asynchronously retrieve PageNumber for given ContentPosition. 
                                    bringIntoViewState = new BringIntoViewState(this, contentPosition, args.TargetObject, args.TargetRect); 
                                    documentPaginator.GetPageNumberAsync(contentPosition, bringIntoViewState);
                                } 
                            }
                        }
                        args.Handled = true; // Mark the event as handled.
                    } 
                }
                if (args.Handled) 
                { 
                    // Create new BringIntoView request for this element, so
                    // if there is an ancestor handling BringIntoView, it can 
                    // react appropriately and bring this element into view.
                    if (targetRect.IsEmpty)
                    {
                        BringIntoView(); 
                    }
                    else 
                    { 
                        BringIntoView(targetRect);
                    } 
                }
            }
        }
 
        /// 
        /// Update values for readonly properties. 
        ///  
        /// Whether PageCount has been changed.
        /// Whether MasterPageNumber has been changed. 
        private void UpdateReadOnlyProperties(bool pageCountChanged, bool masterPageChanged)
        {
            if (pageCountChanged)
            { 
                SetValue(PageCountPropertyKey, (_document != null) ? _document.DocumentPaginator.PageCount : 0);
            } 
 
            bool invalidateRequery = false;
 
            if (masterPageChanged)
            {
                int masterPageNumber = 0;
                DocumentPageView masterPageView; 
                if (_document != null && _pageViews.Count > 0)
                { 
                    masterPageView = GetMasterPageView(); 
                    if (masterPageView != null)
                    { 
                        masterPageNumber = masterPageView.PageNumber + 1;
                    }
                }
 
                SetValue(MasterPageNumberPropertyKey, masterPageNumber);
                SetValue(CanGoToPreviousPagePropertyKey, MasterPageNumber > 1); 
 
                invalidateRequery = true;
            } 

            if (pageCountChanged || masterPageChanged)
            {
                bool canGoToNextPage = false; 
                if (_document != null)
                { 
                    canGoToNextPage = (MasterPageNumber < _document.DocumentPaginator.PageCount) || !_document.DocumentPaginator.IsPageCountValid; 
                }
                SetValue(CanGoToNextPagePropertyKey, canGoToNextPage); 

                invalidateRequery = true;
            }
 
            if(invalidateRequery)
            { 
                CommandManager.InvalidateRequerySuggested(); 
            }
        } 

        /// 
        /// Shift all pages by specified offset.
        ///  
        private void ShiftPagesByOffset(int offset)
        { 
            int index; 
            if (offset != 0)
            { 
                for (index = 0; index < _pageViews.Count; index++)
                {
                    _pageViews[index].PageNumber += offset;
                } 
                // Change of PageNumber property on DocumentPageViews will cause
                // invalidation of content represented by DocumentPageViews. 
                OnMasterPageNumberChanged(); 
            }
        } 

        /// 
        /// Sets or unsets one or multiple flags.
        ///  
        /// Whether flag or flags are set or cleared.
        /// Combination of flags to change. 
        private void SetFlags(bool value, Flags flags) 
        {
            _flags = value ? (_flags | flags) : (_flags & (~flags)); 
        }

        /// 
        /// Returns true if all of passed flags in the bitmask are set. 
        /// 
        /// Combination of flags to get the value. 
        /// Returns true if all of passed flags in the bitmask are set. 
        private bool CheckFlags(Flags flags)
        { 
            return ((_flags & flags) == flags);
        }

        ///  
        /// The Document has changed and needs to be updated.
        ///  
        private void DocumentChanged(IDocumentPaginatorSource oldDocument, IDocumentPaginatorSource newDocument) 
        {
            DependencyObject doDocument; 
            DynamicDocumentPaginator dynamicDocumentPaginator;
            _document = newDocument;

            // Cleanup state associated with the old document. 
            if (oldDocument != null)
            { 
                // If Document was added to logical tree of DocumentViewer before, remove it. 
                if (CheckFlags(Flags.DocumentAsLogicalChild))
                { 
                    RemoveLogicalChild(oldDocument);
                }
                // Unregister from PaginationProgress and PaginationCompleted events.
                dynamicDocumentPaginator = oldDocument.DocumentPaginator as DynamicDocumentPaginator; 
                if (dynamicDocumentPaginator != null)
                { 
                    dynamicDocumentPaginator.PaginationProgress -= new PaginationProgressEventHandler(HandlePaginationProgress); 
                    dynamicDocumentPaginator.PaginationCompleted -= new EventHandler(HandlePaginationCompleted);
                    dynamicDocumentPaginator.GetPageNumberCompleted -= new GetPageNumberCompletedEventHandler(HandleGetPageNumberCompleted); 
                }

                DependencyObject depObj = oldDocument as DependencyObject;
                if (depObj != null) 
                {
                    depObj.ClearValue(PathNode.HiddenParentProperty); 
                } 
            }
 
            // If DocumentViewer was created through style, then do not modify
            // the logical tree. Instead, set "core parent" for the Document.
            doDocument = _document as DependencyObject;
 	        if (doDocument != null && LogicalTreeHelper.GetParent(doDocument) != null && doDocument is ContentElement) 
            {
                // Set the "core parent" back to us. 
                ContentOperations.SetParent((ContentElement)doDocument, this); 
                SetFlags(false, Flags.DocumentAsLogicalChild);
            } 
            else
            {
                SetFlags(true, Flags.DocumentAsLogicalChild);
            } 

            // Initialize state associated with the new document. 
            if (_document != null) 
            {
                // If Document should be part of DocumentViewer's logical tree, add it. 
                if (CheckFlags(Flags.DocumentAsLogicalChild))
                {
                    AddLogicalChild(_document);
                } 
                // Register for PaginationProgress and PaginationCompleted events.
                dynamicDocumentPaginator = _document.DocumentPaginator as DynamicDocumentPaginator; 
                if (dynamicDocumentPaginator != null) 
                {
                    dynamicDocumentPaginator.PaginationProgress += new PaginationProgressEventHandler(HandlePaginationProgress); 
                    dynamicDocumentPaginator.PaginationCompleted += new EventHandler(HandlePaginationCompleted);
                    dynamicDocumentPaginator.GetPageNumberCompleted += new GetPageNumberCompletedEventHandler(HandleGetPageNumberCompleted);
                }
 
                // Setup DPs and processors for annotation handling.  If the service isn't already
                // enabled the processors will be registered by the service when it is enabled. 
                FlowDocument flowDocument; 
                DependencyObject doc = _document as DependencyObject;
                if (_document is FixedDocument || _document is FixedDocumentSequence) 
                {
                    // Clear properties that aren't needed for FixedDocument
                    this.ClearValue(AnnotationService.DataIdProperty);
                    // Setup service to look for FixedPages in the content 
                    AnnotationService.SetSubTreeProcessorId(this, FixedPageProcessor.Id);
                    // Tell the content how to get to its parent DocumentViewer 
                    doc.SetValue(PathNode.HiddenParentProperty, this); 
                    // If the service is already registered, set it up for fixed content
                    AnnotationService service = AnnotationService.GetService(this); 
                    if (service != null)
                    {
                        service.LocatorManager.RegisterSelectionProcessor(new FixedTextSelectionProcessor(), typeof(TextRange));
                        service.LocatorManager.RegisterSelectionProcessor(new FixedTextSelectionProcessor(), typeof(TextAnchor)); 
                    }
                } 
                else if ((flowDocument = _document as FlowDocument) != null) 
                {
                    // Tell the content how to get to its parent DocumentViewer 
                    flowDocument.SetValue(PathNode.HiddenParentProperty, this);
                    // If the service is already registered, set it up for fixed content
                    AnnotationService service = AnnotationService.GetService(this);
                    if (service != null) 
                    {
                        service.LocatorManager.RegisterSelectionProcessor(new TextSelectionProcessor(), typeof(TextRange)); 
                        service.LocatorManager.RegisterSelectionProcessor(new TextSelectionProcessor(), typeof(TextAnchor)); 
                        service.LocatorManager.RegisterSelectionProcessor(new TextViewSelectionProcessor(), typeof(DocumentViewerBase));
                    } 
                    // Setup service to use DataID processor
                    AnnotationService.SetDataId(this, "FlowDocument");
                }
                else 
                {
                    // Clear values that were set directly on the tree - only valid for Fixed or Flow Documents 
                    this.ClearValue(AnnotationService.SubTreeProcessorIdProperty); 
                    this.ClearValue(AnnotationService.DataIdProperty);
                } 
            }

            // Document is also represented as Automation child. Need to invalidate peer to force update.
            DocumentViewerBaseAutomationPeer peer = UIElementAutomationPeer.FromElement(this) as DocumentViewerBaseAutomationPeer; 
            if (peer != null)
            { 
                peer.InvalidatePeer(); 
            }
 
            // Respond to Document change - update state that is affected by this change.
            OnDocumentChanged();
        }
 
        /// 
        /// Cleans up after a print operation by unregistering for events and re-enabling buttons. 
        ///  
        private void CleanUpPrintOperation()
        { 
#if !DONOTREFPRINTINGASMMETA
            if (_documentWriter != null)
            {
                _documentWriter.WritingCompleted -= new WritingCompletedEventHandler(HandlePrintCompleted); 
                _documentWriter.WritingCancelled -= new WritingCancelledEventHandler(HandlePrintCancelled);
                _documentWriter = null; 
 
                // Since _documentWriter value is used to determine CanExecute state, we must invalidate that state.
                CommandManager.InvalidateRequerySuggested(); 
            }
#endif // DONOTREFPRINTINGASMMETA
        }
 
        #region Commands
 
        ///  
        /// Set up Command and RoutedCommand bindings.
        ///  
        private static void CreateCommandBindings()
        {
            ExecutedRoutedEventHandler executedHandler;
            CanExecuteRoutedEventHandler canExecuteHandler; 

            // Create our generic ExecutedRoutedEventHandler. 
            executedHandler = new ExecutedRoutedEventHandler(ExecutedRoutedEventHandler); 
            // Create our generic QueryEnabledStatusHandler
            canExecuteHandler = new CanExecuteRoutedEventHandler(CanExecuteRoutedEventHandler); 

            // Command: NavigationCommands.PreviousPage
            CommandHelpers.RegisterCommandHandler(typeof(DocumentViewerBase), NavigationCommands.PreviousPage,
                executedHandler, canExecuteHandler); // no key gesture 

            // Command: NavigationCommands.NextPage 
            CommandHelpers.RegisterCommandHandler(typeof(DocumentViewerBase), NavigationCommands.NextPage, 
                executedHandler, canExecuteHandler); // no key gesture
 
            // Command: NavigationCommands.FirstPage
            CommandHelpers.RegisterCommandHandler(typeof(DocumentViewerBase), NavigationCommands.FirstPage,
                executedHandler, canExecuteHandler); // no key gesture
 
            // Command: NavigationCommands.LastPage
            CommandHelpers.RegisterCommandHandler(typeof(DocumentViewerBase), NavigationCommands.LastPage, 
                executedHandler, canExecuteHandler); // no key gesture 

            // Command: NavigationCommands.GoToPage 
            CommandHelpers.RegisterCommandHandler(typeof(DocumentViewerBase), NavigationCommands.GoToPage,
                executedHandler, canExecuteHandler); // no key gesture

            // Command: ApplicationCommands.Print 
            CommandHelpers.RegisterCommandHandler(typeof(DocumentViewerBase), ApplicationCommands.Print,
                executedHandler, canExecuteHandler, new KeyGesture(Key.P, ModifierKeys.Control)); 
 
            // Command: ApplicationCommands.CancelPrint
            CommandHelpers.RegisterCommandHandler(typeof(DocumentViewerBase), ApplicationCommands.CancelPrint, 
                executedHandler, canExecuteHandler); // no key gesture

            // Register editing command handlers - After our commands to let editor handle them first
            TextEditor.RegisterCommandHandlers(typeof(DocumentViewerBase), /*acceptsRichContent:*/true, /*readOnly:*/!IsEditingEnabled, /*registerEventListeners*/true); 
        }
 
        ///  
        /// Central handler for CanExecuteRouted events fired by Commands directed at DocumentViewerBase.
        ///  
        /// The target of this Command, expected to be DocumentViewerBase
        /// The event arguments for this event.
        private static void CanExecuteRoutedEventHandler(object target, CanExecuteRoutedEventArgs args)
        { 
            DocumentViewerBase dv = target as DocumentViewerBase;
            Invariant.Assert(dv != null, "Target of CanExecuteRoutedEventHandler must be DocumentViewerBase."); 
            Invariant.Assert(args != null, "args cannot be null."); 

            // DocumentViewerBase is capable of execution of the majority of its commands. 
            // Special rules:
            // a) Print command is enabled when Document is attached and printing is not in progress.
            // b) CancelPrint command is enabled only during printing.
            if (args.Command == ApplicationCommands.Print) 
            {
                args.CanExecute = (dv.Document != null) && (dv._documentWriter == null); 
                args.Handled = true; 
            }
            else if (args.Command == ApplicationCommands.CancelPrint) 
            {
                args.CanExecute = (dv._documentWriter != null);
            }
            else 
            {
                args.CanExecute = true; 
            } 
        }
 
        /// 
        /// Central handler for all ExecutedRouted events fired by Commands directed at DocumentViewerBase.
        /// 
        /// The target of this Command, expected to be DocumentViewerBase. 
        /// The event arguments associated with this event.
        private static void ExecutedRoutedEventHandler(object target, ExecutedRoutedEventArgs args) 
        { 
            DocumentViewerBase dv = target as DocumentViewerBase;
            Invariant.Assert(dv != null, "Target of ExecuteEvent must be DocumentViewerBase."); 
            Invariant.Assert(args != null, "args cannot be null.");

            // 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 == NavigationCommands.PreviousPage) 
            { 
                dv.OnPreviousPageCommand();
            } 
            else if (args.Command == NavigationCommands.NextPage)
            {
                dv.OnNextPageCommand();
            } 
            else if (args.Command == NavigationCommands.FirstPage)
            { 
                dv.OnFirstPageCommand(); 
            }
            else if (args.Command == NavigationCommands.LastPage) 
            {
                dv.OnLastPageCommand();
            }
            else if (args.Command == NavigationCommands.GoToPage) 
            {
                // Ignore GoToPageCommand, if: 
                //  a) there is no value for the page number. 
                //  b) the value cannot be converted to Int32.
                if (args.Parameter != null) 
                {
                    int pageNumber = -1;
                    try
                    { 
                        pageNumber = Convert.ToInt32(args.Parameter, System.Globalization.CultureInfo.CurrentCulture);
                    } 
#pragma warning disable 56502 // Allow empty catch statements. 
                    catch (InvalidCastException) { }
                    catch (OverflowException) { } 
                    catch (FormatException) { }
#pragma warning restore 56502

                    if (pageNumber >= 0) 
                    {
                        dv.OnGoToPageCommand(pageNumber); 
                    } 
                }
            } 
            else if (args.Command == ApplicationCommands.Print)
            {
                dv.OnPrintCommand();
            } 
            else if (args.Command == ApplicationCommands.CancelPrint)
            { 
                dv.OnCancelPrintCommand(); 
            }
            else 
            {
                Invariant.Assert(false, "Command not handled in ExecutedRoutedEventHandler.");
            }
        } 

        #endregion Commands 
 
        #region Static Methods
 
        /// 
        /// Called from the event handler to make sure the target is visible in the client
        /// area. May cause navigation to a different page.
        ///  
        /// The instance handling the event.
        /// RequestBringIntoViewEventArgs indicates the element and region to scroll into view. 
        private static void HandleRequestBringIntoView(object sender, RequestBringIntoViewEventArgs args) 
        {
            if (sender != null && sender is DocumentViewerBase) 
            {
                ((DocumentViewerBase)sender).HandleRequestBringIntoView(args);
            }
        } 

        ///  
        /// The Document has changed and needs to be updated. 
        /// 
        private static void DocumentChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
        {
            Invariant.Assert(d != null && d is DocumentViewerBase);
            ((DocumentViewerBase) d).DocumentChanged((IDocumentPaginatorSource) e.OldValue, (IDocumentPaginatorSource) e.NewValue);
 
            // Since Document state is used to determine CanExecute state, we must invalidate that state.
            CommandManager.InvalidateRequerySuggested(); 
        } 

        #endregion Static Methods 

        #endregion Private Methods

        //------------------------------------------------------------------- 
        //
        //  Private Properties 
        // 
        //-------------------------------------------------------------------
 
        #region Private Properties

        /// 
        /// ITextContainer associated with Document. 
        /// 
        private ITextContainer TextContainer 
        { 
            get
            { 
                ITextContainer textContainer = null;
                if (_document != null)
                {
                    if (_document is IServiceProvider && CheckFlags(Flags.IsSelectionEnabled)) 
                    {
                        textContainer = ((IServiceProvider)_document).GetService(typeof(ITextContainer)) as ITextContainer; 
                    } 
                }
                return textContainer; 
            }
        }

        #endregion Private Properties 

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

        #region Private Fields
 
        private ReadOnlyCollection _pageViews;    // Collection of DocumentPageViews presenting paginated Document.
        private FrameworkElement _textEditorRenderScope;            // RenderScope associated with the TextEditor. 
        private MultiPageTextView _textView;                        // ITextView associated with DocumentViewer. 
        private TextEditor _textEditor;                             // TextEditor associated with DocumentViewer.
        private IDocumentPaginatorSource _document;                 // IDocumentPaginatorSource representing Document. 
        private Flags _flags;                                       // Flags reflecting various aspects of object's state.
#if !DONOTREFPRINTINGASMMETA
        private XpsDocumentWriter _documentWriter;                  // DocumentWriter used for printing.
#endif // DONOTREFPRINTINGASMMETA 

        private static bool IsEditingEnabled = false;               // A flag enabling text editing within a document viewer 
                                                                    // accessible only through reflection. 

        #endregion Private Fields 

        //--------------------------------------------------------------------
        //
        //  Private Types 
        //
        //-------------------------------------------------------------------- 
 
        #region Private Types
 
        /// 
        /// Flags reflecting various aspects of viewer's state.
        /// 
        [System.Flags] 
        private enum Flags
        { 
            // free bit                 = 0x10, 
            IsSelectionEnabled          = 0x20,     // Is text selection enabled.
            DocumentAsLogicalChild      = 0x40,     // Is Document part of logical tree. 
        }

        /// 
        /// State of BringIntoView operation. 
        /// 
        private class BringIntoViewState 
        { 
            internal BringIntoViewState(DocumentViewerBase source, ContentPosition contentPosition, DependencyObject targetObject, Rect targetRect)
            { 
                this.Source = source;
                this.ContentPosition = contentPosition;
                this.TargetObject = targetObject;
                this.TargetRect = targetRect; 
            }
            internal DocumentViewerBase Source; 
            internal ContentPosition ContentPosition; 
            internal DependencyObject TargetObject;
            internal Rect TargetRect; 
        }

        #endregion Private Types
 
        //-------------------------------------------------------------------
        // 
        //  IAddChild 
        //
        //-------------------------------------------------------------------- 

        #region IAddChild

        ///  
        /// Called to add the object as a Child.
        ///  
        /// Object to add as a child. 
        /// DocumentViewerBase only supports a single child of type IDocumentPaginatorSource.
        void IAddChild.AddChild(Object value) 
        {
            if (value == null)
            {
                throw new ArgumentNullException("value"); 
            }
            // Check if Content has already been set. 
            if (this.Document != null) 
            {
                throw new InvalidOperationException(SR.Get(SRID.DocumentViewerCanHaveOnlyOneChild)); 
            }
            // Only IDocumentPaginatorSource is a valid content.
            IDocumentPaginatorSource document = value as IDocumentPaginatorSource;
            if (document == null) 
            {
                throw new ArgumentException(SR.Get(SRID.DocumentViewerChildMustImplementIDocumentPaginatorSource), "value"); 
            } 
            this.Document = document;
        } 

        /// 
        /// Called when text appears under the tag in markup
        ///  
        /// Text to add to the Object.
        /// DocumentViewer does not support Text children. 
        void IAddChild.AddText(string text) 
        {
            XamlSerializerUtil.ThrowIfNonWhiteSpaceInAddText(text, this); 
        }

        #endregion IAddChild
 
        //-------------------------------------------------------------------
        // 
        //  IServiceProvider 
        //
        //------------------------------------------------------------------- 

        #region IServiceProvider

        ///  
        /// Returns service objects associated with this control.
        ///  
        /// Specifies the type of service object to get. 
        object IServiceProvider.GetService(Type serviceType)
        { 
            object service = null;
            if (serviceType == null)
            {
                throw new ArgumentNullException("serviceType"); 
            }
 
            // Following services are available: 
            // (1) TextView - wrapper for TextViews exposed by PageViews.
            // (2) TextContainer - the service object is retrieved from Document. 
            if (serviceType == typeof(ITextView))
            {
                service = _textView;
            } 
            else if (serviceType == typeof(TextContainer) || serviceType == typeof(ITextContainer))
            { 
                service = this.TextContainer; 
            }
            return service; 
        }

        #endregion IServiceProvider
    } 
}
#pragma warning enable 1634, 1691 
 

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