DocumentPageView.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Dotnetfx_Vista_SP2 / Dotnetfx_Vista_SP2 / 8.0.50727.4016 / DEVDIV / depot / DevDiv / releases / Orcas / QFE / wpf / src / Framework / System / Windows / Controls / Primitives / DocumentPageView.cs / 1 / DocumentPageView.cs

                            //---------------------------------------------------------------------------- 
//
// Copyright (C) Microsoft Corporation.  All rights reserved.
//
// File: DocumentPageView.cs 
//
// Description: Provides a view port for a page of content for a DocumentPage. 
// 
//---------------------------------------------------------------------------
 
using System.Windows.Automation;            // AutomationPattern
using System.Windows.Automation.Peers;      // AutomationPeer
using System.Windows.Controls;              // StretchDirection
using System.Windows.Controls.Primitives;   // DocumentViewerBase 
using System.Windows.Documents;             // DocumentPaginator
using System.Windows.Media;                 // Visual 
using System.Windows.Media.Imaging;         // RenderTargetBitmap 
using System.Windows.Threading;             // Dispatcher
using MS.Internal;                          // Invariant 
using MS.Internal.Documents;                // DocumentPageHost, DocumentPageTextView
using MS.Internal.Automation;               // TextAdaptor
using MS.Internal.KnownBoxes;               // BooleanBoxes
 

namespace System.Windows.Controls.Primitives 
{ 
    /// 
    /// Provides a view port for a page of content for a DocumentPage. 
    /// 
    public class DocumentPageView : FrameworkElement, IServiceProvider, IDisposable
    {
        //------------------------------------------------------------------- 
        //
        //  Constructors 
        // 
        //-------------------------------------------------------------------
 
        #region Constructors

        /// 
        /// Create an instance of a DocumentPageView. 
        /// 
        ///  
        /// This does basic initialization of the DocumentPageView.  All subclasses 
        /// must call the base constructor to perform this initialization.
        ///  
        public DocumentPageView() : base()
        {
            _pageZoom = 1.0;
        } 

        ///  
        /// Static ctor. Initializes property metadata. 
        /// 
        static DocumentPageView() 
        {
            ClipToBoundsProperty.OverrideMetadata(typeof(DocumentPageView), new PropertyMetadata(BooleanBoxes.TrueBox));
        }
 
        #endregion
 
        //-------------------------------------------------------------------- 
        //
        //  Public Properties 
        //
        //-------------------------------------------------------------------

        #region Public Properties 

        ///  
        /// The Paginator from which this DocumentPageView retrieves pages. 
        /// 
        public DocumentPaginator DocumentPaginator 
        {
            get { return _documentPaginator; }
            set
            { 
                CheckDisposed();
                if (_documentPaginator != value) 
                { 
                    // Cleanup all state associated with old Paginator.
                    if (_documentPaginator != null) 
                    {
                        _documentPaginator.GetPageCompleted -= new GetPageCompletedEventHandler(HandleGetPageCompleted);
                        _documentPaginator.PagesChanged -= new PagesChangedEventHandler(HandlePagesChanged);
                        DisposeCurrentPage(); 
                        DisposeAsyncPage();
                    } 
 
                    Invariant.Assert(_documentPage == null);
                    Invariant.Assert(_documentPageAsync == null); 
                    _documentPaginator = value;
                    _textView = null;

                    // Register for events on new Paginator and invalidate 
                    // measure to force content update.
                    if (_documentPaginator != null) 
                    { 
                        _documentPaginator.GetPageCompleted += new GetPageCompletedEventHandler(HandleGetPageCompleted);
                        _documentPaginator.PagesChanged += new PagesChangedEventHandler(HandlePagesChanged); 
                    }
                    InvalidateMeasure();
                }
            } 
        }
 
        ///  
        /// The DocumentPage for the displayed page.
        ///  
        public DocumentPage DocumentPage
        {
            get { return (_documentPage == null) ? DocumentPage.Missing : _documentPage; }
        } 

        ///  
        /// The page number displayed; no content is displayed if this number is negative. 
        /// PageNumber is zero-based.
        ///  
        public int PageNumber
        {
            get { return (int) GetValue(PageNumberProperty); }
            set { SetValue(PageNumberProperty, value); } 
        }
 
        ///  
        /// Controls the stretching behavior for the page.
        ///  
        public Stretch Stretch
        {
            get { return (Stretch)GetValue(StretchProperty); }
            set { SetValue(StretchProperty, value); } 
        }
 
        ///  
        /// Specifies the directions in which page may be stretched.
        ///  
        public StretchDirection StretchDirection
        {
            get { return (StretchDirection)GetValue(StretchDirectionProperty); }
            set { SetValue(StretchDirectionProperty, value); } 
        }
 
        #region Public Dynamic Properties 

        ///  
        /// 
        /// 
        public static readonly DependencyProperty PageNumberProperty =
                DependencyProperty.Register( 
                        "PageNumber",
                        typeof(int), 
                        typeof(DocumentPageView), 
                        new FrameworkPropertyMetadata(
                                0, 
                                FrameworkPropertyMetadataOptions.AffectsMeasure,
                                new PropertyChangedCallback(OnPageNumberChanged)));

        ///  
        /// 
        ///  
        public static readonly DependencyProperty StretchProperty = 
                Viewbox.StretchProperty.AddOwner(
                        typeof(DocumentPageView), 
                        new FrameworkPropertyMetadata(
                                Stretch.Uniform,
                                FrameworkPropertyMetadataOptions.AffectsMeasure));
 
        /// 
        ///  
        ///  
        public static readonly DependencyProperty StretchDirectionProperty =
                Viewbox.StretchDirectionProperty.AddOwner( 
                        typeof(DocumentPageView),
                        new FrameworkPropertyMetadata(
                                StretchDirection.DownOnly,
                                FrameworkPropertyMetadataOptions.AffectsMeasure)); 

        #endregion Public Dynamic Properties 
 
        #endregion Public Properties
 
        //--------------------------------------------------------------------
        //
        //  Public Events
        // 
        //--------------------------------------------------------------------
 
        #region Public Events 

        ///  
        /// Fired after a DocumentPage.Visual is connected.
        /// 
        public event EventHandler PageConnected;
 
        /// 
        /// Fired after a DocumentPage.Visual is disconnected. 
        ///  
        public event EventHandler PageDisconnected;
 
        #endregion Public Events

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

        #region Protected Methods 

        /// 
        /// Content measurement.
        ///  
        /// Available size that parent can give to the child. This is soft constraint.
        /// The DocumentPageView's desired size. 
        protected override sealed Size MeasureOverride(Size availableSize) 
        {
            Size newPageSize, pageZoom; 
            Size pageSize;
            Size desiredSize = new Size(); // If no page is available, return (0,0) as size.

            CheckDisposed(); 

            if (_suspendLayout) 
            { 
                desiredSize = this.DesiredSize;
            } 
            else if (_documentPaginator != null)
            {
                // Reflow content if needed.
                if (ShouldReflowContent()) 
                {
                    // Reflow is disabled when dealing with infinite size in both directions. 
                    // If only one dimention is infinte, calculate value based on PageSize of the 
                    // document and Stretching properties.
                    if (!Double.IsInfinity(availableSize.Width) || !Double.IsInfinity(availableSize.Height)) 
                    {
                        pageSize = _documentPaginator.PageSize;
                        if (Double.IsInfinity(availableSize.Width))
                        { 
                            newPageSize = new Size();
                            newPageSize.Height = availableSize.Height / _pageZoom; 
                            newPageSize.Width = newPageSize.Height * (pageSize.Width / pageSize.Height); // Keep aspect ratio. 
                        }
                        else if (Double.IsInfinity(availableSize.Height)) 
                        {
                            newPageSize = new Size();
                            newPageSize.Width = availableSize.Width / _pageZoom;
                            newPageSize.Height = newPageSize.Width * (pageSize.Height / pageSize.Width); // Keep aspect ratio. 
                        }
                        else 
                        { 
                            newPageSize = new Size(availableSize.Width / _pageZoom, availableSize.Height / _pageZoom);
                        } 
                        if (!DoubleUtil.AreClose(pageSize, newPageSize))
                        {
                            _documentPaginator.PageSize = newPageSize;
                        } 
                    }
                } 
 
                // If the main page or pending async page are not available yet,
                // asynchronously request new page from Paginator. 
                if (_documentPage == null && _documentPageAsync == null)
                {
                    if (PageNumber >= 0)
                    { 
                        if (_useAsynchronous)
                        { 
                            _documentPaginator.GetPageAsync(PageNumber, this); 
                        }
                        else 
                        {
                            _documentPageAsync = _documentPaginator.GetPage(PageNumber);
                            if (_documentPageAsync == null)
                            { 
                                _documentPageAsync = DocumentPage.Missing;
                            } 
                        } 
                    }
                    else 
                    {
                        _documentPage = DocumentPage.Missing;
                    }
                } 

                // If pending async page is available, discard the main page and 
                // set _documentPage to _documentPageAsync. 
                if (_documentPageAsync != null)
                { 
                    // Do cleanup for currently used page, because it gets replaced.
                    DisposeCurrentPage();
                    // DisposeCurrentPage raises PageDisposed and DocumentPage.PageDestroyed events.
                    // Handlers for those events may dispose _documentPageAsync. Treat this situation 
                    // as missing page.
                    if (_documentPageAsync == null) 
                    { 
                        _documentPageAsync = DocumentPage.Missing;
                    } 
                    if (_pageVisualClone != null)
                    {
                        RemoveDuplicateVisual();
                    } 

                    // Replace the main page with cached async page. 
                    _documentPage = _documentPageAsync; 
                    if (_documentPage != DocumentPage.Missing)
                    { 
                        _documentPage.PageDestroyed += new EventHandler(HandlePageDestroyed);
                        _documentPageAsync.PageDestroyed -= new EventHandler(HandleAsyncPageDestroyed);
                    }
                    _documentPageAsync = null; 

                    // Set a flag that will indicate that a PageConnected must be fired in 
                    // ArrangeOverride 
                    _newPageConnected = true;
                } 

                // If page is available, return its size as desired size.
                if (_documentPage != null && _documentPage != DocumentPage.Missing)
                { 
                    pageSize = new Size(_documentPage.Size.Width * _pageZoom, _documentPage.Size.Height * _pageZoom);
                    pageZoom = Viewbox.ComputeScaleFactor(availableSize, pageSize, this.Stretch, this.StretchDirection); 
                    desiredSize = new Size(pageSize.Width * pageZoom.Width, pageSize.Height * pageZoom.Height); 
                }
 
                if (_pageVisualClone != null)
                {
                    desiredSize = _visualCloneSize;
                } 
            }
 
            return desiredSize; 
        }
 
        /// 
        /// Content arrangement.
        /// 
        /// The final size that element should use to arrange itself and its children. 
        protected override sealed Size ArrangeOverride(Size finalSize)
        { 
            Transform pageTransform; 
            ScaleTransform pageScaleTransform;
            Visual pageVisual; 
            Size pageSize, pageZoom;

            CheckDisposed();
 
            if (_pageVisualClone == null)
            { 
                if (_pageHost == null) 
                {
                    _pageHost = new DocumentPageHost(); 
                    this.AddVisualChild(_pageHost);
                }
                Invariant.Assert(_pageHost != null);
 
                pageVisual = (_documentPage == null) ? null : _documentPage.Visual;
                if (pageVisual == null) 
                { 
                    // Remove existing visiual children.
                    _pageHost.PageVisual = null; 

                    // Reset offset and transform on the page host before Arrange
                    _pageHost.CachedOffset = new Point();
                    _pageHost.RenderTransform = null; 

                    // Size for the page host needs to be set to finalSize 
                    _pageHost.Arrange(new Rect(_pageHost.CachedOffset, finalSize)); 
                }
                else 
                {
                    // Add visual representing the page contents. For performance reasons
                    // first check if it is already insered there.
                    if (_pageHost.PageVisual != pageVisual) 
                    {
                        // There might be a case where a visual associated with a page was 
                        // inserted to a visual tree before. It got removed later, but GC did not 
                        // destroy its parent yet. To workaround this case always check for the parent
                        // of page visual and disconnect it, when necessary. 
                        DocumentPageHost.DisconnectPageVisual(pageVisual);

                        _pageHost.PageVisual = pageVisual;
                    } 

                    // Compute transform to be applied to the page visual. First take into account 
                    // mirroring transform, if necessary. Apply also scaling transform. 
                    pageSize = _documentPage.Size;
                    pageTransform = Transform.Identity; 

                    // DocumentPage.Visual is always LeftToRight, so if the current
                    // FlowDirection is RightToLeft, need to unmirror the child visual.
                    if (FlowDirection == FlowDirection.RightToLeft) 
                    {
                        pageTransform = new MatrixTransform(-1.0, 0.0, 0.0, 1.0, pageSize.Width, 0.0); 
                    } 

                    // Apply zooming 
                    if (!DoubleUtil.IsOne(_pageZoom))
                    {
                        pageScaleTransform = new ScaleTransform(_pageZoom, _pageZoom);
                        if (pageTransform == Transform.Identity) 
                        {
                            pageTransform = pageScaleTransform; 
                        } 
                        else
                        { 
                            pageTransform = new MatrixTransform(pageTransform.Value * pageScaleTransform.Value);
                        }
                        pageSize = new Size(pageSize.Width * _pageZoom, pageSize.Height * _pageZoom);
                    } 

                    // Apply stretch properties 
                    pageZoom = Viewbox.ComputeScaleFactor(finalSize, pageSize, this.Stretch, this.StretchDirection); 
                    if (!DoubleUtil.IsOne(pageZoom.Width) || !DoubleUtil.IsOne(pageZoom.Height))
                    { 
                        pageScaleTransform = new ScaleTransform(pageZoom.Width, pageZoom.Height);
                        if (pageTransform == Transform.Identity)
                        {
                            pageTransform = pageScaleTransform; 
                        }
                        else 
                        { 
                            pageTransform = new MatrixTransform(pageTransform.Value * pageScaleTransform.Value);
                        } 
                        pageSize = new Size(pageSize.Width * pageZoom.Width, pageSize.Height * pageZoom.Height);
                    }

                    // Set offset and transform on the page host before Arrange 
                    _pageHost.CachedOffset = new Point((finalSize.Width - pageSize.Width) / 2, (finalSize.Height - pageSize.Height) / 2);
                    _pageHost.RenderTransform = pageTransform; 
 
                    // Arrange pagehost to original size of the page.
                    _pageHost.Arrange(new Rect(_pageHost.CachedOffset, _documentPage.Size)); 

                }

                // Fire [....] notification if new page was connected. 
                if (_newPageConnected)
                { 
                    OnPageConnected(); 
                }
 
                // Transform for the page has been changed, need to notify TextView about the changes.
                OnTransformChangedAsync();
            }
            else 
            {
                if (_pageHost.PageVisual != _pageVisualClone) 
                { 
                    // Remove existing visiual children.
                    _pageHost.PageVisual = _pageVisualClone; 
                    // Size for the page host needs to be set to finalSize

                    // Use previous offset and transform
                    _pageHost.Arrange(new Rect(_pageHost.CachedOffset, finalSize)); 
                }
            } 
 
            return base.ArrangeOverride(finalSize);
        } 

        /// 
        /// Derived class must implement to support Visual children. The method must return
        /// the child at the specified index. Index must be between 0 and GetVisualChildrenCount-1. 
        /// 
        protected override Visual GetVisualChild(int index) 
        { 
            if (index != 0 || _pageHost == null)
            { 
                throw new ArgumentOutOfRangeException("index", index, SR.Get(SRID.Visual_ArgumentOutOfRange));
            }
            return _pageHost;
        } 

        ///  
        /// Dispose the object. 
        /// 
        protected void Dispose() 
        {
            if (!_disposed)
            {
                _disposed = true; 

                // Cleanup all state associated with Paginator. 
                if (_documentPaginator != null) 
                {
                    _documentPaginator.GetPageCompleted -= new GetPageCompletedEventHandler(HandleGetPageCompleted); 
                    _documentPaginator.PagesChanged -= new PagesChangedEventHandler(HandlePagesChanged);
                    _documentPaginator.CancelAsync(this);
                    DisposeCurrentPage();
                    DisposeAsyncPage(); 
                }
                Invariant.Assert(_documentPage == null); 
                Invariant.Assert(_documentPageAsync == null); 
                _documentPaginator = null;
                _textView = null; 
            }
        }

        ///  
        /// Returns service objects associated with this control.
        /// This method should be called by IServiceProvider.GetService implementation 
        /// for DocumentPageView or subclasses. 
        /// 
        /// Specifies the type of service object to get. 
        protected object GetService(Type serviceType)
        {
            object service = null;
            if (serviceType == null) 
            {
                throw new ArgumentNullException("serviceType"); 
            } 
            CheckDisposed();
 
            // No service is available if the Content does not provide
            // any services.
            if (_documentPaginator != null && _documentPaginator is IServiceProvider)
            { 
                // Following services are available:
                // (1) TextView - wrapper for TextView exposed by the current page. 
                // (2) TextContainer - the service object is retrieved from DocumentPaginator. 
                if (serviceType == typeof(ITextView))
                { 
                    if (_textView == null)
                    {
                        ITextContainer tc = ((IServiceProvider)_documentPaginator).GetService(typeof(ITextContainer)) as ITextContainer;
                        if (tc != null) 
                        {
                            _textView = new DocumentPageTextView(this, tc); 
                        } 
                    }
                    service = _textView; 
                }
                else if (serviceType == typeof(TextContainer) || serviceType == typeof(ITextContainer))
                {
                    service = ((IServiceProvider)_documentPaginator).GetService(serviceType); 
                }
            } 
            return service; 
        }
 
        /// 
        /// Creates AutomationPeer ()
        /// 
        protected override AutomationPeer OnCreateAutomationPeer() 
        {
            return new DocumentPageViewAutomationPeer(this); 
        } 

        #endregion Protected Methods 

        //-------------------------------------------------------------------
        //
        //  Protected Properties 
        //
        //------------------------------------------------------------------- 
 
        #region Protected Properties
 
        /// 
        /// Whether this DocumentPageView has been disposed.
        /// 
        protected bool IsDisposed 
        {
            get { return _disposed; } 
        } 

        ///  
        /// Derived classes override this property to enable the Visual code to enumerate
        /// the Visual children. Derived classes need to return the number of children
        /// from this method.
        ///  
        protected override int VisualChildrenCount
        { 
            get { return _pageHost != null ? 1 : 0; } 
        }
 
        #endregion Protected Properties

        //-------------------------------------------------------------------
        // 
        //  Internal Methods
        // 
        //-------------------------------------------------------------------- 

        #region Internal Methods 

        /// 
        /// Sets the zoom applied to the page being displayed.
        ///  
        /// Page zooom value.
        internal void SetPageZoom(double pageZoom) 
        { 
            Invariant.Assert(!DoubleUtil.LessThanOrClose(pageZoom, 0d) && !Double.IsInfinity(pageZoom));
            Invariant.Assert(!_disposed); 

            if (!DoubleUtil.AreClose(_pageZoom, pageZoom))
            {
                _pageZoom = pageZoom; 
                InvalidateMeasure();
            } 
        } 

        ///  
        /// Suspends page layout.
        /// 
        internal void SuspendLayout()
        { 
            _suspendLayout = true;
            _pageVisualClone = DuplicatePageVisual(); 
            _visualCloneSize = this.DesiredSize; 
        }
 
        /// 
        /// Resumes page layout.
        /// 
        internal void ResumeLayout() 
        {
            _suspendLayout = false; 
            _pageVisualClone = null; 
            InvalidateMeasure();
        } 

        /// 
        /// Duplicates the current page visual, if possible
        ///  
        internal void DuplicateVisual()
        { 
            if (_documentPage != null && _pageVisualClone == null) 
            {
                _pageVisualClone = DuplicatePageVisual(); 
                _visualCloneSize = this.DesiredSize;
                InvalidateArrange();
            }
        } 

        ///  
        /// Clears the duplicated page visual, if one exists. 
        /// 
        internal void RemoveDuplicateVisual() 
        {
            if (_pageVisualClone != null)
            {
                _pageVisualClone = null; 
                InvalidateArrange();
            } 
        } 

        #endregion Internal Methods 

        //-------------------------------------------------------------------
        //
        //  Internal Properties 
        //
        //-------------------------------------------------------------------- 
 
        #region Internal Properties
 
        /// 
        ///    Default is true.  Controls whether we use asynchronous mode to
        ///    request the DocumentPage.  In some cases, such as synchronous
        ///    printing, we don't want to wait for the asynchronous events. 
        /// 
        internal bool UseAsynchronousGetPage 
        { 
            get { return _useAsynchronous; }
            set { _useAsynchronous = value; } 
        }

        /// 
        /// The DocumentPage for the displayed page. 
        /// 
        internal DocumentPage DocumentPageInternal 
        { 
            get { return _documentPage; }
        } 

        #endregion Internal Properties

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

        /// 
        /// Handles PageDestroyed event raised for the current DocumentPage. 
        /// 
        /// Source of the event. 
        /// Not used. 
        private void HandlePageDestroyed(object sender, EventArgs e)
        { 
            if (!_disposed)
            {
                InvalidateMeasure();
                DisposeCurrentPage(); 
            }
        } 
 
        /// 
        /// Handles PageDestroyed event raised for the cached async DocumentPage. 
        /// 
        /// Source of the event.
        /// Not used.
        private void HandleAsyncPageDestroyed(object sender, EventArgs e) 
        {
            if (!_disposed) 
            { 
                DisposeAsyncPage();
            } 
        }

        /// 
        /// Handles GetPageCompleted event raised by the DocumentPaginator. 
        /// 
        /// Source of the event. 
        /// Details about this event. 
        private void HandleGetPageCompleted(object sender, GetPageCompletedEventArgs e)
        { 
            if (!_disposed && (e != null) && !e.Cancelled && e.Error == null)
            {
                if (e.PageNumber == this.PageNumber && e.UserState == this)
                { 
                    if (_documentPageAsync != null && _documentPageAsync != DocumentPage.Missing)
                    { 
                        _documentPageAsync.PageDestroyed -= new EventHandler(HandleAsyncPageDestroyed); 
                    }
                    _documentPageAsync = e.DocumentPage; 
                    if (_documentPageAsync == null)
                    {
                        _documentPageAsync = DocumentPage.Missing;
                    } 
                    if (_documentPageAsync != DocumentPage.Missing)
                    { 
                        _documentPageAsync.PageDestroyed += new EventHandler(HandleAsyncPageDestroyed); 
                    }
                    InvalidateMeasure(); 
                }
                // else; the page is not ours
            }
        } 

        ///  
        /// Handles PagesChanged event raised by the DocumentPaginator. 
        /// 
        /// Source of the event. 
        /// Details about this event.
        private void HandlePagesChanged(object sender, PagesChangedEventArgs e)
        {
            if (!_disposed && (e != null)) 
            {
                if (this.PageNumber >= e.Start && 
                    (e.Count == int.MaxValue || this.PageNumber <= e.Start + e.Count)) 
                {
                    OnPageContentChanged(); 
                }
            }
        }
 
        /// 
        /// Async notification about transform changes for embedded page. 
        ///  
        private void OnTransformChangedAsync()
        { 
            Dispatcher.BeginInvoke(DispatcherPriority.Normal,
                new DispatcherOperationCallback(OnTransformChanged), null);
        }
 
        /// 
        /// Notification about transform changes for embedded page. 
        ///  
        /// Not used.
        /// Not used. 
        private object OnTransformChanged(object arg)
        {
            if (_textView != null && _documentPage != null)
            { 
                _textView.OnTransformChanged();
            } 
            return null; 
        }
 
        /// 
        /// Raises PageConnected event.
        /// 
        private void OnPageConnected() 
        {
            _newPageConnected = false; 
            if (_textView != null) 
            {
                _textView.OnPageConnected(); 
            }
            if (this.PageConnected != null && _documentPage != null)
            {
                this.PageConnected(this, EventArgs.Empty); 
            }
        } 
 
        /// 
        /// Raises PageDisconnected event. 
        /// 
        private void OnPageDisconnected()
        {
            if (_textView != null) 
            {
                _textView.OnPageDisconnected(); 
            } 
            if (this.PageDisconnected != null)
            { 
                this.PageDisconnected(this, EventArgs.Empty);
            }
        }
 
        /// 
        /// Responds to page content change. 
        ///  
        private void OnPageContentChanged()
        { 
            // Force remeasure which will cause to reget DocumentPage
            InvalidateMeasure();
            // Do cleanup for currently used page, because it gets replaced.
            DisposeCurrentPage(); 
            DisposeAsyncPage();
        } 
 
        /// 
        /// Disposes the current DocumentPage. 
        /// 
        private void DisposeCurrentPage()
        {
            // Do cleanup for currently used page, because it gets replaced. 
            if (_documentPage != null)
            { 
                // Remove visual for currently used page. 
                if (_pageHost != null)
                { 
                    _pageHost.PageVisual = null;
                }

                // Clear TextView & DocumentPage 
                if (_documentPage != DocumentPage.Missing)
                { 
                    _documentPage.PageDestroyed -= new EventHandler(HandlePageDestroyed); 
                }
                if (_documentPage is IDisposable) 
                {
                    ((IDisposable)_documentPage).Dispose();
                }
                _documentPage = null; 

                OnPageDisconnected(); 
            } 
        }
 
        /// 
        /// Disposes pending async DocumentPage.
        /// 
        private void DisposeAsyncPage() 
        {
            // Do cleanup for cached async page. 
            if (_documentPageAsync != null) 
            {
                if (_documentPageAsync != DocumentPage.Missing) 
                {
                    _documentPageAsync.PageDestroyed -= new EventHandler(HandleAsyncPageDestroyed);
                }
                if (_documentPageAsync is IDisposable) 
                {
                    ((IDisposable)_documentPageAsync).Dispose(); 
                } 
                _documentPageAsync = null;
            } 
        }

        /// 
        /// Checks if the instance is already disposed. 
        /// 
        private void CheckDisposed() 
        { 
            if (_disposed)
            { 
                throw new ObjectDisposedException(typeof(DocumentPageView).ToString());
            }
        }
 
        /// 
        /// Check whether content needs to be reflowed. 
        ///  
        /// True, if content needs to be reflowed.
        private bool ShouldReflowContent() 
        {
            bool shouldReflow = false;
            DocumentViewerBase hostViewer;
 
            if (DocumentViewerBase.GetIsMasterPage(this))
            { 
                hostViewer = GetHostViewer(); 
                if (hostViewer != null)
                { 
                    shouldReflow = hostViewer.IsMasterPageView(this);
                }
            }
            return shouldReflow; 
        }
 
        ///  
        /// Retrieves DocumentViewerBase that hosts this view.
        ///  
        /// DocumentViewerBase that hosts this view.
        private DocumentViewerBase GetHostViewer()
        {
            DocumentViewerBase hostViewer = null; 
            Visual visualParent;
 
            // First do quick check for TemplatedParent. It will cover good 
            // amount of cases, because static viewers will have their
            // DocumentPageViews defined in the style. 
            // If quick check does not work, do a visual tree walk.
            if (this.TemplatedParent is DocumentViewerBase)
            {
                hostViewer = (DocumentViewerBase)this.TemplatedParent; 
            }
            else 
            { 
                // Check if hosted by DocumentViewerBase.
                visualParent = VisualTreeHelper.GetParent(this) as Visual; 
                while (visualParent != null)
                {
                    if (visualParent is DocumentViewerBase)
                    { 
                        hostViewer = (DocumentViewerBase)visualParent;
                        break; 
                    } 
                    visualParent = VisualTreeHelper.GetParent(visualParent) as Visual;
                } 
            }
            return hostViewer;
        }
 

        ///  
        /// The PageNumber has changed and needs to be updated. 
        /// 
        private static void OnPageNumberChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
        {
            Invariant.Assert(d != null && d is DocumentPageView);
            ((DocumentPageView)d).OnPageContentChanged();
        } 

        ///  
        /// Duplicates content of the PageVisual. 
        /// 
        private DrawingVisual DuplicatePageVisual() 
        {
            DrawingVisual drawingVisual = null;
            if (_pageHost != null && _pageHost.PageVisual != null && _documentPage.Size != Size.Empty)
            { 
                const double maxWidth = 4096.0;
                const double maxHeight = maxWidth; 
 
                Rect pageVisualRect = new Rect(_documentPage.Size);
 
                pageVisualRect.Width = Math.Min(pageVisualRect.Width, maxWidth);
                pageVisualRect.Height = Math.Min(pageVisualRect.Height, maxHeight);

                drawingVisual = new DrawingVisual(); 

                try 
                { 
                    if(pageVisualRect.Width > 1.0 && pageVisualRect.Height > 1.0)
                    { 
                        RenderTargetBitmap renderTargetBitmap = new RenderTargetBitmap((int)pageVisualRect.Width, (int)pageVisualRect.Height, 96.0, 96.0, PixelFormats.Pbgra32);
                        renderTargetBitmap.Render(_pageHost.PageVisual);

                        ImageBrush imageBrush = new ImageBrush(renderTargetBitmap); 
                        drawingVisual.Opacity = 0.50;
                        using (DrawingContext dc = drawingVisual.RenderOpen()) 
                        { 
                            dc.DrawRectangle(imageBrush, null, pageVisualRect);
                        } 
                    }
                }
                catch(System.OverflowException)
                { 
                    // Ignore overflow exception - caused by render target creation not possible under current memory conditions.
                } 
 
            }
            return drawingVisual; 
        }

        #endregion Private Methods
 
        //--------------------------------------------------------------------
        // 
        //  Private Fields 
        //
        //------------------------------------------------------------------- 

        #region Private Fields

        private DocumentPaginator _documentPaginator; 
        private double _pageZoom;
        private DocumentPage _documentPage; 
        private DocumentPage _documentPageAsync; 
        private DocumentPageTextView _textView;
        private DocumentPageHost _pageHost; 
        private Visual _pageVisualClone;
        private Size _visualCloneSize;
        private bool _useAsynchronous = true;
        private bool _suspendLayout; 
        private bool _disposed;
        private bool _newPageConnected; 
 
        #endregion Private Fields
 
        //-------------------------------------------------------------------
        //
        //  IServiceProvider Members
        // 
        //-------------------------------------------------------------------
 
        #region IServiceProvider Members 

        ///  
        /// Returns service objects associated with this control.
        /// 
        /// Specifies the type of service object to get.
        object IServiceProvider.GetService(Type serviceType) 
        {
            return this.GetService(serviceType); 
        } 

        #endregion IServiceProvider Members 

        //--------------------------------------------------------------------
        //
        //  IDisposable Members 
        //
        //------------------------------------------------------------------- 
 
        #region IDisposable Members
 
        /// 
        /// Dispose the object.
        /// 
        void IDisposable.Dispose() 
        {
            this.Dispose(); 
        } 

        #endregion IDisposable Members 
    }
}

 


// 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: DocumentPageView.cs 
//
// Description: Provides a view port for a page of content for a DocumentPage. 
// 
//---------------------------------------------------------------------------
 
using System.Windows.Automation;            // AutomationPattern
using System.Windows.Automation.Peers;      // AutomationPeer
using System.Windows.Controls;              // StretchDirection
using System.Windows.Controls.Primitives;   // DocumentViewerBase 
using System.Windows.Documents;             // DocumentPaginator
using System.Windows.Media;                 // Visual 
using System.Windows.Media.Imaging;         // RenderTargetBitmap 
using System.Windows.Threading;             // Dispatcher
using MS.Internal;                          // Invariant 
using MS.Internal.Documents;                // DocumentPageHost, DocumentPageTextView
using MS.Internal.Automation;               // TextAdaptor
using MS.Internal.KnownBoxes;               // BooleanBoxes
 

namespace System.Windows.Controls.Primitives 
{ 
    /// 
    /// Provides a view port for a page of content for a DocumentPage. 
    /// 
    public class DocumentPageView : FrameworkElement, IServiceProvider, IDisposable
    {
        //------------------------------------------------------------------- 
        //
        //  Constructors 
        // 
        //-------------------------------------------------------------------
 
        #region Constructors

        /// 
        /// Create an instance of a DocumentPageView. 
        /// 
        ///  
        /// This does basic initialization of the DocumentPageView.  All subclasses 
        /// must call the base constructor to perform this initialization.
        ///  
        public DocumentPageView() : base()
        {
            _pageZoom = 1.0;
        } 

        ///  
        /// Static ctor. Initializes property metadata. 
        /// 
        static DocumentPageView() 
        {
            ClipToBoundsProperty.OverrideMetadata(typeof(DocumentPageView), new PropertyMetadata(BooleanBoxes.TrueBox));
        }
 
        #endregion
 
        //-------------------------------------------------------------------- 
        //
        //  Public Properties 
        //
        //-------------------------------------------------------------------

        #region Public Properties 

        ///  
        /// The Paginator from which this DocumentPageView retrieves pages. 
        /// 
        public DocumentPaginator DocumentPaginator 
        {
            get { return _documentPaginator; }
            set
            { 
                CheckDisposed();
                if (_documentPaginator != value) 
                { 
                    // Cleanup all state associated with old Paginator.
                    if (_documentPaginator != null) 
                    {
                        _documentPaginator.GetPageCompleted -= new GetPageCompletedEventHandler(HandleGetPageCompleted);
                        _documentPaginator.PagesChanged -= new PagesChangedEventHandler(HandlePagesChanged);
                        DisposeCurrentPage(); 
                        DisposeAsyncPage();
                    } 
 
                    Invariant.Assert(_documentPage == null);
                    Invariant.Assert(_documentPageAsync == null); 
                    _documentPaginator = value;
                    _textView = null;

                    // Register for events on new Paginator and invalidate 
                    // measure to force content update.
                    if (_documentPaginator != null) 
                    { 
                        _documentPaginator.GetPageCompleted += new GetPageCompletedEventHandler(HandleGetPageCompleted);
                        _documentPaginator.PagesChanged += new PagesChangedEventHandler(HandlePagesChanged); 
                    }
                    InvalidateMeasure();
                }
            } 
        }
 
        ///  
        /// The DocumentPage for the displayed page.
        ///  
        public DocumentPage DocumentPage
        {
            get { return (_documentPage == null) ? DocumentPage.Missing : _documentPage; }
        } 

        ///  
        /// The page number displayed; no content is displayed if this number is negative. 
        /// PageNumber is zero-based.
        ///  
        public int PageNumber
        {
            get { return (int) GetValue(PageNumberProperty); }
            set { SetValue(PageNumberProperty, value); } 
        }
 
        ///  
        /// Controls the stretching behavior for the page.
        ///  
        public Stretch Stretch
        {
            get { return (Stretch)GetValue(StretchProperty); }
            set { SetValue(StretchProperty, value); } 
        }
 
        ///  
        /// Specifies the directions in which page may be stretched.
        ///  
        public StretchDirection StretchDirection
        {
            get { return (StretchDirection)GetValue(StretchDirectionProperty); }
            set { SetValue(StretchDirectionProperty, value); } 
        }
 
        #region Public Dynamic Properties 

        ///  
        /// 
        /// 
        public static readonly DependencyProperty PageNumberProperty =
                DependencyProperty.Register( 
                        "PageNumber",
                        typeof(int), 
                        typeof(DocumentPageView), 
                        new FrameworkPropertyMetadata(
                                0, 
                                FrameworkPropertyMetadataOptions.AffectsMeasure,
                                new PropertyChangedCallback(OnPageNumberChanged)));

        ///  
        /// 
        ///  
        public static readonly DependencyProperty StretchProperty = 
                Viewbox.StretchProperty.AddOwner(
                        typeof(DocumentPageView), 
                        new FrameworkPropertyMetadata(
                                Stretch.Uniform,
                                FrameworkPropertyMetadataOptions.AffectsMeasure));
 
        /// 
        ///  
        ///  
        public static readonly DependencyProperty StretchDirectionProperty =
                Viewbox.StretchDirectionProperty.AddOwner( 
                        typeof(DocumentPageView),
                        new FrameworkPropertyMetadata(
                                StretchDirection.DownOnly,
                                FrameworkPropertyMetadataOptions.AffectsMeasure)); 

        #endregion Public Dynamic Properties 
 
        #endregion Public Properties
 
        //--------------------------------------------------------------------
        //
        //  Public Events
        // 
        //--------------------------------------------------------------------
 
        #region Public Events 

        ///  
        /// Fired after a DocumentPage.Visual is connected.
        /// 
        public event EventHandler PageConnected;
 
        /// 
        /// Fired after a DocumentPage.Visual is disconnected. 
        ///  
        public event EventHandler PageDisconnected;
 
        #endregion Public Events

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

        #region Protected Methods 

        /// 
        /// Content measurement.
        ///  
        /// Available size that parent can give to the child. This is soft constraint.
        /// The DocumentPageView's desired size. 
        protected override sealed Size MeasureOverride(Size availableSize) 
        {
            Size newPageSize, pageZoom; 
            Size pageSize;
            Size desiredSize = new Size(); // If no page is available, return (0,0) as size.

            CheckDisposed(); 

            if (_suspendLayout) 
            { 
                desiredSize = this.DesiredSize;
            } 
            else if (_documentPaginator != null)
            {
                // Reflow content if needed.
                if (ShouldReflowContent()) 
                {
                    // Reflow is disabled when dealing with infinite size in both directions. 
                    // If only one dimention is infinte, calculate value based on PageSize of the 
                    // document and Stretching properties.
                    if (!Double.IsInfinity(availableSize.Width) || !Double.IsInfinity(availableSize.Height)) 
                    {
                        pageSize = _documentPaginator.PageSize;
                        if (Double.IsInfinity(availableSize.Width))
                        { 
                            newPageSize = new Size();
                            newPageSize.Height = availableSize.Height / _pageZoom; 
                            newPageSize.Width = newPageSize.Height * (pageSize.Width / pageSize.Height); // Keep aspect ratio. 
                        }
                        else if (Double.IsInfinity(availableSize.Height)) 
                        {
                            newPageSize = new Size();
                            newPageSize.Width = availableSize.Width / _pageZoom;
                            newPageSize.Height = newPageSize.Width * (pageSize.Height / pageSize.Width); // Keep aspect ratio. 
                        }
                        else 
                        { 
                            newPageSize = new Size(availableSize.Width / _pageZoom, availableSize.Height / _pageZoom);
                        } 
                        if (!DoubleUtil.AreClose(pageSize, newPageSize))
                        {
                            _documentPaginator.PageSize = newPageSize;
                        } 
                    }
                } 
 
                // If the main page or pending async page are not available yet,
                // asynchronously request new page from Paginator. 
                if (_documentPage == null && _documentPageAsync == null)
                {
                    if (PageNumber >= 0)
                    { 
                        if (_useAsynchronous)
                        { 
                            _documentPaginator.GetPageAsync(PageNumber, this); 
                        }
                        else 
                        {
                            _documentPageAsync = _documentPaginator.GetPage(PageNumber);
                            if (_documentPageAsync == null)
                            { 
                                _documentPageAsync = DocumentPage.Missing;
                            } 
                        } 
                    }
                    else 
                    {
                        _documentPage = DocumentPage.Missing;
                    }
                } 

                // If pending async page is available, discard the main page and 
                // set _documentPage to _documentPageAsync. 
                if (_documentPageAsync != null)
                { 
                    // Do cleanup for currently used page, because it gets replaced.
                    DisposeCurrentPage();
                    // DisposeCurrentPage raises PageDisposed and DocumentPage.PageDestroyed events.
                    // Handlers for those events may dispose _documentPageAsync. Treat this situation 
                    // as missing page.
                    if (_documentPageAsync == null) 
                    { 
                        _documentPageAsync = DocumentPage.Missing;
                    } 
                    if (_pageVisualClone != null)
                    {
                        RemoveDuplicateVisual();
                    } 

                    // Replace the main page with cached async page. 
                    _documentPage = _documentPageAsync; 
                    if (_documentPage != DocumentPage.Missing)
                    { 
                        _documentPage.PageDestroyed += new EventHandler(HandlePageDestroyed);
                        _documentPageAsync.PageDestroyed -= new EventHandler(HandleAsyncPageDestroyed);
                    }
                    _documentPageAsync = null; 

                    // Set a flag that will indicate that a PageConnected must be fired in 
                    // ArrangeOverride 
                    _newPageConnected = true;
                } 

                // If page is available, return its size as desired size.
                if (_documentPage != null && _documentPage != DocumentPage.Missing)
                { 
                    pageSize = new Size(_documentPage.Size.Width * _pageZoom, _documentPage.Size.Height * _pageZoom);
                    pageZoom = Viewbox.ComputeScaleFactor(availableSize, pageSize, this.Stretch, this.StretchDirection); 
                    desiredSize = new Size(pageSize.Width * pageZoom.Width, pageSize.Height * pageZoom.Height); 
                }
 
                if (_pageVisualClone != null)
                {
                    desiredSize = _visualCloneSize;
                } 
            }
 
            return desiredSize; 
        }
 
        /// 
        /// Content arrangement.
        /// 
        /// The final size that element should use to arrange itself and its children. 
        protected override sealed Size ArrangeOverride(Size finalSize)
        { 
            Transform pageTransform; 
            ScaleTransform pageScaleTransform;
            Visual pageVisual; 
            Size pageSize, pageZoom;

            CheckDisposed();
 
            if (_pageVisualClone == null)
            { 
                if (_pageHost == null) 
                {
                    _pageHost = new DocumentPageHost(); 
                    this.AddVisualChild(_pageHost);
                }
                Invariant.Assert(_pageHost != null);
 
                pageVisual = (_documentPage == null) ? null : _documentPage.Visual;
                if (pageVisual == null) 
                { 
                    // Remove existing visiual children.
                    _pageHost.PageVisual = null; 

                    // Reset offset and transform on the page host before Arrange
                    _pageHost.CachedOffset = new Point();
                    _pageHost.RenderTransform = null; 

                    // Size for the page host needs to be set to finalSize 
                    _pageHost.Arrange(new Rect(_pageHost.CachedOffset, finalSize)); 
                }
                else 
                {
                    // Add visual representing the page contents. For performance reasons
                    // first check if it is already insered there.
                    if (_pageHost.PageVisual != pageVisual) 
                    {
                        // There might be a case where a visual associated with a page was 
                        // inserted to a visual tree before. It got removed later, but GC did not 
                        // destroy its parent yet. To workaround this case always check for the parent
                        // of page visual and disconnect it, when necessary. 
                        DocumentPageHost.DisconnectPageVisual(pageVisual);

                        _pageHost.PageVisual = pageVisual;
                    } 

                    // Compute transform to be applied to the page visual. First take into account 
                    // mirroring transform, if necessary. Apply also scaling transform. 
                    pageSize = _documentPage.Size;
                    pageTransform = Transform.Identity; 

                    // DocumentPage.Visual is always LeftToRight, so if the current
                    // FlowDirection is RightToLeft, need to unmirror the child visual.
                    if (FlowDirection == FlowDirection.RightToLeft) 
                    {
                        pageTransform = new MatrixTransform(-1.0, 0.0, 0.0, 1.0, pageSize.Width, 0.0); 
                    } 

                    // Apply zooming 
                    if (!DoubleUtil.IsOne(_pageZoom))
                    {
                        pageScaleTransform = new ScaleTransform(_pageZoom, _pageZoom);
                        if (pageTransform == Transform.Identity) 
                        {
                            pageTransform = pageScaleTransform; 
                        } 
                        else
                        { 
                            pageTransform = new MatrixTransform(pageTransform.Value * pageScaleTransform.Value);
                        }
                        pageSize = new Size(pageSize.Width * _pageZoom, pageSize.Height * _pageZoom);
                    } 

                    // Apply stretch properties 
                    pageZoom = Viewbox.ComputeScaleFactor(finalSize, pageSize, this.Stretch, this.StretchDirection); 
                    if (!DoubleUtil.IsOne(pageZoom.Width) || !DoubleUtil.IsOne(pageZoom.Height))
                    { 
                        pageScaleTransform = new ScaleTransform(pageZoom.Width, pageZoom.Height);
                        if (pageTransform == Transform.Identity)
                        {
                            pageTransform = pageScaleTransform; 
                        }
                        else 
                        { 
                            pageTransform = new MatrixTransform(pageTransform.Value * pageScaleTransform.Value);
                        } 
                        pageSize = new Size(pageSize.Width * pageZoom.Width, pageSize.Height * pageZoom.Height);
                    }

                    // Set offset and transform on the page host before Arrange 
                    _pageHost.CachedOffset = new Point((finalSize.Width - pageSize.Width) / 2, (finalSize.Height - pageSize.Height) / 2);
                    _pageHost.RenderTransform = pageTransform; 
 
                    // Arrange pagehost to original size of the page.
                    _pageHost.Arrange(new Rect(_pageHost.CachedOffset, _documentPage.Size)); 

                }

                // Fire [....] notification if new page was connected. 
                if (_newPageConnected)
                { 
                    OnPageConnected(); 
                }
 
                // Transform for the page has been changed, need to notify TextView about the changes.
                OnTransformChangedAsync();
            }
            else 
            {
                if (_pageHost.PageVisual != _pageVisualClone) 
                { 
                    // Remove existing visiual children.
                    _pageHost.PageVisual = _pageVisualClone; 
                    // Size for the page host needs to be set to finalSize

                    // Use previous offset and transform
                    _pageHost.Arrange(new Rect(_pageHost.CachedOffset, finalSize)); 
                }
            } 
 
            return base.ArrangeOverride(finalSize);
        } 

        /// 
        /// Derived class must implement to support Visual children. The method must return
        /// the child at the specified index. Index must be between 0 and GetVisualChildrenCount-1. 
        /// 
        protected override Visual GetVisualChild(int index) 
        { 
            if (index != 0 || _pageHost == null)
            { 
                throw new ArgumentOutOfRangeException("index", index, SR.Get(SRID.Visual_ArgumentOutOfRange));
            }
            return _pageHost;
        } 

        ///  
        /// Dispose the object. 
        /// 
        protected void Dispose() 
        {
            if (!_disposed)
            {
                _disposed = true; 

                // Cleanup all state associated with Paginator. 
                if (_documentPaginator != null) 
                {
                    _documentPaginator.GetPageCompleted -= new GetPageCompletedEventHandler(HandleGetPageCompleted); 
                    _documentPaginator.PagesChanged -= new PagesChangedEventHandler(HandlePagesChanged);
                    _documentPaginator.CancelAsync(this);
                    DisposeCurrentPage();
                    DisposeAsyncPage(); 
                }
                Invariant.Assert(_documentPage == null); 
                Invariant.Assert(_documentPageAsync == null); 
                _documentPaginator = null;
                _textView = null; 
            }
        }

        ///  
        /// Returns service objects associated with this control.
        /// This method should be called by IServiceProvider.GetService implementation 
        /// for DocumentPageView or subclasses. 
        /// 
        /// Specifies the type of service object to get. 
        protected object GetService(Type serviceType)
        {
            object service = null;
            if (serviceType == null) 
            {
                throw new ArgumentNullException("serviceType"); 
            } 
            CheckDisposed();
 
            // No service is available if the Content does not provide
            // any services.
            if (_documentPaginator != null && _documentPaginator is IServiceProvider)
            { 
                // Following services are available:
                // (1) TextView - wrapper for TextView exposed by the current page. 
                // (2) TextContainer - the service object is retrieved from DocumentPaginator. 
                if (serviceType == typeof(ITextView))
                { 
                    if (_textView == null)
                    {
                        ITextContainer tc = ((IServiceProvider)_documentPaginator).GetService(typeof(ITextContainer)) as ITextContainer;
                        if (tc != null) 
                        {
                            _textView = new DocumentPageTextView(this, tc); 
                        } 
                    }
                    service = _textView; 
                }
                else if (serviceType == typeof(TextContainer) || serviceType == typeof(ITextContainer))
                {
                    service = ((IServiceProvider)_documentPaginator).GetService(serviceType); 
                }
            } 
            return service; 
        }
 
        /// 
        /// Creates AutomationPeer ()
        /// 
        protected override AutomationPeer OnCreateAutomationPeer() 
        {
            return new DocumentPageViewAutomationPeer(this); 
        } 

        #endregion Protected Methods 

        //-------------------------------------------------------------------
        //
        //  Protected Properties 
        //
        //------------------------------------------------------------------- 
 
        #region Protected Properties
 
        /// 
        /// Whether this DocumentPageView has been disposed.
        /// 
        protected bool IsDisposed 
        {
            get { return _disposed; } 
        } 

        ///  
        /// Derived classes override this property to enable the Visual code to enumerate
        /// the Visual children. Derived classes need to return the number of children
        /// from this method.
        ///  
        protected override int VisualChildrenCount
        { 
            get { return _pageHost != null ? 1 : 0; } 
        }
 
        #endregion Protected Properties

        //-------------------------------------------------------------------
        // 
        //  Internal Methods
        // 
        //-------------------------------------------------------------------- 

        #region Internal Methods 

        /// 
        /// Sets the zoom applied to the page being displayed.
        ///  
        /// Page zooom value.
        internal void SetPageZoom(double pageZoom) 
        { 
            Invariant.Assert(!DoubleUtil.LessThanOrClose(pageZoom, 0d) && !Double.IsInfinity(pageZoom));
            Invariant.Assert(!_disposed); 

            if (!DoubleUtil.AreClose(_pageZoom, pageZoom))
            {
                _pageZoom = pageZoom; 
                InvalidateMeasure();
            } 
        } 

        ///  
        /// Suspends page layout.
        /// 
        internal void SuspendLayout()
        { 
            _suspendLayout = true;
            _pageVisualClone = DuplicatePageVisual(); 
            _visualCloneSize = this.DesiredSize; 
        }
 
        /// 
        /// Resumes page layout.
        /// 
        internal void ResumeLayout() 
        {
            _suspendLayout = false; 
            _pageVisualClone = null; 
            InvalidateMeasure();
        } 

        /// 
        /// Duplicates the current page visual, if possible
        ///  
        internal void DuplicateVisual()
        { 
            if (_documentPage != null && _pageVisualClone == null) 
            {
                _pageVisualClone = DuplicatePageVisual(); 
                _visualCloneSize = this.DesiredSize;
                InvalidateArrange();
            }
        } 

        ///  
        /// Clears the duplicated page visual, if one exists. 
        /// 
        internal void RemoveDuplicateVisual() 
        {
            if (_pageVisualClone != null)
            {
                _pageVisualClone = null; 
                InvalidateArrange();
            } 
        } 

        #endregion Internal Methods 

        //-------------------------------------------------------------------
        //
        //  Internal Properties 
        //
        //-------------------------------------------------------------------- 
 
        #region Internal Properties
 
        /// 
        ///    Default is true.  Controls whether we use asynchronous mode to
        ///    request the DocumentPage.  In some cases, such as synchronous
        ///    printing, we don't want to wait for the asynchronous events. 
        /// 
        internal bool UseAsynchronousGetPage 
        { 
            get { return _useAsynchronous; }
            set { _useAsynchronous = value; } 
        }

        /// 
        /// The DocumentPage for the displayed page. 
        /// 
        internal DocumentPage DocumentPageInternal 
        { 
            get { return _documentPage; }
        } 

        #endregion Internal Properties

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

        /// 
        /// Handles PageDestroyed event raised for the current DocumentPage. 
        /// 
        /// Source of the event. 
        /// Not used. 
        private void HandlePageDestroyed(object sender, EventArgs e)
        { 
            if (!_disposed)
            {
                InvalidateMeasure();
                DisposeCurrentPage(); 
            }
        } 
 
        /// 
        /// Handles PageDestroyed event raised for the cached async DocumentPage. 
        /// 
        /// Source of the event.
        /// Not used.
        private void HandleAsyncPageDestroyed(object sender, EventArgs e) 
        {
            if (!_disposed) 
            { 
                DisposeAsyncPage();
            } 
        }

        /// 
        /// Handles GetPageCompleted event raised by the DocumentPaginator. 
        /// 
        /// Source of the event. 
        /// Details about this event. 
        private void HandleGetPageCompleted(object sender, GetPageCompletedEventArgs e)
        { 
            if (!_disposed && (e != null) && !e.Cancelled && e.Error == null)
            {
                if (e.PageNumber == this.PageNumber && e.UserState == this)
                { 
                    if (_documentPageAsync != null && _documentPageAsync != DocumentPage.Missing)
                    { 
                        _documentPageAsync.PageDestroyed -= new EventHandler(HandleAsyncPageDestroyed); 
                    }
                    _documentPageAsync = e.DocumentPage; 
                    if (_documentPageAsync == null)
                    {
                        _documentPageAsync = DocumentPage.Missing;
                    } 
                    if (_documentPageAsync != DocumentPage.Missing)
                    { 
                        _documentPageAsync.PageDestroyed += new EventHandler(HandleAsyncPageDestroyed); 
                    }
                    InvalidateMeasure(); 
                }
                // else; the page is not ours
            }
        } 

        ///  
        /// Handles PagesChanged event raised by the DocumentPaginator. 
        /// 
        /// Source of the event. 
        /// Details about this event.
        private void HandlePagesChanged(object sender, PagesChangedEventArgs e)
        {
            if (!_disposed && (e != null)) 
            {
                if (this.PageNumber >= e.Start && 
                    (e.Count == int.MaxValue || this.PageNumber <= e.Start + e.Count)) 
                {
                    OnPageContentChanged(); 
                }
            }
        }
 
        /// 
        /// Async notification about transform changes for embedded page. 
        ///  
        private void OnTransformChangedAsync()
        { 
            Dispatcher.BeginInvoke(DispatcherPriority.Normal,
                new DispatcherOperationCallback(OnTransformChanged), null);
        }
 
        /// 
        /// Notification about transform changes for embedded page. 
        ///  
        /// Not used.
        /// Not used. 
        private object OnTransformChanged(object arg)
        {
            if (_textView != null && _documentPage != null)
            { 
                _textView.OnTransformChanged();
            } 
            return null; 
        }
 
        /// 
        /// Raises PageConnected event.
        /// 
        private void OnPageConnected() 
        {
            _newPageConnected = false; 
            if (_textView != null) 
            {
                _textView.OnPageConnected(); 
            }
            if (this.PageConnected != null && _documentPage != null)
            {
                this.PageConnected(this, EventArgs.Empty); 
            }
        } 
 
        /// 
        /// Raises PageDisconnected event. 
        /// 
        private void OnPageDisconnected()
        {
            if (_textView != null) 
            {
                _textView.OnPageDisconnected(); 
            } 
            if (this.PageDisconnected != null)
            { 
                this.PageDisconnected(this, EventArgs.Empty);
            }
        }
 
        /// 
        /// Responds to page content change. 
        ///  
        private void OnPageContentChanged()
        { 
            // Force remeasure which will cause to reget DocumentPage
            InvalidateMeasure();
            // Do cleanup for currently used page, because it gets replaced.
            DisposeCurrentPage(); 
            DisposeAsyncPage();
        } 
 
        /// 
        /// Disposes the current DocumentPage. 
        /// 
        private void DisposeCurrentPage()
        {
            // Do cleanup for currently used page, because it gets replaced. 
            if (_documentPage != null)
            { 
                // Remove visual for currently used page. 
                if (_pageHost != null)
                { 
                    _pageHost.PageVisual = null;
                }

                // Clear TextView & DocumentPage 
                if (_documentPage != DocumentPage.Missing)
                { 
                    _documentPage.PageDestroyed -= new EventHandler(HandlePageDestroyed); 
                }
                if (_documentPage is IDisposable) 
                {
                    ((IDisposable)_documentPage).Dispose();
                }
                _documentPage = null; 

                OnPageDisconnected(); 
            } 
        }
 
        /// 
        /// Disposes pending async DocumentPage.
        /// 
        private void DisposeAsyncPage() 
        {
            // Do cleanup for cached async page. 
            if (_documentPageAsync != null) 
            {
                if (_documentPageAsync != DocumentPage.Missing) 
                {
                    _documentPageAsync.PageDestroyed -= new EventHandler(HandleAsyncPageDestroyed);
                }
                if (_documentPageAsync is IDisposable) 
                {
                    ((IDisposable)_documentPageAsync).Dispose(); 
                } 
                _documentPageAsync = null;
            } 
        }

        /// 
        /// Checks if the instance is already disposed. 
        /// 
        private void CheckDisposed() 
        { 
            if (_disposed)
            { 
                throw new ObjectDisposedException(typeof(DocumentPageView).ToString());
            }
        }
 
        /// 
        /// Check whether content needs to be reflowed. 
        ///  
        /// True, if content needs to be reflowed.
        private bool ShouldReflowContent() 
        {
            bool shouldReflow = false;
            DocumentViewerBase hostViewer;
 
            if (DocumentViewerBase.GetIsMasterPage(this))
            { 
                hostViewer = GetHostViewer(); 
                if (hostViewer != null)
                { 
                    shouldReflow = hostViewer.IsMasterPageView(this);
                }
            }
            return shouldReflow; 
        }
 
        ///  
        /// Retrieves DocumentViewerBase that hosts this view.
        ///  
        /// DocumentViewerBase that hosts this view.
        private DocumentViewerBase GetHostViewer()
        {
            DocumentViewerBase hostViewer = null; 
            Visual visualParent;
 
            // First do quick check for TemplatedParent. It will cover good 
            // amount of cases, because static viewers will have their
            // DocumentPageViews defined in the style. 
            // If quick check does not work, do a visual tree walk.
            if (this.TemplatedParent is DocumentViewerBase)
            {
                hostViewer = (DocumentViewerBase)this.TemplatedParent; 
            }
            else 
            { 
                // Check if hosted by DocumentViewerBase.
                visualParent = VisualTreeHelper.GetParent(this) as Visual; 
                while (visualParent != null)
                {
                    if (visualParent is DocumentViewerBase)
                    { 
                        hostViewer = (DocumentViewerBase)visualParent;
                        break; 
                    } 
                    visualParent = VisualTreeHelper.GetParent(visualParent) as Visual;
                } 
            }
            return hostViewer;
        }
 

        ///  
        /// The PageNumber has changed and needs to be updated. 
        /// 
        private static void OnPageNumberChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
        {
            Invariant.Assert(d != null && d is DocumentPageView);
            ((DocumentPageView)d).OnPageContentChanged();
        } 

        ///  
        /// Duplicates content of the PageVisual. 
        /// 
        private DrawingVisual DuplicatePageVisual() 
        {
            DrawingVisual drawingVisual = null;
            if (_pageHost != null && _pageHost.PageVisual != null && _documentPage.Size != Size.Empty)
            { 
                const double maxWidth = 4096.0;
                const double maxHeight = maxWidth; 
 
                Rect pageVisualRect = new Rect(_documentPage.Size);
 
                pageVisualRect.Width = Math.Min(pageVisualRect.Width, maxWidth);
                pageVisualRect.Height = Math.Min(pageVisualRect.Height, maxHeight);

                drawingVisual = new DrawingVisual(); 

                try 
                { 
                    if(pageVisualRect.Width > 1.0 && pageVisualRect.Height > 1.0)
                    { 
                        RenderTargetBitmap renderTargetBitmap = new RenderTargetBitmap((int)pageVisualRect.Width, (int)pageVisualRect.Height, 96.0, 96.0, PixelFormats.Pbgra32);
                        renderTargetBitmap.Render(_pageHost.PageVisual);

                        ImageBrush imageBrush = new ImageBrush(renderTargetBitmap); 
                        drawingVisual.Opacity = 0.50;
                        using (DrawingContext dc = drawingVisual.RenderOpen()) 
                        { 
                            dc.DrawRectangle(imageBrush, null, pageVisualRect);
                        } 
                    }
                }
                catch(System.OverflowException)
                { 
                    // Ignore overflow exception - caused by render target creation not possible under current memory conditions.
                } 
 
            }
            return drawingVisual; 
        }

        #endregion Private Methods
 
        //--------------------------------------------------------------------
        // 
        //  Private Fields 
        //
        //------------------------------------------------------------------- 

        #region Private Fields

        private DocumentPaginator _documentPaginator; 
        private double _pageZoom;
        private DocumentPage _documentPage; 
        private DocumentPage _documentPageAsync; 
        private DocumentPageTextView _textView;
        private DocumentPageHost _pageHost; 
        private Visual _pageVisualClone;
        private Size _visualCloneSize;
        private bool _useAsynchronous = true;
        private bool _suspendLayout; 
        private bool _disposed;
        private bool _newPageConnected; 
 
        #endregion Private Fields
 
        //-------------------------------------------------------------------
        //
        //  IServiceProvider Members
        // 
        //-------------------------------------------------------------------
 
        #region IServiceProvider Members 

        ///  
        /// Returns service objects associated with this control.
        /// 
        /// Specifies the type of service object to get.
        object IServiceProvider.GetService(Type serviceType) 
        {
            return this.GetService(serviceType); 
        } 

        #endregion IServiceProvider Members 

        //--------------------------------------------------------------------
        //
        //  IDisposable Members 
        //
        //------------------------------------------------------------------- 
 
        #region IDisposable Members
 
        /// 
        /// Dispose the object.
        /// 
        void IDisposable.Dispose() 
        {
            this.Dispose(); 
        } 

        #endregion IDisposable Members 
    }
}

 


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