MultiPageTextView.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 / MS / Internal / documents / MultiPageTextView.cs / 1 / MultiPageTextView.cs

                            //---------------------------------------------------------------------------- 
//
// Copyright (C) Microsoft Corporation.  All rights reserved.
//
// File: MultiPageTextView.cs 
//
// Description: TextView implementation for collection of DocumentPageTextViews. 
// 
//---------------------------------------------------------------------------
 
using System;                               // InvalidOperationException, ...
using System.Collections.Generic;           // List
using System.Collections.ObjectModel;       // ReadOnlyCollection
using System.Windows;                       // Point, Rect, ... 
using System.Windows.Controls;              // FlowDocumentPageViewer, DocumentViewer
using System.Windows.Controls.Primitives;   // DocumentPageView, DocumentViewerBase 
using System.Windows.Documents;             // ITextView, ITextContainer 
using System.Windows.Media;                 // VisualTreeHelper
using System.Windows.Threading;             // DispatcherPriority, DispatherOperationCallback 

namespace MS.Internal.Documents
{
    ///  
    /// TextView implementation for collection of DocumentPageTextViews.
    ///  
    internal class MultiPageTextView : TextViewBase 
    {
        //------------------------------------------------------------------- 
        //
        //  Constructors
        //
        //------------------------------------------------------------------- 

        #region Constructors 
 
        /// 
        /// Constructor. 
        /// 
        /// Viewer associated with TextView.
        /// Render scope - root of layout structure visualizing content.
        /// TextContainer representing content. 
        internal MultiPageTextView(DocumentViewerBase viewer, UIElement renderScope, ITextContainer textContainer)
        { 
            _viewer = viewer; 
            _renderScope = renderScope;
            _textContainer = textContainer; 
            _pageTextViews = new List();
            OnPagesUpdatedCore();
        }
 
        #endregion Constructors
 
        //-------------------------------------------------------------------- 
        //
        //  Protected Methods 
        //
        //-------------------------------------------------------------------

        #region Protected Methods 

        ///  
        /// Fires Updated event. 
        /// 
        /// Event arguments for the Updated event. 
        protected override void OnUpdated(EventArgs e)
        {
            // Forward the event.
            base.OnUpdated(e); 

            // Update. 
            if (this.IsValid) 
            {
                OnUpdatedWorker(null); 
            }
            else
            {
                _renderScope.Dispatcher.BeginInvoke(DispatcherPriority.Normal, new DispatcherOperationCallback(OnUpdatedWorker), EventArgs.Empty); 
            }
        } 
 
        #endregion Protected Methods
 
        //--------------------------------------------------------------------
        //
        //  Internal Methods
        // 
        //--------------------------------------------------------------------
 
        #region Internal Methods 

        ///  
        /// 
        /// 
        internal override ITextPointer GetTextPositionFromPoint(Point point, bool snapToText)
        { 
            ITextPointer position = null;
            DocumentPageTextView pageTextView; 
 
            // Verify that layout information is valid. Cannot continue if not valid.
            if (!IsValid) 
            {
                throw new InvalidOperationException(SR.Get(SRID.TextViewInvalidLayout));
            }
 
            pageTextView = GetTextViewFromPoint(point, false);
            if (pageTextView != null) 
            { 
                // Transform to DocumentPageView coordinates and query inner TextView
                point = TransformToDescendant(pageTextView.RenderScope, point); 
                position = pageTextView.GetTextPositionFromPoint(point, snapToText);

            }
            return position; 
        }
 
        ///  
        /// 
        ///  
        internal override Rect GetRawRectangleFromTextPosition(ITextPointer position, out Transform transform)
        {
            Rect rect = Rect.Empty;
            DocumentPageTextView pageTextView; 

            // Initialize transform to Identity 
            transform = Transform.Identity; 

            // Verify that layout information is valid. Cannot continue if not valid. 
            if (!IsValid)
            {
                throw new InvalidOperationException(SR.Get(SRID.TextViewInvalidLayout));
            } 

            pageTextView = GetTextViewFromPosition(position); 
            if (pageTextView != null) 
            {
                // Query nested TextView and transform from DocumentPageView coordinates. 
                Transform pageTextViewTransform, ancestorTransform;
                rect = pageTextView.GetRawRectangleFromTextPosition(position, out pageTextViewTransform);
                ancestorTransform = GetTransformToAncestor(pageTextView.RenderScope);
                transform = GetAggregateTransform(pageTextViewTransform, ancestorTransform); 
            }
            return rect; 
        } 

        ///  
        /// 
        /// 
        internal override Geometry GetTightBoundingGeometryFromTextPositions(ITextPointer startPosition, ITextPointer endPosition)
        { 
            //  verify that layout information is valid. Cannot continue if not valid.
            if (!IsValid) 
            { 
                throw new InvalidOperationException(SR.Get(SRID.TextViewInvalidLayout));
            } 

            Geometry geometry = null;

            for (int i = 0, count = _pageTextViews.Count; i < count; ++i) 
            {
                ReadOnlyCollection textSegments = _pageTextViews[i].TextSegments; 
 
                for (int segmentIndex = 0; segmentIndex < textSegments.Count; segmentIndex++)
                { 
                    TextSegment textSegment = textSegments[segmentIndex];

                    ITextPointer startPositionInTextSegment = startPosition.CompareTo(textSegment.Start) > 0 ? startPosition : textSegment.Start;
                    ITextPointer endPositionInTextSegment = endPosition.CompareTo(textSegment.End) < 0 ? endPosition : textSegment.End; 

                    if (startPositionInTextSegment.CompareTo(endPositionInTextSegment) >= 0) 
                    { 
                        continue;
                    } 

                    Geometry pageGeometry = _pageTextViews[i].GetTightBoundingGeometryFromTextPositions(startPositionInTextSegment, endPositionInTextSegment);
                    if (pageGeometry != null)
                    { 
                        Transform transform = _pageTextViews[i].RenderScope.TransformToAncestor(_renderScope).AffineTransform;
                        CaretElement.AddTransformToGeometry(pageGeometry, transform); 
 
                        CaretElement.AddGeometry(ref geometry, pageGeometry);
                    } 
                }
            }

            return (geometry); 
        }
 
        ///  
        /// 
        ///  
        internal override ITextPointer GetPositionAtNextLine(ITextPointer position, double suggestedX, int count, out double newSuggestedX, out int linesMoved)
        {
            int pageNumber;
 
            // Verify that layout information is valid. Cannot continue if not valid.
            if (!IsValid) 
            { 
                throw new InvalidOperationException(SR.Get(SRID.TextViewInvalidLayout));
            } 
            return GetPositionAtNextLineCore(position, suggestedX, count, out newSuggestedX, out linesMoved, out pageNumber);
        }

        ///  
        /// 
        ///  
        internal override ITextPointer GetPositionAtNextPage(ITextPointer position, Point suggestedOffset, int count, out Point newSuggestedOffset, out int pagesMoved) 
        {
            int pageNumber;             // Verify that layout information is valid. Cannot continue if not valid. 
            if (!IsValid)
            {
                throw new InvalidOperationException(SR.Get(SRID.TextViewInvalidLayout));
            } 
            return GetPositionAtNextPageCore(position, suggestedOffset, count, out newSuggestedOffset, out pagesMoved, out pageNumber);
        } 
 
        /// 
        ///  
        /// 
        internal override bool IsAtCaretUnitBoundary(ITextPointer position)
        {
            bool atCaretUnitBoundary = false; 
            DocumentPageTextView pageTextView;
 
            // Verify that layout information is valid. Cannot continue if not valid. 
            if (!IsValid)
            { 
                throw new InvalidOperationException(SR.Get(SRID.TextViewInvalidLayout));
            }

            pageTextView = GetTextViewFromPosition(position); 
            if (pageTextView != null)
            { 
                atCaretUnitBoundary = pageTextView.IsAtCaretUnitBoundary(position); 
            }
            return atCaretUnitBoundary; 
        }

        /// 
        ///  
        /// 
        internal override ITextPointer GetNextCaretUnitPosition(ITextPointer position, LogicalDirection direction) 
        { 
            ITextPointer positionOut = null;
            DocumentPageTextView pageTextView; 

            // Verify that layout information is valid. Cannot continue if not valid.
            if (!IsValid)
            { 
                throw new InvalidOperationException(SR.Get(SRID.TextViewInvalidLayout));
            } 
 
            pageTextView = GetTextViewFromPosition(position);
            if (pageTextView != null) 
            {
                positionOut = pageTextView.GetNextCaretUnitPosition(position, direction);
            }
            return positionOut; 
        }
 
        ///  
        /// 
        ///  
        internal override ITextPointer GetBackspaceCaretUnitPosition(ITextPointer position)
        {
            ITextPointer positionOut = null;
            DocumentPageTextView pageTextView; 

            // Verify that layout information is valid. Cannot continue if not valid. 
            if (!IsValid) 
            {
                throw new InvalidOperationException(SR.Get(SRID.TextViewInvalidLayout)); 
            }

            pageTextView = GetTextViewFromPosition(position);
            if (pageTextView != null) 
            {
                positionOut = pageTextView.GetBackspaceCaretUnitPosition(position); 
            } 
            return positionOut;
        } 

        /// 
        /// 
        ///  
        internal override TextSegment GetLineRange(ITextPointer position)
        { 
            TextSegment textSegment = TextSegment.Null; 
            DocumentPageTextView pageTextView;
 
            // Verify that layout information is valid. Cannot continue if not valid.
            if (!IsValid)
            {
                throw new InvalidOperationException(SR.Get(SRID.TextViewInvalidLayout)); 
            }
 
            pageTextView = GetTextViewFromPosition(position); 
            if (pageTextView != null)
            { 
                textSegment = pageTextView.GetLineRange(position);
            }
            return textSegment;
        } 

        ///  
        ///  
        /// 
        internal override bool Contains(ITextPointer position) 
        {
            // Verify that layout information is valid. Cannot continue if not valid.
            if (!IsValid)
            { 
                throw new InvalidOperationException(SR.Get(SRID.TextViewInvalidLayout));
            } 
            return (GetTextViewFromPosition(position) != null); 
        }
 
        /// 
        /// 
        /// 
        internal override void BringPositionIntoViewAsync(ITextPointer position, object userState) 
        {
            DocumentPageTextView pageTextView; 
            int pageNumber; 
            BringPositionIntoViewRequest pendingRequest;
 
            // Verify that layout information is valid. Cannot continue if not valid.
            if (!IsValid)
            {
                throw new InvalidOperationException(SR.Get(SRID.TextViewInvalidLayout)); 
            }
            if (_pendingRequest != null) 
            { 
                // Ignore new request if the previous is not completed yet.
                OnBringPositionIntoViewCompleted(new BringPositionIntoViewCompletedEventArgs( 
                    position, false, null, false, userState));
            }

            pendingRequest = new BringPositionIntoViewRequest(position, userState); 
            _pendingRequest = pendingRequest;
 
            pageTextView = GetTextViewFromPosition(position); 
            // If the position is currently in the view, do nothing.
            // Otherwise, let the viewer handle the request. 
            if (pageTextView != null)
            {
                pendingRequest.Succeeded = true;
                OnBringPositionIntoViewCompleted(pendingRequest); 
            }
            else 
            { 
                if (position is ContentPosition)
                { 
                    DynamicDocumentPaginator documentPaginator = _viewer.Document.DocumentPaginator as DynamicDocumentPaginator;
                    if (documentPaginator != null)
                    {
                        pageNumber = documentPaginator.GetPageNumber((ContentPosition)position) + 1; 
                        if (_viewer.CanGoToPage(pageNumber))
                        { 
                            _viewer.GoToPage(pageNumber); 
                        }
                        else 
                        {
                            OnBringPositionIntoViewCompleted(pendingRequest);
                        }
                    } 
                    else
                    { 
                        OnBringPositionIntoViewCompleted(pendingRequest); 
                    }
                } 
                else
                {
                    OnBringPositionIntoViewCompleted(pendingRequest);
                } 
            }
        } 
 
        /// 
        ///  
        /// 
        internal override void BringPointIntoViewAsync(Point point, object userState)
        {
            DocumentPageTextView pageTextView; 
            ITextPointer position;
            BringPointIntoViewRequest pendingRequest; 
            bool bringIntoViewPending; 

            // Verify that layout information is valid. Cannot continue if not valid. 
            if (!IsValid)
            {
                throw new InvalidOperationException(SR.Get(SRID.TextViewInvalidLayout));
            } 
            if (_pendingRequest != null)
            { 
                // Ignore new request if the previous is not completed yet. 
                OnBringPointIntoViewCompleted(new BringPointIntoViewCompletedEventArgs(
                    point, null, false, null, false, userState)); 
            }
            else
            {
                pendingRequest = new BringPointIntoViewRequest(point, userState); 
                _pendingRequest = pendingRequest;
 
                pageTextView = GetTextViewFromPoint(point, false); 
                // If the point is currently in the view, use existing TextView to retrieve the position.
                // Otherwise, let the viewer handle the request. 
                if (pageTextView != null)
                {
                    // Transform to DocumentPageView coordinates and query inner TextView
                    point = TransformToDescendant(pageTextView.RenderScope, point); 
                    position = pageTextView.GetTextPositionFromPoint(point, true);
 
                    pendingRequest.Position = position; 
                    OnBringPointIntoViewCompleted(pendingRequest);
                } 
                else
                {
                    // Request to bring point into view in the Viewer.
                    // This code is specific to known viewers. Since text selection is not 
                    // exposed in a public way, it should not cause any "extensibility" problems.
                    GeneralTransform transform = _renderScope.TransformToAncestor(_viewer); 
 
                    //
 
                    transform.TryTransform(point, out point);
                    bringIntoViewPending = false;
                    if (_viewer is FlowDocumentPageViewer)
                    { 
                        // Special handling for FlowDocumentPageViewer
                        bringIntoViewPending = ((FlowDocumentPageViewer)_viewer).BringPointIntoView(point); 
                    } 
                    else if (_viewer is DocumentViewer)
                    { 
                        // Special handling for DocumentViewer
                        bringIntoViewPending = ((DocumentViewer)_viewer).BringPointIntoView(point);
                    }
                    else 
                    {
                        if (DoubleUtil.LessThan(point.X, 0)) 
                        { 
                            if (_viewer.CanGoToPreviousPage)
                            { 
                                _viewer.PreviousPage();
                                bringIntoViewPending = true;
                            }
                        } 
                        else if (DoubleUtil.GreaterThan(point.X, _viewer.RenderSize.Width))
                        { 
                            if (_viewer.CanGoToNextPage) 
                            {
                                _viewer.NextPage(); 
                                bringIntoViewPending = true;
                            }
                        }
                        else if (DoubleUtil.LessThan(point.Y, 0)) 
                        {
                            if (_viewer.CanGoToPreviousPage) 
                            { 
                                _viewer.PreviousPage();
                                bringIntoViewPending = true; 
                            }
                        }
                        else if (DoubleUtil.GreaterThan(point.Y, _viewer.RenderSize.Height))
                        { 
                            if (_viewer.CanGoToNextPage)
                            { 
                                _viewer.NextPage(); 
                                bringIntoViewPending = true;
                            } 
                        }
                    }
                    if (!bringIntoViewPending)
                    { 
                        OnBringPointIntoViewCompleted(pendingRequest);
                    } 
                } 
            }
        } 

        /// 
        /// 
        ///  
        internal override void BringLineIntoViewAsync(ITextPointer position, double suggestedX, int count, object userState)
        { 
            // Verify that layout information is valid. Cannot continue if not valid. 
            if (!IsValid)
            { 
                throw new InvalidOperationException(SR.Get(SRID.TextViewInvalidLayout));
            }
            if (_pendingRequest != null)
            { 
                // Ignore new request if the previous is not completed yet.
                OnBringLineIntoViewCompleted(new BringLineIntoViewCompletedEventArgs( 
                    position, suggestedX, count, position, suggestedX, 0, false, null, false, userState)); 
            }
            else 
            {
                _pendingRequest = new BringLineIntoViewRequest(position, suggestedX, count, userState);
                BringLineIntoViewCore((BringLineIntoViewRequest)_pendingRequest);
            } 

        } 
 
        /// 
        ///  
        /// 
        internal override void BringPageIntoViewAsync(ITextPointer position, Point suggestedOffset, int count, object userState)
        {
            // Verify that layout information is valid. Cannot continue if not valid. 
            if (!IsValid)
            { 
                throw new InvalidOperationException(SR.Get(SRID.TextViewInvalidLayout)); 
            }
            if (_pendingRequest != null) 
            {
                // Ignore new request if the previous is not completed yet.
                OnBringPageIntoViewCompleted(new BringPageIntoViewCompletedEventArgs(
                    position, suggestedOffset, count, position, suggestedOffset, 0, false, null, false, userState)); 
            }
            else 
            { 
                _pendingRequest = new BringPageIntoViewRequest(position, suggestedOffset, count, userState);
                BringPageIntoViewCore((BringPageIntoViewRequest)_pendingRequest); 
            }

        }
 

        ///  
        ///  
        /// 
        internal override void CancelAsync(object userState) 
        {
            BringLineIntoViewRequest lineRequest;
            BringPageIntoViewRequest pageRequest;
            BringPointIntoViewRequest pointRequest; 
            BringPositionIntoViewRequest positionRequest;
 
            if (_pendingRequest != null) 
            {
                if (_pendingRequest is BringLineIntoViewRequest) 
                {
                    lineRequest = (BringLineIntoViewRequest)_pendingRequest;
                    OnBringLineIntoViewCompleted(new BringLineIntoViewCompletedEventArgs(
                        lineRequest.Position, lineRequest.SuggestedX, lineRequest.Count, 
                        lineRequest.NewPosition, lineRequest.NewSuggestedX, lineRequest.Count - lineRequest.NewCount,
                        false, null, true, lineRequest.UserState)); 
                } 
                else if (_pendingRequest is BringPageIntoViewRequest)
                { 
                    pageRequest = (BringPageIntoViewRequest)_pendingRequest;
                    OnBringPageIntoViewCompleted(new BringPageIntoViewCompletedEventArgs(
                        pageRequest.Position, pageRequest.SuggestedOffset, pageRequest.Count,
                        pageRequest.NewPosition, pageRequest.NewSuggestedOffset, pageRequest.Count - pageRequest.NewCount, 
                        false, null, true, pageRequest.UserState));
                } 
                else if (_pendingRequest is BringPointIntoViewRequest) 
                {
                    pointRequest = (BringPointIntoViewRequest)_pendingRequest; 
                    OnBringPointIntoViewCompleted(new BringPointIntoViewCompletedEventArgs(
                        pointRequest.Point, pointRequest.Position, false, null, true, pointRequest.UserState));
                }
                else if (_pendingRequest is BringPositionIntoViewRequest) 
                {
                    positionRequest = (BringPositionIntoViewRequest)_pendingRequest; 
                    OnBringPositionIntoViewCompleted(new BringPositionIntoViewCompletedEventArgs( 
                        positionRequest.Position, false, null, true, positionRequest.UserState));
                } 
                _pendingRequest = null;
            }
        }
 
        /// 
        /// Collection of DocumentPageViews has been changed. Need to update 
        /// collection of TextViews. 
        /// 
        internal void OnPagesUpdated() 
        {
            OnPagesUpdatedCore();
            if (IsValid)
            { 
                OnUpdated(EventArgs.Empty);
            } 
        } 

        ///  
        /// Invoked when Page Layout has changed in order to keep
        /// the TextView in [....].
        /// 
        internal void OnPageLayoutChanged() 
        {
            if (IsValid) 
            { 
                OnUpdated(EventArgs.Empty);
            } 
        }


        ///  
        /// Retrieves an active TextView containing the object or character
        /// represented by the given TextPointer. 
        ///  
        /// Position of an object/character.
        ///  
        /// Active TextView containing the object or character represented by
        /// the given TextPointer.
        /// 
        internal ITextView GetPageTextViewFromPosition(ITextPointer position) 
        {
            // Verify that layout information is valid. Cannot continue if not valid. 
            if (!IsValid) 
            {
                throw new InvalidOperationException(SR.Get(SRID.TextViewInvalidLayout)); 
            }
            return GetTextViewFromPosition(position);
        }
 
        #endregion Internal Methods
 
        //------------------------------------------------------------------- 
        //
        //  Internal Properties 
        //
        //--------------------------------------------------------------------

        #region Internal Properties 

        ///  
        ///  
        /// 
        internal override UIElement RenderScope 
        {
            get { return _renderScope; }
        }
 
        /// 
        ///  
        ///  
        internal override ITextContainer TextContainer
        { 
            get { return _textContainer; }
        }

        ///  
        /// 
        ///  
        internal override bool IsValid 
        {
            get 
            {
                bool valid = false;
                if (_pageTextViews != null)
                { 
                    valid = true;
                    for (int i = 0; i < _pageTextViews.Count; i++) 
                    { 
                        if (!_pageTextViews[i].IsValid)
                        { 
                            valid = false;
                            break;
                        }
                    } 
                }
                return valid; 
            } 
        }
 

        /// 
        /// 
        ///  
        internal override bool RendersOwnSelection
        { 
            get 
            {
                if (_pageTextViews != null && _pageTextViews.Count > 0) 
                {
                    return _pageTextViews[0].RendersOwnSelection;
                }
                return false; 
            }
        } 
 

        ///  
        /// 
        /// 
        internal override ReadOnlyCollection TextSegments
        { 
            get
            { 
                List textSegments = new List(); 
                if (IsValid)
                { 
                    // Get collection of active TextViews for all PageDocumentViews.
                    for (int i = 0; i < _pageTextViews.Count; i++)
                    {
                        textSegments.AddRange(_pageTextViews[i].TextSegments); 
                    }
                } 
                return new ReadOnlyCollection(textSegments); 
            }
        } 

        #endregion Internal Properties

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

        /// 
        /// Collection of DocumentPageViews has been changed. Need to update 
        /// collection of TextViews.
        ///  
        private void OnPagesUpdatedCore() 
        {
            ReadOnlyCollection pageViews; 
            DocumentPageTextView pageTextView;
            int index;

            // Drop old collection of DocumentPageTextView objects. 
            for (index = 0; index < _pageTextViews.Count; index++)
            { 
                _pageTextViews[index].Updated -= new EventHandler(HandlePageTextViewUpdated); 
            }
 
            _pageTextViews.Clear();
            pageViews = _viewer.PageViews;
            if (pageViews != null)
            { 
                for (index = 0; index < pageViews.Count; index++)
                { 
                    pageTextView = ((IServiceProvider)pageViews[index]).GetService(typeof(ITextView)) as DocumentPageTextView; 
                    if (pageTextView != null)
                    { 
                        _pageTextViews.Add(pageTextView);
                        pageTextView.Updated += new EventHandler(HandlePageTextViewUpdated);
                    }
                } 
            }
        } 
 
        /// 
        /// Handler for Updated event raised by the inner TextView. 
        /// 
        private void HandlePageTextViewUpdated(object sender, EventArgs e)
        {
            OnUpdated(EventArgs.Empty); 
        }
 
        ///  
        /// Bring line into view.
        ///  
        private void BringLineIntoViewCore(BringLineIntoViewRequest request)
        {
            ITextPointer newPosition;
            double newSuggestedX; 
            int linesMoved;
            int pageNumber; 
 
            // Try to use existing TextViews to handle this request.
            newPosition = GetPositionAtNextLineCore(request.NewPosition, request.NewSuggestedX, request.NewCount, out newSuggestedX, out linesMoved, out pageNumber); 
            Invariant.Assert(Math.Abs(request.NewCount) >= Math.Abs(linesMoved));
            request.NewPosition = newPosition;
            request.NewSuggestedX = newSuggestedX;
            request.NewCount = request.NewCount - linesMoved; 
            request.NewPageNumber = pageNumber;
 
            if (request.NewCount == 0) 
            {
                OnBringLineIntoViewCompleted(request); 
            }
            else
            {
                if (newPosition is DocumentSequenceTextPointer || newPosition is FixedTextPointer) 
                {
                    //Fixed generally uses a stitched viewing mechanism and the approach used for Flow does not work properly for Fixed 
                    //NextPage() call in DocumentViewer results in DocumentGrid.ScrollToNextRow() which scrolls to firstVisibleRow + 1 
                    //E.g. if there are two views on the screen and we need to navigate to the third, this makes it impossible to achieve
                    if (_viewer.CanGoToPage(pageNumber + 1)) 
                    {
                        _viewer.GoToPage(pageNumber + 1);
                    }
                    else 
                    {
                        OnBringLineIntoViewCompleted(request); 
                    } 
                }
                else 
                {
                    if (request.NewCount > 0)
                    {
                        // If the viewer can navigate to the next page, request navigation and wait for 
                        // Updated event for the TextView.
                        // If cannot to the next page, raise BringLineIntoViewCompleted with success = 'False'. 
                        if (_viewer.CanGoToNextPage) 
                        {
                            _viewer.NextPage(); 
                        }
                        else
                        {
                            OnBringLineIntoViewCompleted(request); 
                        }
                    } 
                    else 
                    {
                        // If the viewer can navigate to the previous page, request navigation and wait for 
                        // Updated event fo the TextView.
                        // If cannot to the previous page, raise BringLineIntoViewCompleted with success = 'False'.
                        if (_viewer.CanGoToPreviousPage)
                        { 
                            _viewer.PreviousPage();
                        } 
                        else 
                        {
                            OnBringLineIntoViewCompleted(request); 
                        }
                    }
                }
            } 
        }
 
        ///  
        /// Bring page into view.
        ///  
        private void BringPageIntoViewCore(BringPageIntoViewRequest request)
        {
            ITextPointer newPosition;
            Point newSuggestedOffset; 
            int pagesMoved;
            int newPageNumber; 
 
            // Try to use existing TextViews to handle this request.
            newPosition = GetPositionAtNextPageCore(request.NewPosition, request.NewSuggestedOffset, request.NewCount, out newSuggestedOffset, out pagesMoved, out newPageNumber); 
            Invariant.Assert(Math.Abs(request.NewCount) >= Math.Abs(pagesMoved));
            request.NewPosition = newPosition;
            request.NewSuggestedOffset = newSuggestedOffset;
            request.NewCount = request.NewCount - pagesMoved; 

            if (request.NewCount == 0 || newPageNumber == -1) 
            { 
                OnBringPageIntoViewCompleted(request);
            } 
            else
            {
                // If the viewer can navigate to the next page, request navigation and wait for
                // Updated event for the TextView. 
                // If cannot to the next page, raise BringLineIntoViewCompleted with success = 'False'.
                newPageNumber += (request.NewCount > 0) ? 1 : -1; 
                if (_viewer.CanGoToPage(newPageNumber + 1)) 
                {
                    request.NewPageNumber = newPageNumber; 
                    _viewer.GoToPage(newPageNumber + 1);
                }
                else
                { 
                    OnBringPageIntoViewCompleted(request);
                } 
            } 
        }
 
        /// 
        /// 
        /// 
        private ITextPointer GetPositionAtNextLineCore(ITextPointer position, double suggestedX, int count, out double newSuggestedX, out int linesMoved, out int pageNumber) 
        {
            ITextPointer positionOut; 
            DocumentPageTextView pageTextView; 
            int originalCount;
            Point offset; 
            int newLinesMoved;
            int previousCount;
            ReadOnlyCollection segments;
 
            pageTextView = GetTextViewFromPosition(position);
            if (pageTextView != null) 
            { 
                originalCount = count;
 
                // Transform to DocumentPageView coordinates
                offset = TransformToDescendant(pageTextView.RenderScope, new Point(suggestedX, 0));
                suggestedX = offset.X;
 
                // Query inner TextView
                positionOut = pageTextView.GetPositionAtNextLine(position, suggestedX, count, out newSuggestedX, out linesMoved); 
                pageNumber = ((DocumentPageView)pageTextView.RenderScope).PageNumber; 

                // Transform from DocumentPageView coordinates 
                offset = TransformToAncestor(pageTextView.RenderScope, new Point(newSuggestedX, 0));
                newSuggestedX = offset.X;

                // If number of lines moved is different than requested number of lines, 
                // try to find query the previous/next page.
                while (originalCount != linesMoved) 
                { 
                    newLinesMoved = 0;
                    count = originalCount - linesMoved; 

                    // Try to find TextView for DocumentPageView with the next/previous page number.
                    pageNumber += (count > 0) ? 1 : -1;
                    pageTextView = GetTextViewFromPageNumber(pageNumber); 
                    if (pageTextView != null)
                    { 
                        // All positions have to be in the TextView boundary. 
                        // Since we are quering another TextView, move requested position to its range.
                        segments = pageTextView.TextSegments; 
                        previousCount = count;
                        if (count > 0)
                        {
                            position = pageTextView.GetTextPositionFromPoint(new Point(suggestedX, 0), true); 
                            if (position != null)
                            { 
                                --count; 
                                ++linesMoved;
                            } 
                        }
                        else
                        {
                            position = pageTextView.GetTextPositionFromPoint(new Point(suggestedX, pageTextView.RenderScope.RenderSize.Height), true); 
                            if (position != null)
                            { 
                                ++count; 
                                --linesMoved;
                            } 
                        }

                        if (position != null)
                        { 
                            // If moving to the first/last line of the next/previous TextView, there is
                            // special handling needed to position at the right suggestedX. Otherwise, TextView 
                            // will return the same position. 
                            if (count == 0)
                            { 
                                positionOut = GetPositionAtPageBoundary(previousCount > 0, pageTextView, position, suggestedX);
                                newSuggestedX = suggestedX;
                            }
                            else 
                            {
                                // Query nested TextView. 
                                // Use the same logical 'suggestedX' as for previous DocumentPageView. 
                                positionOut = pageTextView.GetPositionAtNextLine(position, suggestedX, count, out newSuggestedX, out newLinesMoved);
                                linesMoved += newLinesMoved; 
                            }

                            // Transform from DocumentPageView coordinates
                            offset = TransformToAncestor(pageTextView.RenderScope, new Point(newSuggestedX, 0)); 
                            newSuggestedX = offset.X;
                        } 
                    } 
                    else
                    { 
                        // If DocumentPageView has not been found, there is no point
                        // to continue.
                        // 'positionOut' contains the closes position we can return.
                        break; 
                    }
                } 
            } 
            else
            { 
                positionOut = position;
                linesMoved = 0;
                newSuggestedX = suggestedX;
                pageNumber = -1; 
            }
            return positionOut; 
        } 

        private ITextPointer GetPositionAtNextPageCore(ITextPointer position, Point suggestedOffset, int count, out Point newSuggestedOffset, out int pagesMoved, out int pageNumber) 
        {
            // Initialize output
            ITextPointer positionOut = position;
            pagesMoved = 0; 
            newSuggestedOffset = suggestedOffset;
            pageNumber = -1; 
 
            DocumentPageTextView pageTextView = GetTextViewFromPosition(position);
            if (pageTextView != null) 
            {
                int currentPageNumber = ((DocumentPageView)pageTextView.RenderScope).PageNumber;
                DocumentPageTextView newPageTextView = GetTextViewForNextPage(currentPageNumber, count, out pageNumber);
                pagesMoved = pageNumber - currentPageNumber; 
                Invariant.Assert(Math.Abs(pagesMoved) <= Math.Abs(count));
 
                if (pageNumber != currentPageNumber && newPageTextView != null) 
                {
                    // Transform suggested offset to to DocumentPageView coordinates to use as X-coordinate 
                    Point point = TransformToDescendant(pageTextView.RenderScope, suggestedOffset);

                    // Query inner TextView for requested page to find position at that point.
                    positionOut = newPageTextView.GetTextPositionFromPoint(point, /*snapToText*/true); 
                    if (positionOut != null)
                    { 
                        Rect rect = newPageTextView.GetRectangleFromTextPosition(positionOut); 
                        point = TransformToAncestor(pageTextView.RenderScope, new Point(rect.X, rect.Y));
                        newSuggestedOffset = point; 
                    }
                    else
                    {
                        positionOut = position; 
                        pagesMoved = 0;
                        pageNumber = currentPageNumber; 
                    } 
                }
                else 
                {
                    pagesMoved = 0;
                    pageNumber = currentPageNumber;
                } 
            }
 
            return positionOut; 
        }
 
        /// 
        /// Retrieves position at the page boundary from given suggestedX.
        /// 
        /// Whether asking for top of the page or bottom of the page. 
        /// TextView representing the page.
        /// Position at the beginning/end of the page. 
        /// Suggested offset in the page. 
        /// Position at the page boundary from given suggestedX.
        private ITextPointer GetPositionAtPageBoundary(bool pageTop, ITextView pageTextView, ITextPointer position, double suggestedX) 
        {
            double newSuggestedX;
            int newLinesMoved;
            ITextPointer positionOut; 

            // If moving to the first/last line of the next/previous TextView, there is 
            // special handling needed to position at the right suggestedX. Otherwise, TextView 
            // will return the same position.
            if (pageTop) 
            {
                // Move line down and line up.
                positionOut = pageTextView.GetPositionAtNextLine(position, suggestedX, 1, out newSuggestedX, out newLinesMoved);
                if (newLinesMoved == 1) 
                {
                    positionOut = pageTextView.GetPositionAtNextLine(positionOut, newSuggestedX, -1, out newSuggestedX, out newLinesMoved); 
                } 
                else
                { 
                    // Line down failed, so use the first position of TextView.
                    positionOut = position;
                }
            } 
            else
            { 
                // Move line up and line down. 
                positionOut = pageTextView.GetPositionAtNextLine(position, suggestedX, -1, out newSuggestedX, out newLinesMoved);
                if (newLinesMoved == -1) 
                {
                    positionOut = pageTextView.GetPositionAtNextLine(positionOut, newSuggestedX, 1, out newSuggestedX, out newLinesMoved);
                }
                else 
                {
                    // Line up failed, so use the last position of TextView. 
                    positionOut = position; 
                }
            } 
            return positionOut;
        }

        ///  
        /// Returns an active TextView that matches the supplied Point.
        ///  
        /// Point in pixel coordinates to test. 
        /// Snap to closest TextView.
        /// An active TextView that matches the supplied Point. 
        private DocumentPageTextView GetTextViewFromPoint(Point point, bool snap)
        {
            DocumentPageTextView textView = null;
            Rect textViewBounds; 
            int i;
 
            // Try to find pageElement with exact hit. 
            // Enumerate all inner TextViews and try to find exact hit for given Point.
            for (i = 0; i < _pageTextViews.Count; i++) 
            {
                textViewBounds = TransformToAncestor(_pageTextViews[i].RenderScope, new Rect(_pageTextViews[i].RenderScope.RenderSize));
                if (textViewBounds.Contains(point))
                { 
                    textView = _pageTextViews[i];
                    break; 
                } 
            }
 
            if (textView == null && snap)
            {
                // For each TextView calculate 'proximity' function.
                double[] textViewProximities = new double[_pageTextViews.Count]; 
                for (i = 0; i < _pageTextViews.Count; i++)
                { 
                    textViewBounds = TransformToAncestor(_pageTextViews[i].RenderScope, new Rect(_pageTextViews[i].RenderScope.RenderSize)); 
                    double horz, vert;
                    if (point.X >= textViewBounds.Left && point.X <= textViewBounds.Right) 
                    {
                        horz = 0;
                    }
                    else 
                    {
                        horz = Math.Min(Math.Abs(point.X - textViewBounds.Left), Math.Abs(point.X - textViewBounds.Right)); 
                    } 
                    if (point.Y >= textViewBounds.Top && point.Y <= textViewBounds.Bottom)
                    { 
                        vert = 0;
                    }
                    else
                    { 
                        vert = Math.Min(Math.Abs(point.Y - textViewBounds.Top), Math.Abs(point.Y - textViewBounds.Bottom));
                    } 
                    textViewProximities[i] = Math.Sqrt(Math.Pow(horz, 2) + Math.Pow(vert, 2)); 
                }
                // Get the closest TextView according to 'proximity' function. 
                double proximity = double.MaxValue;
                for (i = 0; i < textViewProximities.Length; i++)
                {
                    if (proximity > textViewProximities[i]) 
                    {
                        proximity = textViewProximities[i]; 
                        textView = _pageTextViews[i]; 
                    }
                } 
            }

            return textView;
        } 

        ///  
        /// Retrieves an active TextView containing the object or character 
        /// represented by the given TextPointer.
        ///  
        /// Position of an object/character.
        /// 
        /// Active TextView containing the object or character represented by
        /// the given TextPointer. 
        /// 
        private DocumentPageTextView GetTextViewFromPosition(ITextPointer position) 
        { 
            DocumentPageTextView textView = null;
            int i; 

            // Try to find pageElement with exact hit.
            for (i = 0; i < _pageTextViews.Count; i++)
            { 
                if (_pageTextViews[i].Contains(position))
                { 
                    textView = _pageTextViews[i]; 
                    break;
                } 
            }

            return textView;
        } 

        ///  
        /// Retrieves an active TextView from DocumentPageView with specified page number. 
        /// 
        /// Page number. 
        /// 
        /// Active TextView from DocumentPageView with specified page number.
        /// 
        private DocumentPageTextView GetTextViewFromPageNumber(int pageNumber) 
        {
            DocumentPageTextView textView = null; 
            int i; 

            // Try to find pageElement with exact hit. 
            for (i = 0; i < _pageTextViews.Count; i++)
            {
                if (_pageTextViews[i].DocumentPageView.PageNumber == pageNumber)
                { 
                    textView = _pageTextViews[i];
                    break; 
                } 
            }
            return textView; 
        }

        /// 
        /// Given page number and count, retrieves an active TextView at distance count from the specified page number 
        /// 
        /// Page number. 
        /// Number of pages between specified page number and desired page number 
        /// Page number of the view that is actually returned
        ///  
        /// If there is no view at distance count from the specified page number in the list of views, return the page text view that's
        /// closest in the direction of count, i.e. if we're on page 2 and count = 5, and we have pages 5 and 10 in view but not page 7, return
        /// 5, i.e. we never move by > count
        ///  
        private DocumentPageTextView GetTextViewForNextPage(int pageNumber, int count, out int newPageNumber)
        { 
            Invariant.Assert(count != 0); 
            newPageNumber = pageNumber + count;
            int closestPageNumber = newPageNumber; 
            DocumentPageTextView textView = null;
            int closestDistance = Math.Abs(count);

            for (int i = 0; i < _pageTextViews.Count; i++) 
            {
                if (_pageTextViews[i].DocumentPageView.PageNumber == newPageNumber) 
                { 
                    textView = _pageTextViews[i];
                    closestPageNumber = newPageNumber; 
                    break;
                }
                else
                { 
                    int currentPageNumber = _pageTextViews[i].DocumentPageView.PageNumber;
                    if (count > 0 && currentPageNumber > pageNumber) 
                    { 
                        int distance = currentPageNumber - pageNumber;
                        if (distance < closestDistance) 
                        {
                            closestDistance = distance;
                            textView = _pageTextViews[i];
                            closestPageNumber = currentPageNumber; 
                        }
                    } 
                    else if (count < 0 && currentPageNumber < pageNumber) 
                    {
                        int distance = Math.Abs(currentPageNumber - pageNumber); 
                        if (distance < closestDistance)
                        {
                            closestDistance = distance;
                            textView = _pageTextViews[i]; 
                            closestPageNumber = currentPageNumber;
                        } 
                    } 
                }
            } 

            if (textView != null)
            {
                newPageNumber = closestPageNumber; 
            }
            else 
            { 
                newPageNumber = pageNumber;
                textView = GetTextViewFromPageNumber(pageNumber); 
            }
            Invariant.Assert(newPageNumber >= 0);
            return textView;
        } 

 
        ///  
        /// Gets transform to ancestor for inner scope
        ///  
        private Transform GetTransformToAncestor(Visual innerScope)
        {
            // NOTE: TransformToAncestor is safe (will never throw an exception).
            Transform transform = innerScope.TransformToAncestor(_renderScope) as Transform; 
            if (transform == null)
            { 
                transform = Transform.Identity; 
            }
            return transform; 
        }

        /// 
        /// Transforms rectangle from inner scope. 
        /// 
        private Rect TransformToAncestor(Visual innerScope, Rect rect) 
        { 
            if (rect != Rect.Empty)
            { 
                // NOTE: TransformToAncestor is safe (will never throw an exception).
                GeneralTransform transform = innerScope.TransformToAncestor(_renderScope);
                if (transform != null)
                { 
                    rect = transform.TransformBounds(rect);
                } 
            } 
            return rect;
        } 

        /// 
        /// Transforms point from inner scope.
        ///  
        private Point TransformToAncestor(Visual innerScope, Point point)
        { 
            // NOTE: TransformToAncestor is safe (will never throw an exception). 
            GeneralTransform transform = innerScope.TransformToAncestor(_renderScope);
            if (transform != null) 
            {
                point = transform.Transform(point);
            }
            return point; 
        }
 
        ///  
        /// Transforms rectangle from inner scope
        ///  
        private Point TransformToDescendant(Visual innerScope, Point point)
        {
            // NOTE: TransformToAncestor is safe (will never throw an exception).
            GeneralTransform transform = innerScope.TransformToAncestor(_renderScope); 
            if (transform != null)
            { 
                transform = transform.Inverse; 
                if (transform != null)
                { 
                    point = transform.Transform(point);
                }
            }
            return point; 
        }
 
        ///  
        /// Fires BringPositionIntoViewCompleted event.
        ///  
        private void OnBringPositionIntoViewCompleted(BringPositionIntoViewRequest request)
        {
            _pendingRequest = null;
            OnBringPositionIntoViewCompleted(new BringPositionIntoViewCompletedEventArgs( 
                request.Position, request.Succeeded, null, false, request.UserState));
        } 
 
        /// 
        /// Fires BringPointIntoViewCompleted event. 
        /// 
        private void OnBringPointIntoViewCompleted(BringPointIntoViewRequest request)
        {
            _pendingRequest = null; 
            OnBringPointIntoViewCompleted(new BringPointIntoViewCompletedEventArgs(
                request.Point, request.Position, 
                request.Position != null, null, false, request.UserState)); 
        }
 
        /// 
        /// Fires BringLineIntoViewCompleted event.
        /// 
        private void OnBringLineIntoViewCompleted(BringLineIntoViewRequest request) 
        {
            _pendingRequest = null; 
            OnBringLineIntoViewCompleted(new BringLineIntoViewCompletedEventArgs( 
                request.Position, request.SuggestedX, request.Count,
                request.NewPosition, request.NewSuggestedX, request.Count - request.NewCount, 
                request.NewCount == 0, null, false, request.UserState));
        }

        ///  
        /// Fires BringPageIntoViewCompleted event.
        ///  
        private void OnBringPageIntoViewCompleted(BringPageIntoViewRequest request) 
        {
            _pendingRequest = null; 
            OnBringPageIntoViewCompleted(new BringPageIntoViewCompletedEventArgs(
                request.Position, request.SuggestedOffset, request.Count,
                request.NewPosition, request.NewSuggestedOffset, request.Count - request.NewCount,
                request.NewCount == 0, null, false, request.UserState)); 
        }
 
        ///  
        /// Responds to an OnUpdated call.
        ///  
        private object OnUpdatedWorker(object o)
        {
            BringLineIntoViewRequest lineRequest;
            BringPageIntoViewRequest pageRequest; 
            BringPointIntoViewRequest pointRequest;
            BringPositionIntoViewRequest positionRequest; 
            ITextView pageTextView; 
            ITextPointer newPosition;
            Point point; 
            double suggestedX;

            if (this.IsValid && _pendingRequest != null)
            { 
                if (_pendingRequest is BringLineIntoViewRequest)
                { 
                    lineRequest = (BringLineIntoViewRequest)_pendingRequest; 

                    // Try to find TextView for DocumentPageView with stored page number. 
                    pageTextView = GetTextViewFromPageNumber(lineRequest.NewPageNumber);
                    if (pageTextView != null)
                    {
                        // Transform to DocumentPageView coordinates 
                        point = TransformToDescendant(pageTextView.RenderScope, new Point(lineRequest.NewSuggestedX, 0));
                        suggestedX = point.X; 
 
                        // All positions have to be in the TextView boundary.
                        // Since we are quering another TextView, move requested position to its range. 
                        if (lineRequest.Count > 0)
                        {
                            // Search for a point just outside the limits so that GetTextView.GetTextPositionFromPoint will not hit test
                            // inside anchored blocks unless they are offset out of the page. 
                            newPosition = pageTextView.GetTextPositionFromPoint(new Point(-1, -1), true);
                            if (newPosition != null) 
                            { 
                                lineRequest.NewCount = lineRequest.NewCount - 1;
                            } 
                        }
                        else
                        {
                            newPosition = pageTextView.GetTextPositionFromPoint((Point)pageTextView.RenderScope.RenderSize, true); 
                            if (newPosition != null)
                            { 
                                lineRequest.NewCount = lineRequest.NewCount + 1; 
                            }
                        } 

                        // If still have some lines to be moved, do another BringLineIntoView request.
                        // Otherwise the goal has been reached and fire completed event.
                        if (newPosition == null) 
                        {
                            // New position cannot be found, return best result so far. 
                            if (lineRequest.NewPosition == null) 
                            {
                                lineRequest.NewPosition = lineRequest.Position; 
                                lineRequest.NewCount = lineRequest.Count;
                            }
                            OnBringLineIntoViewCompleted(lineRequest);
                        } 
                        else if (lineRequest.NewCount != 0)
                        { 
                            lineRequest.NewPosition = newPosition; 
                            BringLineIntoViewCore(lineRequest);
                        } 
                        else
                        {
                            lineRequest.NewPosition = GetPositionAtPageBoundary(lineRequest.Count > 0, pageTextView, newPosition, lineRequest.NewSuggestedX);
                            OnBringLineIntoViewCompleted(lineRequest); 
                        }
                    } 
                    else if(IsPageNumberOutOfRange(lineRequest.NewPageNumber)) 
                    {
                        OnBringLineIntoViewCompleted(lineRequest); 
                    }
                }
                else if (_pendingRequest is BringPageIntoViewRequest)
                { 
                    pageRequest = (BringPageIntoViewRequest)_pendingRequest;
 
                    // Try to find TextView for DocumentPageView with stored page number. 
                    pageTextView = GetTextViewFromPageNumber(pageRequest.NewPageNumber);
                    if (pageTextView != null) 
                    {
                        // Transform to DocumentPageView coordinates
                        point = TransformToDescendant(pageTextView.RenderScope, pageRequest.NewSuggestedOffset);
                        Point suggestedOffset = point; 

                        Invariant.Assert(pageRequest.NewCount != 0); 
                        newPosition = pageTextView.GetTextPositionFromPoint(suggestedOffset, true); 
                        if (newPosition != null)
                        { 
                            pageRequest.NewCount = (pageRequest.Count > 0) ? pageRequest.NewCount - 1 : pageRequest.NewCount + 1;
                        }

                        // If still have some lines to be moved, do another BringLineIntoView request. 
                        // Otherwise the goal has been reached and fire completed event.
                        if (newPosition == null) 
                        { 
                            // New position cannot be found, return best result so far.
                            if (pageRequest.NewPosition == null) 
                            {
                                pageRequest.NewPosition = pageRequest.Position;
                                pageRequest.NewCount = pageRequest.Count;
                            } 
                            OnBringPageIntoViewCompleted(pageRequest);
                        } 
                        else if (pageRequest.NewCount != 0) 
                        {
                            pageRequest.NewPosition = newPosition; 
                            BringPageIntoViewCore(pageRequest);
                        }
                        else
                        { 
                            pageRequest.NewPosition = newPosition;
                            OnBringPageIntoViewCompleted(pageRequest); 
                        } 
                    }
                    else if(IsPageNumberOutOfRange(pageRequest.NewPageNumber)) 
                    {
                        OnBringPageIntoViewCompleted(pageRequest);
                    }
                } 
                else if (_pendingRequest is BringPointIntoViewRequest)
                { 
                    pointRequest = (BringPointIntoViewRequest)_pendingRequest; 

                    pageTextView = GetTextViewFromPoint(pointRequest.Point, true); 
                    if (pageTextView != null)
                    {
                        // Transform to DocumentPageView coordinates and query inner TextView
                        point = TransformToDescendant(pageTextView.RenderScope, pointRequest.Point); 
                        pointRequest.Position = pageTextView.GetTextPositionFromPoint(point, true);
                    } 
                    OnBringPointIntoViewCompleted(pointRequest); 
                }
                else if (_pendingRequest is BringPositionIntoViewRequest) 
                {
                    positionRequest = (BringPositionIntoViewRequest)_pendingRequest;
                    positionRequest.Succeeded = positionRequest.Position.HasValidLayout;
                    OnBringPositionIntoViewCompleted(positionRequest); 
                }
            } 
 
            return null;
        } 

        /// 
        /// Distinguishes between whether a page is not available now, or will never be available.
        ///  
        private bool IsPageNumberOutOfRange(int pageNumber)
        { 
            if(pageNumber < 0) 
            {
                return true; 
            }

            IDocumentPaginatorSource document = _viewer.Document;
            if(document == null) 
            {
                return true; 
            } 

            DocumentPaginator documentPaginator = document.DocumentPaginator; 

            if(documentPaginator == null)
            {
                return true; 
            }
 
            if(documentPaginator.IsPageCountValid && pageNumber >= documentPaginator.PageCount) 
            {
                return true; 
            }

            return false;
        } 

        #endregion Private Methods 
 
        //-------------------------------------------------------------------
        // 
        //  Private Fields
        //
        //--------------------------------------------------------------------
 
        #region Private Fields
 
        ///  
        /// Viewer associated with TextView.
        ///  
        private readonly DocumentViewerBase _viewer;

        /// 
        /// Root of layout structure visualizing content. 
        /// 
        private readonly UIElement _renderScope; 
 
        /// 
        /// TextContainer representing content. 
        /// 
        private readonly ITextContainer _textContainer;

        ///  
        /// Collection of hosted TextViews.
        ///  
        private List _pageTextViews; 

        ///  
        /// Pending BringIntoView request.
        /// 
        private BringIntoViewRequest _pendingRequest;
 
        #endregion Private Fields
 
        //------------------------------------------------------------------- 
        //
        //  Private Types 
        //
        //--------------------------------------------------------------------

        #region Private Types 

        ///  
        /// Pending BringIntoView request. 
        /// 
        private class BringIntoViewRequest 
        {
            internal BringIntoViewRequest(object userState)
            {
                this.UserState = userState; 
            }
            internal readonly object UserState; 
        } 

        ///  
        /// Pending BringPositionIntoView request.
        /// 
        private class BringPositionIntoViewRequest : BringIntoViewRequest
        { 
            internal BringPositionIntoViewRequest(ITextPointer position, object userState)
                : base(userState) 
            { 
                this.Position = position;
                this.Succeeded = false; 
            }
            internal readonly ITextPointer Position;
            internal bool Succeeded;
        } 

        ///  
        /// Pending BringPointIntoView request. 
        /// 
        private class BringPointIntoViewRequest : BringIntoViewRequest 
        {
            internal BringPointIntoViewRequest(Point point, object userState)
                : base(userState)
            { 
                this.Point = point;
                this.Position = null; 
            } 
            internal readonly Point Point;
            internal ITextPointer Position; 
        }

        /// 
        /// Pending BringLineIntoView request. 
        /// 
        private class BringLineIntoViewRequest : BringIntoViewRequest 
        { 
            internal BringLineIntoViewRequest(ITextPointer position, double suggestedX, int count, object userState)
                : base(userState) 
            {
                this.Position = position;
                this.SuggestedX = suggestedX;
                this.Count = count; 
                this.NewPosition = position;
                this.NewSuggestedX = suggestedX; 
                this.NewCount = count; 
            }
            internal readonly ITextPointer Position; 
            internal readonly double SuggestedX;
            internal readonly int Count;
            internal ITextPointer NewPosition;
            internal double NewSuggestedX; 
            internal int NewCount;
            internal int NewPageNumber; 
        } 

        ///  
        /// Pending BringPageIntoView request.
        /// 
        private class BringPageIntoViewRequest : BringIntoViewRequest
        { 
            internal BringPageIntoViewRequest(ITextPointer position, Point suggestedOffset, int count, object userState)
                : base(userState) 
            { 
                this.Position = position;
                this.SuggestedOffset = suggestedOffset; 
                this.Count = count;
                this.NewPosition = position;
                this.NewSuggestedOffset = suggestedOffset;
                this.NewCount = count; 
            }
            internal readonly ITextPointer Position; 
            internal readonly Point SuggestedOffset; 
            internal readonly int Count;
            internal ITextPointer NewPosition; 
            internal Point NewSuggestedOffset;
            internal int NewCount;
            internal int NewPageNumber;
        } 

        #endregion Private Types 
    } 
}
 

// 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: MultiPageTextView.cs 
//
// Description: TextView implementation for collection of DocumentPageTextViews. 
// 
//---------------------------------------------------------------------------
 
using System;                               // InvalidOperationException, ...
using System.Collections.Generic;           // List
using System.Collections.ObjectModel;       // ReadOnlyCollection
using System.Windows;                       // Point, Rect, ... 
using System.Windows.Controls;              // FlowDocumentPageViewer, DocumentViewer
using System.Windows.Controls.Primitives;   // DocumentPageView, DocumentViewerBase 
using System.Windows.Documents;             // ITextView, ITextContainer 
using System.Windows.Media;                 // VisualTreeHelper
using System.Windows.Threading;             // DispatcherPriority, DispatherOperationCallback 

namespace MS.Internal.Documents
{
    ///  
    /// TextView implementation for collection of DocumentPageTextViews.
    ///  
    internal class MultiPageTextView : TextViewBase 
    {
        //------------------------------------------------------------------- 
        //
        //  Constructors
        //
        //------------------------------------------------------------------- 

        #region Constructors 
 
        /// 
        /// Constructor. 
        /// 
        /// Viewer associated with TextView.
        /// Render scope - root of layout structure visualizing content.
        /// TextContainer representing content. 
        internal MultiPageTextView(DocumentViewerBase viewer, UIElement renderScope, ITextContainer textContainer)
        { 
            _viewer = viewer; 
            _renderScope = renderScope;
            _textContainer = textContainer; 
            _pageTextViews = new List();
            OnPagesUpdatedCore();
        }
 
        #endregion Constructors
 
        //-------------------------------------------------------------------- 
        //
        //  Protected Methods 
        //
        //-------------------------------------------------------------------

        #region Protected Methods 

        ///  
        /// Fires Updated event. 
        /// 
        /// Event arguments for the Updated event. 
        protected override void OnUpdated(EventArgs e)
        {
            // Forward the event.
            base.OnUpdated(e); 

            // Update. 
            if (this.IsValid) 
            {
                OnUpdatedWorker(null); 
            }
            else
            {
                _renderScope.Dispatcher.BeginInvoke(DispatcherPriority.Normal, new DispatcherOperationCallback(OnUpdatedWorker), EventArgs.Empty); 
            }
        } 
 
        #endregion Protected Methods
 
        //--------------------------------------------------------------------
        //
        //  Internal Methods
        // 
        //--------------------------------------------------------------------
 
        #region Internal Methods 

        ///  
        /// 
        /// 
        internal override ITextPointer GetTextPositionFromPoint(Point point, bool snapToText)
        { 
            ITextPointer position = null;
            DocumentPageTextView pageTextView; 
 
            // Verify that layout information is valid. Cannot continue if not valid.
            if (!IsValid) 
            {
                throw new InvalidOperationException(SR.Get(SRID.TextViewInvalidLayout));
            }
 
            pageTextView = GetTextViewFromPoint(point, false);
            if (pageTextView != null) 
            { 
                // Transform to DocumentPageView coordinates and query inner TextView
                point = TransformToDescendant(pageTextView.RenderScope, point); 
                position = pageTextView.GetTextPositionFromPoint(point, snapToText);

            }
            return position; 
        }
 
        ///  
        /// 
        ///  
        internal override Rect GetRawRectangleFromTextPosition(ITextPointer position, out Transform transform)
        {
            Rect rect = Rect.Empty;
            DocumentPageTextView pageTextView; 

            // Initialize transform to Identity 
            transform = Transform.Identity; 

            // Verify that layout information is valid. Cannot continue if not valid. 
            if (!IsValid)
            {
                throw new InvalidOperationException(SR.Get(SRID.TextViewInvalidLayout));
            } 

            pageTextView = GetTextViewFromPosition(position); 
            if (pageTextView != null) 
            {
                // Query nested TextView and transform from DocumentPageView coordinates. 
                Transform pageTextViewTransform, ancestorTransform;
                rect = pageTextView.GetRawRectangleFromTextPosition(position, out pageTextViewTransform);
                ancestorTransform = GetTransformToAncestor(pageTextView.RenderScope);
                transform = GetAggregateTransform(pageTextViewTransform, ancestorTransform); 
            }
            return rect; 
        } 

        ///  
        /// 
        /// 
        internal override Geometry GetTightBoundingGeometryFromTextPositions(ITextPointer startPosition, ITextPointer endPosition)
        { 
            //  verify that layout information is valid. Cannot continue if not valid.
            if (!IsValid) 
            { 
                throw new InvalidOperationException(SR.Get(SRID.TextViewInvalidLayout));
            } 

            Geometry geometry = null;

            for (int i = 0, count = _pageTextViews.Count; i < count; ++i) 
            {
                ReadOnlyCollection textSegments = _pageTextViews[i].TextSegments; 
 
                for (int segmentIndex = 0; segmentIndex < textSegments.Count; segmentIndex++)
                { 
                    TextSegment textSegment = textSegments[segmentIndex];

                    ITextPointer startPositionInTextSegment = startPosition.CompareTo(textSegment.Start) > 0 ? startPosition : textSegment.Start;
                    ITextPointer endPositionInTextSegment = endPosition.CompareTo(textSegment.End) < 0 ? endPosition : textSegment.End; 

                    if (startPositionInTextSegment.CompareTo(endPositionInTextSegment) >= 0) 
                    { 
                        continue;
                    } 

                    Geometry pageGeometry = _pageTextViews[i].GetTightBoundingGeometryFromTextPositions(startPositionInTextSegment, endPositionInTextSegment);
                    if (pageGeometry != null)
                    { 
                        Transform transform = _pageTextViews[i].RenderScope.TransformToAncestor(_renderScope).AffineTransform;
                        CaretElement.AddTransformToGeometry(pageGeometry, transform); 
 
                        CaretElement.AddGeometry(ref geometry, pageGeometry);
                    } 
                }
            }

            return (geometry); 
        }
 
        ///  
        /// 
        ///  
        internal override ITextPointer GetPositionAtNextLine(ITextPointer position, double suggestedX, int count, out double newSuggestedX, out int linesMoved)
        {
            int pageNumber;
 
            // Verify that layout information is valid. Cannot continue if not valid.
            if (!IsValid) 
            { 
                throw new InvalidOperationException(SR.Get(SRID.TextViewInvalidLayout));
            } 
            return GetPositionAtNextLineCore(position, suggestedX, count, out newSuggestedX, out linesMoved, out pageNumber);
        }

        ///  
        /// 
        ///  
        internal override ITextPointer GetPositionAtNextPage(ITextPointer position, Point suggestedOffset, int count, out Point newSuggestedOffset, out int pagesMoved) 
        {
            int pageNumber;             // Verify that layout information is valid. Cannot continue if not valid. 
            if (!IsValid)
            {
                throw new InvalidOperationException(SR.Get(SRID.TextViewInvalidLayout));
            } 
            return GetPositionAtNextPageCore(position, suggestedOffset, count, out newSuggestedOffset, out pagesMoved, out pageNumber);
        } 
 
        /// 
        ///  
        /// 
        internal override bool IsAtCaretUnitBoundary(ITextPointer position)
        {
            bool atCaretUnitBoundary = false; 
            DocumentPageTextView pageTextView;
 
            // Verify that layout information is valid. Cannot continue if not valid. 
            if (!IsValid)
            { 
                throw new InvalidOperationException(SR.Get(SRID.TextViewInvalidLayout));
            }

            pageTextView = GetTextViewFromPosition(position); 
            if (pageTextView != null)
            { 
                atCaretUnitBoundary = pageTextView.IsAtCaretUnitBoundary(position); 
            }
            return atCaretUnitBoundary; 
        }

        /// 
        ///  
        /// 
        internal override ITextPointer GetNextCaretUnitPosition(ITextPointer position, LogicalDirection direction) 
        { 
            ITextPointer positionOut = null;
            DocumentPageTextView pageTextView; 

            // Verify that layout information is valid. Cannot continue if not valid.
            if (!IsValid)
            { 
                throw new InvalidOperationException(SR.Get(SRID.TextViewInvalidLayout));
            } 
 
            pageTextView = GetTextViewFromPosition(position);
            if (pageTextView != null) 
            {
                positionOut = pageTextView.GetNextCaretUnitPosition(position, direction);
            }
            return positionOut; 
        }
 
        ///  
        /// 
        ///  
        internal override ITextPointer GetBackspaceCaretUnitPosition(ITextPointer position)
        {
            ITextPointer positionOut = null;
            DocumentPageTextView pageTextView; 

            // Verify that layout information is valid. Cannot continue if not valid. 
            if (!IsValid) 
            {
                throw new InvalidOperationException(SR.Get(SRID.TextViewInvalidLayout)); 
            }

            pageTextView = GetTextViewFromPosition(position);
            if (pageTextView != null) 
            {
                positionOut = pageTextView.GetBackspaceCaretUnitPosition(position); 
            } 
            return positionOut;
        } 

        /// 
        /// 
        ///  
        internal override TextSegment GetLineRange(ITextPointer position)
        { 
            TextSegment textSegment = TextSegment.Null; 
            DocumentPageTextView pageTextView;
 
            // Verify that layout information is valid. Cannot continue if not valid.
            if (!IsValid)
            {
                throw new InvalidOperationException(SR.Get(SRID.TextViewInvalidLayout)); 
            }
 
            pageTextView = GetTextViewFromPosition(position); 
            if (pageTextView != null)
            { 
                textSegment = pageTextView.GetLineRange(position);
            }
            return textSegment;
        } 

        ///  
        ///  
        /// 
        internal override bool Contains(ITextPointer position) 
        {
            // Verify that layout information is valid. Cannot continue if not valid.
            if (!IsValid)
            { 
                throw new InvalidOperationException(SR.Get(SRID.TextViewInvalidLayout));
            } 
            return (GetTextViewFromPosition(position) != null); 
        }
 
        /// 
        /// 
        /// 
        internal override void BringPositionIntoViewAsync(ITextPointer position, object userState) 
        {
            DocumentPageTextView pageTextView; 
            int pageNumber; 
            BringPositionIntoViewRequest pendingRequest;
 
            // Verify that layout information is valid. Cannot continue if not valid.
            if (!IsValid)
            {
                throw new InvalidOperationException(SR.Get(SRID.TextViewInvalidLayout)); 
            }
            if (_pendingRequest != null) 
            { 
                // Ignore new request if the previous is not completed yet.
                OnBringPositionIntoViewCompleted(new BringPositionIntoViewCompletedEventArgs( 
                    position, false, null, false, userState));
            }

            pendingRequest = new BringPositionIntoViewRequest(position, userState); 
            _pendingRequest = pendingRequest;
 
            pageTextView = GetTextViewFromPosition(position); 
            // If the position is currently in the view, do nothing.
            // Otherwise, let the viewer handle the request. 
            if (pageTextView != null)
            {
                pendingRequest.Succeeded = true;
                OnBringPositionIntoViewCompleted(pendingRequest); 
            }
            else 
            { 
                if (position is ContentPosition)
                { 
                    DynamicDocumentPaginator documentPaginator = _viewer.Document.DocumentPaginator as DynamicDocumentPaginator;
                    if (documentPaginator != null)
                    {
                        pageNumber = documentPaginator.GetPageNumber((ContentPosition)position) + 1; 
                        if (_viewer.CanGoToPage(pageNumber))
                        { 
                            _viewer.GoToPage(pageNumber); 
                        }
                        else 
                        {
                            OnBringPositionIntoViewCompleted(pendingRequest);
                        }
                    } 
                    else
                    { 
                        OnBringPositionIntoViewCompleted(pendingRequest); 
                    }
                } 
                else
                {
                    OnBringPositionIntoViewCompleted(pendingRequest);
                } 
            }
        } 
 
        /// 
        ///  
        /// 
        internal override void BringPointIntoViewAsync(Point point, object userState)
        {
            DocumentPageTextView pageTextView; 
            ITextPointer position;
            BringPointIntoViewRequest pendingRequest; 
            bool bringIntoViewPending; 

            // Verify that layout information is valid. Cannot continue if not valid. 
            if (!IsValid)
            {
                throw new InvalidOperationException(SR.Get(SRID.TextViewInvalidLayout));
            } 
            if (_pendingRequest != null)
            { 
                // Ignore new request if the previous is not completed yet. 
                OnBringPointIntoViewCompleted(new BringPointIntoViewCompletedEventArgs(
                    point, null, false, null, false, userState)); 
            }
            else
            {
                pendingRequest = new BringPointIntoViewRequest(point, userState); 
                _pendingRequest = pendingRequest;
 
                pageTextView = GetTextViewFromPoint(point, false); 
                // If the point is currently in the view, use existing TextView to retrieve the position.
                // Otherwise, let the viewer handle the request. 
                if (pageTextView != null)
                {
                    // Transform to DocumentPageView coordinates and query inner TextView
                    point = TransformToDescendant(pageTextView.RenderScope, point); 
                    position = pageTextView.GetTextPositionFromPoint(point, true);
 
                    pendingRequest.Position = position; 
                    OnBringPointIntoViewCompleted(pendingRequest);
                } 
                else
                {
                    // Request to bring point into view in the Viewer.
                    // This code is specific to known viewers. Since text selection is not 
                    // exposed in a public way, it should not cause any "extensibility" problems.
                    GeneralTransform transform = _renderScope.TransformToAncestor(_viewer); 
 
                    //
 
                    transform.TryTransform(point, out point);
                    bringIntoViewPending = false;
                    if (_viewer is FlowDocumentPageViewer)
                    { 
                        // Special handling for FlowDocumentPageViewer
                        bringIntoViewPending = ((FlowDocumentPageViewer)_viewer).BringPointIntoView(point); 
                    } 
                    else if (_viewer is DocumentViewer)
                    { 
                        // Special handling for DocumentViewer
                        bringIntoViewPending = ((DocumentViewer)_viewer).BringPointIntoView(point);
                    }
                    else 
                    {
                        if (DoubleUtil.LessThan(point.X, 0)) 
                        { 
                            if (_viewer.CanGoToPreviousPage)
                            { 
                                _viewer.PreviousPage();
                                bringIntoViewPending = true;
                            }
                        } 
                        else if (DoubleUtil.GreaterThan(point.X, _viewer.RenderSize.Width))
                        { 
                            if (_viewer.CanGoToNextPage) 
                            {
                                _viewer.NextPage(); 
                                bringIntoViewPending = true;
                            }
                        }
                        else if (DoubleUtil.LessThan(point.Y, 0)) 
                        {
                            if (_viewer.CanGoToPreviousPage) 
                            { 
                                _viewer.PreviousPage();
                                bringIntoViewPending = true; 
                            }
                        }
                        else if (DoubleUtil.GreaterThan(point.Y, _viewer.RenderSize.Height))
                        { 
                            if (_viewer.CanGoToNextPage)
                            { 
                                _viewer.NextPage(); 
                                bringIntoViewPending = true;
                            } 
                        }
                    }
                    if (!bringIntoViewPending)
                    { 
                        OnBringPointIntoViewCompleted(pendingRequest);
                    } 
                } 
            }
        } 

        /// 
        /// 
        ///  
        internal override void BringLineIntoViewAsync(ITextPointer position, double suggestedX, int count, object userState)
        { 
            // Verify that layout information is valid. Cannot continue if not valid. 
            if (!IsValid)
            { 
                throw new InvalidOperationException(SR.Get(SRID.TextViewInvalidLayout));
            }
            if (_pendingRequest != null)
            { 
                // Ignore new request if the previous is not completed yet.
                OnBringLineIntoViewCompleted(new BringLineIntoViewCompletedEventArgs( 
                    position, suggestedX, count, position, suggestedX, 0, false, null, false, userState)); 
            }
            else 
            {
                _pendingRequest = new BringLineIntoViewRequest(position, suggestedX, count, userState);
                BringLineIntoViewCore((BringLineIntoViewRequest)_pendingRequest);
            } 

        } 
 
        /// 
        ///  
        /// 
        internal override void BringPageIntoViewAsync(ITextPointer position, Point suggestedOffset, int count, object userState)
        {
            // Verify that layout information is valid. Cannot continue if not valid. 
            if (!IsValid)
            { 
                throw new InvalidOperationException(SR.Get(SRID.TextViewInvalidLayout)); 
            }
            if (_pendingRequest != null) 
            {
                // Ignore new request if the previous is not completed yet.
                OnBringPageIntoViewCompleted(new BringPageIntoViewCompletedEventArgs(
                    position, suggestedOffset, count, position, suggestedOffset, 0, false, null, false, userState)); 
            }
            else 
            { 
                _pendingRequest = new BringPageIntoViewRequest(position, suggestedOffset, count, userState);
                BringPageIntoViewCore((BringPageIntoViewRequest)_pendingRequest); 
            }

        }
 

        ///  
        ///  
        /// 
        internal override void CancelAsync(object userState) 
        {
            BringLineIntoViewRequest lineRequest;
            BringPageIntoViewRequest pageRequest;
            BringPointIntoViewRequest pointRequest; 
            BringPositionIntoViewRequest positionRequest;
 
            if (_pendingRequest != null) 
            {
                if (_pendingRequest is BringLineIntoViewRequest) 
                {
                    lineRequest = (BringLineIntoViewRequest)_pendingRequest;
                    OnBringLineIntoViewCompleted(new BringLineIntoViewCompletedEventArgs(
                        lineRequest.Position, lineRequest.SuggestedX, lineRequest.Count, 
                        lineRequest.NewPosition, lineRequest.NewSuggestedX, lineRequest.Count - lineRequest.NewCount,
                        false, null, true, lineRequest.UserState)); 
                } 
                else if (_pendingRequest is BringPageIntoViewRequest)
                { 
                    pageRequest = (BringPageIntoViewRequest)_pendingRequest;
                    OnBringPageIntoViewCompleted(new BringPageIntoViewCompletedEventArgs(
                        pageRequest.Position, pageRequest.SuggestedOffset, pageRequest.Count,
                        pageRequest.NewPosition, pageRequest.NewSuggestedOffset, pageRequest.Count - pageRequest.NewCount, 
                        false, null, true, pageRequest.UserState));
                } 
                else if (_pendingRequest is BringPointIntoViewRequest) 
                {
                    pointRequest = (BringPointIntoViewRequest)_pendingRequest; 
                    OnBringPointIntoViewCompleted(new BringPointIntoViewCompletedEventArgs(
                        pointRequest.Point, pointRequest.Position, false, null, true, pointRequest.UserState));
                }
                else if (_pendingRequest is BringPositionIntoViewRequest) 
                {
                    positionRequest = (BringPositionIntoViewRequest)_pendingRequest; 
                    OnBringPositionIntoViewCompleted(new BringPositionIntoViewCompletedEventArgs( 
                        positionRequest.Position, false, null, true, positionRequest.UserState));
                } 
                _pendingRequest = null;
            }
        }
 
        /// 
        /// Collection of DocumentPageViews has been changed. Need to update 
        /// collection of TextViews. 
        /// 
        internal void OnPagesUpdated() 
        {
            OnPagesUpdatedCore();
            if (IsValid)
            { 
                OnUpdated(EventArgs.Empty);
            } 
        } 

        ///  
        /// Invoked when Page Layout has changed in order to keep
        /// the TextView in [....].
        /// 
        internal void OnPageLayoutChanged() 
        {
            if (IsValid) 
            { 
                OnUpdated(EventArgs.Empty);
            } 
        }


        ///  
        /// Retrieves an active TextView containing the object or character
        /// represented by the given TextPointer. 
        ///  
        /// Position of an object/character.
        ///  
        /// Active TextView containing the object or character represented by
        /// the given TextPointer.
        /// 
        internal ITextView GetPageTextViewFromPosition(ITextPointer position) 
        {
            // Verify that layout information is valid. Cannot continue if not valid. 
            if (!IsValid) 
            {
                throw new InvalidOperationException(SR.Get(SRID.TextViewInvalidLayout)); 
            }
            return GetTextViewFromPosition(position);
        }
 
        #endregion Internal Methods
 
        //------------------------------------------------------------------- 
        //
        //  Internal Properties 
        //
        //--------------------------------------------------------------------

        #region Internal Properties 

        ///  
        ///  
        /// 
        internal override UIElement RenderScope 
        {
            get { return _renderScope; }
        }
 
        /// 
        ///  
        ///  
        internal override ITextContainer TextContainer
        { 
            get { return _textContainer; }
        }

        ///  
        /// 
        ///  
        internal override bool IsValid 
        {
            get 
            {
                bool valid = false;
                if (_pageTextViews != null)
                { 
                    valid = true;
                    for (int i = 0; i < _pageTextViews.Count; i++) 
                    { 
                        if (!_pageTextViews[i].IsValid)
                        { 
                            valid = false;
                            break;
                        }
                    } 
                }
                return valid; 
            } 
        }
 

        /// 
        /// 
        ///  
        internal override bool RendersOwnSelection
        { 
            get 
            {
                if (_pageTextViews != null && _pageTextViews.Count > 0) 
                {
                    return _pageTextViews[0].RendersOwnSelection;
                }
                return false; 
            }
        } 
 

        ///  
        /// 
        /// 
        internal override ReadOnlyCollection TextSegments
        { 
            get
            { 
                List textSegments = new List(); 
                if (IsValid)
                { 
                    // Get collection of active TextViews for all PageDocumentViews.
                    for (int i = 0; i < _pageTextViews.Count; i++)
                    {
                        textSegments.AddRange(_pageTextViews[i].TextSegments); 
                    }
                } 
                return new ReadOnlyCollection(textSegments); 
            }
        } 

        #endregion Internal Properties

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

        /// 
        /// Collection of DocumentPageViews has been changed. Need to update 
        /// collection of TextViews.
        ///  
        private void OnPagesUpdatedCore() 
        {
            ReadOnlyCollection pageViews; 
            DocumentPageTextView pageTextView;
            int index;

            // Drop old collection of DocumentPageTextView objects. 
            for (index = 0; index < _pageTextViews.Count; index++)
            { 
                _pageTextViews[index].Updated -= new EventHandler(HandlePageTextViewUpdated); 
            }
 
            _pageTextViews.Clear();
            pageViews = _viewer.PageViews;
            if (pageViews != null)
            { 
                for (index = 0; index < pageViews.Count; index++)
                { 
                    pageTextView = ((IServiceProvider)pageViews[index]).GetService(typeof(ITextView)) as DocumentPageTextView; 
                    if (pageTextView != null)
                    { 
                        _pageTextViews.Add(pageTextView);
                        pageTextView.Updated += new EventHandler(HandlePageTextViewUpdated);
                    }
                } 
            }
        } 
 
        /// 
        /// Handler for Updated event raised by the inner TextView. 
        /// 
        private void HandlePageTextViewUpdated(object sender, EventArgs e)
        {
            OnUpdated(EventArgs.Empty); 
        }
 
        ///  
        /// Bring line into view.
        ///  
        private void BringLineIntoViewCore(BringLineIntoViewRequest request)
        {
            ITextPointer newPosition;
            double newSuggestedX; 
            int linesMoved;
            int pageNumber; 
 
            // Try to use existing TextViews to handle this request.
            newPosition = GetPositionAtNextLineCore(request.NewPosition, request.NewSuggestedX, request.NewCount, out newSuggestedX, out linesMoved, out pageNumber); 
            Invariant.Assert(Math.Abs(request.NewCount) >= Math.Abs(linesMoved));
            request.NewPosition = newPosition;
            request.NewSuggestedX = newSuggestedX;
            request.NewCount = request.NewCount - linesMoved; 
            request.NewPageNumber = pageNumber;
 
            if (request.NewCount == 0) 
            {
                OnBringLineIntoViewCompleted(request); 
            }
            else
            {
                if (newPosition is DocumentSequenceTextPointer || newPosition is FixedTextPointer) 
                {
                    //Fixed generally uses a stitched viewing mechanism and the approach used for Flow does not work properly for Fixed 
                    //NextPage() call in DocumentViewer results in DocumentGrid.ScrollToNextRow() which scrolls to firstVisibleRow + 1 
                    //E.g. if there are two views on the screen and we need to navigate to the third, this makes it impossible to achieve
                    if (_viewer.CanGoToPage(pageNumber + 1)) 
                    {
                        _viewer.GoToPage(pageNumber + 1);
                    }
                    else 
                    {
                        OnBringLineIntoViewCompleted(request); 
                    } 
                }
                else 
                {
                    if (request.NewCount > 0)
                    {
                        // If the viewer can navigate to the next page, request navigation and wait for 
                        // Updated event for the TextView.
                        // If cannot to the next page, raise BringLineIntoViewCompleted with success = 'False'. 
                        if (_viewer.CanGoToNextPage) 
                        {
                            _viewer.NextPage(); 
                        }
                        else
                        {
                            OnBringLineIntoViewCompleted(request); 
                        }
                    } 
                    else 
                    {
                        // If the viewer can navigate to the previous page, request navigation and wait for 
                        // Updated event fo the TextView.
                        // If cannot to the previous page, raise BringLineIntoViewCompleted with success = 'False'.
                        if (_viewer.CanGoToPreviousPage)
                        { 
                            _viewer.PreviousPage();
                        } 
                        else 
                        {
                            OnBringLineIntoViewCompleted(request); 
                        }
                    }
                }
            } 
        }
 
        ///  
        /// Bring page into view.
        ///  
        private void BringPageIntoViewCore(BringPageIntoViewRequest request)
        {
            ITextPointer newPosition;
            Point newSuggestedOffset; 
            int pagesMoved;
            int newPageNumber; 
 
            // Try to use existing TextViews to handle this request.
            newPosition = GetPositionAtNextPageCore(request.NewPosition, request.NewSuggestedOffset, request.NewCount, out newSuggestedOffset, out pagesMoved, out newPageNumber); 
            Invariant.Assert(Math.Abs(request.NewCount) >= Math.Abs(pagesMoved));
            request.NewPosition = newPosition;
            request.NewSuggestedOffset = newSuggestedOffset;
            request.NewCount = request.NewCount - pagesMoved; 

            if (request.NewCount == 0 || newPageNumber == -1) 
            { 
                OnBringPageIntoViewCompleted(request);
            } 
            else
            {
                // If the viewer can navigate to the next page, request navigation and wait for
                // Updated event for the TextView. 
                // If cannot to the next page, raise BringLineIntoViewCompleted with success = 'False'.
                newPageNumber += (request.NewCount > 0) ? 1 : -1; 
                if (_viewer.CanGoToPage(newPageNumber + 1)) 
                {
                    request.NewPageNumber = newPageNumber; 
                    _viewer.GoToPage(newPageNumber + 1);
                }
                else
                { 
                    OnBringPageIntoViewCompleted(request);
                } 
            } 
        }
 
        /// 
        /// 
        /// 
        private ITextPointer GetPositionAtNextLineCore(ITextPointer position, double suggestedX, int count, out double newSuggestedX, out int linesMoved, out int pageNumber) 
        {
            ITextPointer positionOut; 
            DocumentPageTextView pageTextView; 
            int originalCount;
            Point offset; 
            int newLinesMoved;
            int previousCount;
            ReadOnlyCollection segments;
 
            pageTextView = GetTextViewFromPosition(position);
            if (pageTextView != null) 
            { 
                originalCount = count;
 
                // Transform to DocumentPageView coordinates
                offset = TransformToDescendant(pageTextView.RenderScope, new Point(suggestedX, 0));
                suggestedX = offset.X;
 
                // Query inner TextView
                positionOut = pageTextView.GetPositionAtNextLine(position, suggestedX, count, out newSuggestedX, out linesMoved); 
                pageNumber = ((DocumentPageView)pageTextView.RenderScope).PageNumber; 

                // Transform from DocumentPageView coordinates 
                offset = TransformToAncestor(pageTextView.RenderScope, new Point(newSuggestedX, 0));
                newSuggestedX = offset.X;

                // If number of lines moved is different than requested number of lines, 
                // try to find query the previous/next page.
                while (originalCount != linesMoved) 
                { 
                    newLinesMoved = 0;
                    count = originalCount - linesMoved; 

                    // Try to find TextView for DocumentPageView with the next/previous page number.
                    pageNumber += (count > 0) ? 1 : -1;
                    pageTextView = GetTextViewFromPageNumber(pageNumber); 
                    if (pageTextView != null)
                    { 
                        // All positions have to be in the TextView boundary. 
                        // Since we are quering another TextView, move requested position to its range.
                        segments = pageTextView.TextSegments; 
                        previousCount = count;
                        if (count > 0)
                        {
                            position = pageTextView.GetTextPositionFromPoint(new Point(suggestedX, 0), true); 
                            if (position != null)
                            { 
                                --count; 
                                ++linesMoved;
                            } 
                        }
                        else
                        {
                            position = pageTextView.GetTextPositionFromPoint(new Point(suggestedX, pageTextView.RenderScope.RenderSize.Height), true); 
                            if (position != null)
                            { 
                                ++count; 
                                --linesMoved;
                            } 
                        }

                        if (position != null)
                        { 
                            // If moving to the first/last line of the next/previous TextView, there is
                            // special handling needed to position at the right suggestedX. Otherwise, TextView 
                            // will return the same position. 
                            if (count == 0)
                            { 
                                positionOut = GetPositionAtPageBoundary(previousCount > 0, pageTextView, position, suggestedX);
                                newSuggestedX = suggestedX;
                            }
                            else 
                            {
                                // Query nested TextView. 
                                // Use the same logical 'suggestedX' as for previous DocumentPageView. 
                                positionOut = pageTextView.GetPositionAtNextLine(position, suggestedX, count, out newSuggestedX, out newLinesMoved);
                                linesMoved += newLinesMoved; 
                            }

                            // Transform from DocumentPageView coordinates
                            offset = TransformToAncestor(pageTextView.RenderScope, new Point(newSuggestedX, 0)); 
                            newSuggestedX = offset.X;
                        } 
                    } 
                    else
                    { 
                        // If DocumentPageView has not been found, there is no point
                        // to continue.
                        // 'positionOut' contains the closes position we can return.
                        break; 
                    }
                } 
            } 
            else
            { 
                positionOut = position;
                linesMoved = 0;
                newSuggestedX = suggestedX;
                pageNumber = -1; 
            }
            return positionOut; 
        } 

        private ITextPointer GetPositionAtNextPageCore(ITextPointer position, Point suggestedOffset, int count, out Point newSuggestedOffset, out int pagesMoved, out int pageNumber) 
        {
            // Initialize output
            ITextPointer positionOut = position;
            pagesMoved = 0; 
            newSuggestedOffset = suggestedOffset;
            pageNumber = -1; 
 
            DocumentPageTextView pageTextView = GetTextViewFromPosition(position);
            if (pageTextView != null) 
            {
                int currentPageNumber = ((DocumentPageView)pageTextView.RenderScope).PageNumber;
                DocumentPageTextView newPageTextView = GetTextViewForNextPage(currentPageNumber, count, out pageNumber);
                pagesMoved = pageNumber - currentPageNumber; 
                Invariant.Assert(Math.Abs(pagesMoved) <= Math.Abs(count));
 
                if (pageNumber != currentPageNumber && newPageTextView != null) 
                {
                    // Transform suggested offset to to DocumentPageView coordinates to use as X-coordinate 
                    Point point = TransformToDescendant(pageTextView.RenderScope, suggestedOffset);

                    // Query inner TextView for requested page to find position at that point.
                    positionOut = newPageTextView.GetTextPositionFromPoint(point, /*snapToText*/true); 
                    if (positionOut != null)
                    { 
                        Rect rect = newPageTextView.GetRectangleFromTextPosition(positionOut); 
                        point = TransformToAncestor(pageTextView.RenderScope, new Point(rect.X, rect.Y));
                        newSuggestedOffset = point; 
                    }
                    else
                    {
                        positionOut = position; 
                        pagesMoved = 0;
                        pageNumber = currentPageNumber; 
                    } 
                }
                else 
                {
                    pagesMoved = 0;
                    pageNumber = currentPageNumber;
                } 
            }
 
            return positionOut; 
        }
 
        /// 
        /// Retrieves position at the page boundary from given suggestedX.
        /// 
        /// Whether asking for top of the page or bottom of the page. 
        /// TextView representing the page.
        /// Position at the beginning/end of the page. 
        /// Suggested offset in the page. 
        /// Position at the page boundary from given suggestedX.
        private ITextPointer GetPositionAtPageBoundary(bool pageTop, ITextView pageTextView, ITextPointer position, double suggestedX) 
        {
            double newSuggestedX;
            int newLinesMoved;
            ITextPointer positionOut; 

            // If moving to the first/last line of the next/previous TextView, there is 
            // special handling needed to position at the right suggestedX. Otherwise, TextView 
            // will return the same position.
            if (pageTop) 
            {
                // Move line down and line up.
                positionOut = pageTextView.GetPositionAtNextLine(position, suggestedX, 1, out newSuggestedX, out newLinesMoved);
                if (newLinesMoved == 1) 
                {
                    positionOut = pageTextView.GetPositionAtNextLine(positionOut, newSuggestedX, -1, out newSuggestedX, out newLinesMoved); 
                } 
                else
                { 
                    // Line down failed, so use the first position of TextView.
                    positionOut = position;
                }
            } 
            else
            { 
                // Move line up and line down. 
                positionOut = pageTextView.GetPositionAtNextLine(position, suggestedX, -1, out newSuggestedX, out newLinesMoved);
                if (newLinesMoved == -1) 
                {
                    positionOut = pageTextView.GetPositionAtNextLine(positionOut, newSuggestedX, 1, out newSuggestedX, out newLinesMoved);
                }
                else 
                {
                    // Line up failed, so use the last position of TextView. 
                    positionOut = position; 
                }
            } 
            return positionOut;
        }

        ///  
        /// Returns an active TextView that matches the supplied Point.
        ///  
        /// Point in pixel coordinates to test. 
        /// Snap to closest TextView.
        /// An active TextView that matches the supplied Point. 
        private DocumentPageTextView GetTextViewFromPoint(Point point, bool snap)
        {
            DocumentPageTextView textView = null;
            Rect textViewBounds; 
            int i;
 
            // Try to find pageElement with exact hit. 
            // Enumerate all inner TextViews and try to find exact hit for given Point.
            for (i = 0; i < _pageTextViews.Count; i++) 
            {
                textViewBounds = TransformToAncestor(_pageTextViews[i].RenderScope, new Rect(_pageTextViews[i].RenderScope.RenderSize));
                if (textViewBounds.Contains(point))
                { 
                    textView = _pageTextViews[i];
                    break; 
                } 
            }
 
            if (textView == null && snap)
            {
                // For each TextView calculate 'proximity' function.
                double[] textViewProximities = new double[_pageTextViews.Count]; 
                for (i = 0; i < _pageTextViews.Count; i++)
                { 
                    textViewBounds = TransformToAncestor(_pageTextViews[i].RenderScope, new Rect(_pageTextViews[i].RenderScope.RenderSize)); 
                    double horz, vert;
                    if (point.X >= textViewBounds.Left && point.X <= textViewBounds.Right) 
                    {
                        horz = 0;
                    }
                    else 
                    {
                        horz = Math.Min(Math.Abs(point.X - textViewBounds.Left), Math.Abs(point.X - textViewBounds.Right)); 
                    } 
                    if (point.Y >= textViewBounds.Top && point.Y <= textViewBounds.Bottom)
                    { 
                        vert = 0;
                    }
                    else
                    { 
                        vert = Math.Min(Math.Abs(point.Y - textViewBounds.Top), Math.Abs(point.Y - textViewBounds.Bottom));
                    } 
                    textViewProximities[i] = Math.Sqrt(Math.Pow(horz, 2) + Math.Pow(vert, 2)); 
                }
                // Get the closest TextView according to 'proximity' function. 
                double proximity = double.MaxValue;
                for (i = 0; i < textViewProximities.Length; i++)
                {
                    if (proximity > textViewProximities[i]) 
                    {
                        proximity = textViewProximities[i]; 
                        textView = _pageTextViews[i]; 
                    }
                } 
            }

            return textView;
        } 

        ///  
        /// Retrieves an active TextView containing the object or character 
        /// represented by the given TextPointer.
        ///  
        /// Position of an object/character.
        /// 
        /// Active TextView containing the object or character represented by
        /// the given TextPointer. 
        /// 
        private DocumentPageTextView GetTextViewFromPosition(ITextPointer position) 
        { 
            DocumentPageTextView textView = null;
            int i; 

            // Try to find pageElement with exact hit.
            for (i = 0; i < _pageTextViews.Count; i++)
            { 
                if (_pageTextViews[i].Contains(position))
                { 
                    textView = _pageTextViews[i]; 
                    break;
                } 
            }

            return textView;
        } 

        ///  
        /// Retrieves an active TextView from DocumentPageView with specified page number. 
        /// 
        /// Page number. 
        /// 
        /// Active TextView from DocumentPageView with specified page number.
        /// 
        private DocumentPageTextView GetTextViewFromPageNumber(int pageNumber) 
        {
            DocumentPageTextView textView = null; 
            int i; 

            // Try to find pageElement with exact hit. 
            for (i = 0; i < _pageTextViews.Count; i++)
            {
                if (_pageTextViews[i].DocumentPageView.PageNumber == pageNumber)
                { 
                    textView = _pageTextViews[i];
                    break; 
                } 
            }
            return textView; 
        }

        /// 
        /// Given page number and count, retrieves an active TextView at distance count from the specified page number 
        /// 
        /// Page number. 
        /// Number of pages between specified page number and desired page number 
        /// Page number of the view that is actually returned
        ///  
        /// If there is no view at distance count from the specified page number in the list of views, return the page text view that's
        /// closest in the direction of count, i.e. if we're on page 2 and count = 5, and we have pages 5 and 10 in view but not page 7, return
        /// 5, i.e. we never move by > count
        ///  
        private DocumentPageTextView GetTextViewForNextPage(int pageNumber, int count, out int newPageNumber)
        { 
            Invariant.Assert(count != 0); 
            newPageNumber = pageNumber + count;
            int closestPageNumber = newPageNumber; 
            DocumentPageTextView textView = null;
            int closestDistance = Math.Abs(count);

            for (int i = 0; i < _pageTextViews.Count; i++) 
            {
                if (_pageTextViews[i].DocumentPageView.PageNumber == newPageNumber) 
                { 
                    textView = _pageTextViews[i];
                    closestPageNumber = newPageNumber; 
                    break;
                }
                else
                { 
                    int currentPageNumber = _pageTextViews[i].DocumentPageView.PageNumber;
                    if (count > 0 && currentPageNumber > pageNumber) 
                    { 
                        int distance = currentPageNumber - pageNumber;
                        if (distance < closestDistance) 
                        {
                            closestDistance = distance;
                            textView = _pageTextViews[i];
                            closestPageNumber = currentPageNumber; 
                        }
                    } 
                    else if (count < 0 && currentPageNumber < pageNumber) 
                    {
                        int distance = Math.Abs(currentPageNumber - pageNumber); 
                        if (distance < closestDistance)
                        {
                            closestDistance = distance;
                            textView = _pageTextViews[i]; 
                            closestPageNumber = currentPageNumber;
                        } 
                    } 
                }
            } 

            if (textView != null)
            {
                newPageNumber = closestPageNumber; 
            }
            else 
            { 
                newPageNumber = pageNumber;
                textView = GetTextViewFromPageNumber(pageNumber); 
            }
            Invariant.Assert(newPageNumber >= 0);
            return textView;
        } 

 
        ///  
        /// Gets transform to ancestor for inner scope
        ///  
        private Transform GetTransformToAncestor(Visual innerScope)
        {
            // NOTE: TransformToAncestor is safe (will never throw an exception).
            Transform transform = innerScope.TransformToAncestor(_renderScope) as Transform; 
            if (transform == null)
            { 
                transform = Transform.Identity; 
            }
            return transform; 
        }

        /// 
        /// Transforms rectangle from inner scope. 
        /// 
        private Rect TransformToAncestor(Visual innerScope, Rect rect) 
        { 
            if (rect != Rect.Empty)
            { 
                // NOTE: TransformToAncestor is safe (will never throw an exception).
                GeneralTransform transform = innerScope.TransformToAncestor(_renderScope);
                if (transform != null)
                { 
                    rect = transform.TransformBounds(rect);
                } 
            } 
            return rect;
        } 

        /// 
        /// Transforms point from inner scope.
        ///  
        private Point TransformToAncestor(Visual innerScope, Point point)
        { 
            // NOTE: TransformToAncestor is safe (will never throw an exception). 
            GeneralTransform transform = innerScope.TransformToAncestor(_renderScope);
            if (transform != null) 
            {
                point = transform.Transform(point);
            }
            return point; 
        }
 
        ///  
        /// Transforms rectangle from inner scope
        ///  
        private Point TransformToDescendant(Visual innerScope, Point point)
        {
            // NOTE: TransformToAncestor is safe (will never throw an exception).
            GeneralTransform transform = innerScope.TransformToAncestor(_renderScope); 
            if (transform != null)
            { 
                transform = transform.Inverse; 
                if (transform != null)
                { 
                    point = transform.Transform(point);
                }
            }
            return point; 
        }
 
        ///  
        /// Fires BringPositionIntoViewCompleted event.
        ///  
        private void OnBringPositionIntoViewCompleted(BringPositionIntoViewRequest request)
        {
            _pendingRequest = null;
            OnBringPositionIntoViewCompleted(new BringPositionIntoViewCompletedEventArgs( 
                request.Position, request.Succeeded, null, false, request.UserState));
        } 
 
        /// 
        /// Fires BringPointIntoViewCompleted event. 
        /// 
        private void OnBringPointIntoViewCompleted(BringPointIntoViewRequest request)
        {
            _pendingRequest = null; 
            OnBringPointIntoViewCompleted(new BringPointIntoViewCompletedEventArgs(
                request.Point, request.Position, 
                request.Position != null, null, false, request.UserState)); 
        }
 
        /// 
        /// Fires BringLineIntoViewCompleted event.
        /// 
        private void OnBringLineIntoViewCompleted(BringLineIntoViewRequest request) 
        {
            _pendingRequest = null; 
            OnBringLineIntoViewCompleted(new BringLineIntoViewCompletedEventArgs( 
                request.Position, request.SuggestedX, request.Count,
                request.NewPosition, request.NewSuggestedX, request.Count - request.NewCount, 
                request.NewCount == 0, null, false, request.UserState));
        }

        ///  
        /// Fires BringPageIntoViewCompleted event.
        ///  
        private void OnBringPageIntoViewCompleted(BringPageIntoViewRequest request) 
        {
            _pendingRequest = null; 
            OnBringPageIntoViewCompleted(new BringPageIntoViewCompletedEventArgs(
                request.Position, request.SuggestedOffset, request.Count,
                request.NewPosition, request.NewSuggestedOffset, request.Count - request.NewCount,
                request.NewCount == 0, null, false, request.UserState)); 
        }
 
        ///  
        /// Responds to an OnUpdated call.
        ///  
        private object OnUpdatedWorker(object o)
        {
            BringLineIntoViewRequest lineRequest;
            BringPageIntoViewRequest pageRequest; 
            BringPointIntoViewRequest pointRequest;
            BringPositionIntoViewRequest positionRequest; 
            ITextView pageTextView; 
            ITextPointer newPosition;
            Point point; 
            double suggestedX;

            if (this.IsValid && _pendingRequest != null)
            { 
                if (_pendingRequest is BringLineIntoViewRequest)
                { 
                    lineRequest = (BringLineIntoViewRequest)_pendingRequest; 

                    // Try to find TextView for DocumentPageView with stored page number. 
                    pageTextView = GetTextViewFromPageNumber(lineRequest.NewPageNumber);
                    if (pageTextView != null)
                    {
                        // Transform to DocumentPageView coordinates 
                        point = TransformToDescendant(pageTextView.RenderScope, new Point(lineRequest.NewSuggestedX, 0));
                        suggestedX = point.X; 
 
                        // All positions have to be in the TextView boundary.
                        // Since we are quering another TextView, move requested position to its range. 
                        if (lineRequest.Count > 0)
                        {
                            // Search for a point just outside the limits so that GetTextView.GetTextPositionFromPoint will not hit test
                            // inside anchored blocks unless they are offset out of the page. 
                            newPosition = pageTextView.GetTextPositionFromPoint(new Point(-1, -1), true);
                            if (newPosition != null) 
                            { 
                                lineRequest.NewCount = lineRequest.NewCount - 1;
                            } 
                        }
                        else
                        {
                            newPosition = pageTextView.GetTextPositionFromPoint((Point)pageTextView.RenderScope.RenderSize, true); 
                            if (newPosition != null)
                            { 
                                lineRequest.NewCount = lineRequest.NewCount + 1; 
                            }
                        } 

                        // If still have some lines to be moved, do another BringLineIntoView request.
                        // Otherwise the goal has been reached and fire completed event.
                        if (newPosition == null) 
                        {
                            // New position cannot be found, return best result so far. 
                            if (lineRequest.NewPosition == null) 
                            {
                                lineRequest.NewPosition = lineRequest.Position; 
                                lineRequest.NewCount = lineRequest.Count;
                            }
                            OnBringLineIntoViewCompleted(lineRequest);
                        } 
                        else if (lineRequest.NewCount != 0)
                        { 
                            lineRequest.NewPosition = newPosition; 
                            BringLineIntoViewCore(lineRequest);
                        } 
                        else
                        {
                            lineRequest.NewPosition = GetPositionAtPageBoundary(lineRequest.Count > 0, pageTextView, newPosition, lineRequest.NewSuggestedX);
                            OnBringLineIntoViewCompleted(lineRequest); 
                        }
                    } 
                    else if(IsPageNumberOutOfRange(lineRequest.NewPageNumber)) 
                    {
                        OnBringLineIntoViewCompleted(lineRequest); 
                    }
                }
                else if (_pendingRequest is BringPageIntoViewRequest)
                { 
                    pageRequest = (BringPageIntoViewRequest)_pendingRequest;
 
                    // Try to find TextView for DocumentPageView with stored page number. 
                    pageTextView = GetTextViewFromPageNumber(pageRequest.NewPageNumber);
                    if (pageTextView != null) 
                    {
                        // Transform to DocumentPageView coordinates
                        point = TransformToDescendant(pageTextView.RenderScope, pageRequest.NewSuggestedOffset);
                        Point suggestedOffset = point; 

                        Invariant.Assert(pageRequest.NewCount != 0); 
                        newPosition = pageTextView.GetTextPositionFromPoint(suggestedOffset, true); 
                        if (newPosition != null)
                        { 
                            pageRequest.NewCount = (pageRequest.Count > 0) ? pageRequest.NewCount - 1 : pageRequest.NewCount + 1;
                        }

                        // If still have some lines to be moved, do another BringLineIntoView request. 
                        // Otherwise the goal has been reached and fire completed event.
                        if (newPosition == null) 
                        { 
                            // New position cannot be found, return best result so far.
                            if (pageRequest.NewPosition == null) 
                            {
                                pageRequest.NewPosition = pageRequest.Position;
                                pageRequest.NewCount = pageRequest.Count;
                            } 
                            OnBringPageIntoViewCompleted(pageRequest);
                        } 
                        else if (pageRequest.NewCount != 0) 
                        {
                            pageRequest.NewPosition = newPosition; 
                            BringPageIntoViewCore(pageRequest);
                        }
                        else
                        { 
                            pageRequest.NewPosition = newPosition;
                            OnBringPageIntoViewCompleted(pageRequest); 
                        } 
                    }
                    else if(IsPageNumberOutOfRange(pageRequest.NewPageNumber)) 
                    {
                        OnBringPageIntoViewCompleted(pageRequest);
                    }
                } 
                else if (_pendingRequest is BringPointIntoViewRequest)
                { 
                    pointRequest = (BringPointIntoViewRequest)_pendingRequest; 

                    pageTextView = GetTextViewFromPoint(pointRequest.Point, true); 
                    if (pageTextView != null)
                    {
                        // Transform to DocumentPageView coordinates and query inner TextView
                        point = TransformToDescendant(pageTextView.RenderScope, pointRequest.Point); 
                        pointRequest.Position = pageTextView.GetTextPositionFromPoint(point, true);
                    } 
                    OnBringPointIntoViewCompleted(pointRequest); 
                }
                else if (_pendingRequest is BringPositionIntoViewRequest) 
                {
                    positionRequest = (BringPositionIntoViewRequest)_pendingRequest;
                    positionRequest.Succeeded = positionRequest.Position.HasValidLayout;
                    OnBringPositionIntoViewCompleted(positionRequest); 
                }
            } 
 
            return null;
        } 

        /// 
        /// Distinguishes between whether a page is not available now, or will never be available.
        ///  
        private bool IsPageNumberOutOfRange(int pageNumber)
        { 
            if(pageNumber < 0) 
            {
                return true; 
            }

            IDocumentPaginatorSource document = _viewer.Document;
            if(document == null) 
            {
                return true; 
            } 

            DocumentPaginator documentPaginator = document.DocumentPaginator; 

            if(documentPaginator == null)
            {
                return true; 
            }
 
            if(documentPaginator.IsPageCountValid && pageNumber >= documentPaginator.PageCount) 
            {
                return true; 
            }

            return false;
        } 

        #endregion Private Methods 
 
        //-------------------------------------------------------------------
        // 
        //  Private Fields
        //
        //--------------------------------------------------------------------
 
        #region Private Fields
 
        ///  
        /// Viewer associated with TextView.
        ///  
        private readonly DocumentViewerBase _viewer;

        /// 
        /// Root of layout structure visualizing content. 
        /// 
        private readonly UIElement _renderScope; 
 
        /// 
        /// TextContainer representing content. 
        /// 
        private readonly ITextContainer _textContainer;

        ///  
        /// Collection of hosted TextViews.
        ///  
        private List _pageTextViews; 

        ///  
        /// Pending BringIntoView request.
        /// 
        private BringIntoViewRequest _pendingRequest;
 
        #endregion Private Fields
 
        //------------------------------------------------------------------- 
        //
        //  Private Types 
        //
        //--------------------------------------------------------------------

        #region Private Types 

        ///  
        /// Pending BringIntoView request. 
        /// 
        private class BringIntoViewRequest 
        {
            internal BringIntoViewRequest(object userState)
            {
                this.UserState = userState; 
            }
            internal readonly object UserState; 
        } 

        ///  
        /// Pending BringPositionIntoView request.
        /// 
        private class BringPositionIntoViewRequest : BringIntoViewRequest
        { 
            internal BringPositionIntoViewRequest(ITextPointer position, object userState)
                : base(userState) 
            { 
                this.Position = position;
                this.Succeeded = false; 
            }
            internal readonly ITextPointer Position;
            internal bool Succeeded;
        } 

        ///  
        /// Pending BringPointIntoView request. 
        /// 
        private class BringPointIntoViewRequest : BringIntoViewRequest 
        {
            internal BringPointIntoViewRequest(Point point, object userState)
                : base(userState)
            { 
                this.Point = point;
                this.Position = null; 
            } 
            internal readonly Point Point;
            internal ITextPointer Position; 
        }

        /// 
        /// Pending BringLineIntoView request. 
        /// 
        private class BringLineIntoViewRequest : BringIntoViewRequest 
        { 
            internal BringLineIntoViewRequest(ITextPointer position, double suggestedX, int count, object userState)
                : base(userState) 
            {
                this.Position = position;
                this.SuggestedX = suggestedX;
                this.Count = count; 
                this.NewPosition = position;
                this.NewSuggestedX = suggestedX; 
                this.NewCount = count; 
            }
            internal readonly ITextPointer Position; 
            internal readonly double SuggestedX;
            internal readonly int Count;
            internal ITextPointer NewPosition;
            internal double NewSuggestedX; 
            internal int NewCount;
            internal int NewPageNumber; 
        } 

        ///  
        /// Pending BringPageIntoView request.
        /// 
        private class BringPageIntoViewRequest : BringIntoViewRequest
        { 
            internal BringPageIntoViewRequest(ITextPointer position, Point suggestedOffset, int count, object userState)
                : base(userState) 
            { 
                this.Position = position;
                this.SuggestedOffset = suggestedOffset; 
                this.Count = count;
                this.NewPosition = position;
                this.NewSuggestedOffset = suggestedOffset;
                this.NewCount = count; 
            }
            internal readonly ITextPointer Position; 
            internal readonly Point SuggestedOffset; 
            internal readonly int Count;
            internal ITextPointer NewPosition; 
            internal Point NewSuggestedOffset;
            internal int NewCount;
            internal int NewPageNumber;
        } 

        #endregion Private Types 
    } 
}
 

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