FlowDocumentScrollViewer.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ DotNET / DotNET / 8.0 / untmp / WIN_WINDOWS / lh_tools_devdiv_wpf / Windows / wcp / Framework / System / Windows / Controls / FlowDocumentScrollViewer.cs / 4 / FlowDocumentScrollViewer.cs

                            //---------------------------------------------------------------------------- 
//
// Copyright (C) Microsoft Corporation.  All rights reserved.
//
//--------------------------------------------------------------------------- 

using System;                           // Object 
using System.Collections;               // IEnumerator 
using System.Collections.ObjectModel;   // ReadOnlyCollection
using System.Printing;                  // WritingCompletedEventArgs 
using System.Security;                  // SecurityCritical
using System.Windows.Annotations;       // AnnotationService
using System.Windows.Automation.Peers;  // AutomationPeer
using System.Windows.Data;              // BindingOperations 
using System.Windows.Controls.Primitives;   // IScrollInfo
using System.Windows.Documents;         // FlowDocument 
using System.Windows.Documents.Serialization;  // WritingCompletedEventArgs 
using System.Windows.Input;             // KeyEventArgs
using System.Windows.Media;             // ScaleTransform, VisualTreeHelper 
using System.Windows.Markup;            // IAddChild
using System.Windows.Threading;         // Dispatcher
using System.Windows.Xps;               // XpsDocumentWriter
using MS.Internal;                      // Invariant, DoubleUtil 
using MS.Internal.Annotations.Anchoring;
using MS.Internal.Commands;             // CommandHelpers 
using MS.Internal.Controls;             // EmptyEnumerator 
using MS.Internal.Documents;            // FindToolBar
using MS.Internal.KnownBoxes;           // BooleanBoxes 
using MS.Internal.AppModel;             // IJournalState

namespace System.Windows.Controls
{ 
    /// 
    /// The FlowDocumentScrollViewer displays a FlowDocument within a bottomless scrolling view; 
    /// the content of the FlowDocument is displayed in a single column. 
    /// This bottomless scrolling view is similar to the text display provided by web browsers
    /// and most applications today. 
    /// 
    [TemplatePart(Name = "PART_ContentHost", Type = typeof(ScrollViewer))]
    [TemplatePart(Name = "PART_FindToolBarHost", Type = typeof(Decorator))]
    [TemplatePart(Name = "PART_ToolBarHost", Type = typeof(Decorator))] 
    [ContentProperty("Document")]
    public class FlowDocumentScrollViewer : Control, IAddChild, IServiceProvider, IJournalState 
    { 
        //-------------------------------------------------------------------
        // 
        //  Constructors
        //
        //-------------------------------------------------------------------
 
        #region Constructors
 
        ///  
        /// Static Constructor
        ///  
        static FlowDocumentScrollViewer()
        {
            DefaultStyleKeyProperty.OverrideMetadata(
                typeof(FlowDocumentScrollViewer), 
                new FrameworkPropertyMetadata(new ComponentResourceKey(typeof(PresentationUIStyleResources), "PUIFlowDocumentScrollViewer")));
 
            _dType = DependencyObjectType.FromSystemTypeInternal(typeof(FlowDocumentScrollViewer)); 

 
            CreateCommandBindings();

            EventManager.RegisterClassHandler(typeof(FlowDocumentScrollViewer), RequestBringIntoViewEvent, new RequestBringIntoViewEventHandler(HandleRequestBringIntoView));
            EventManager.RegisterClassHandler(typeof(FlowDocumentScrollViewer), Keyboard.KeyDownEvent, new KeyEventHandler(KeyDownHandler), true); 
        }
 
        ///  
        /// Default Constructor
        ///  
        public FlowDocumentScrollViewer()
            : base()
        {
            // Set data ID which will be used to identify annotations on content in this viewer 
            AnnotationService.SetDataId(this, "FlowDocument");
        } 
 
        #endregion
 
        //--------------------------------------------------------------------
        //
        //  Public Methods
        // 
        //-------------------------------------------------------------------
 
        #region Public Methods 

        ///  
        /// Called when the template tree has been created.
        /// 
        public override void OnApplyTemplate()
        { 
            base.OnApplyTemplate();
 
            // Initialize FindTooBar host. 
            // If old FindToolBar is enabled, disable it first to ensure appropriate cleanup.
            if (FindToolBar != null) 
            {
                ToggleFindToolBar(false);
            }
            _findToolBarHost = GetTemplateChild(_findToolBarHostTemplateName) as Decorator; 

            // Initialize TooBar host. 
            _toolBarHost = GetTemplateChild(_toolBarHostTemplateName) as Decorator; 
            if (_toolBarHost != null)
            { 
                _toolBarHost.Visibility = IsToolBarVisible ? Visibility.Visible : Visibility.Collapsed;
            }

            // Initialize ContentHost. 
            // If old ContentHost is enabled, disable it first to ensure appropriate cleanup.
            if (_contentHost != null) 
            { 
                BindingOperations.ClearBinding(_contentHost, HorizontalScrollBarVisibilityProperty);
                BindingOperations.ClearBinding(_contentHost, VerticalScrollBarVisibilityProperty); 
                _contentHost.ScrollChanged -= new ScrollChangedEventHandler(OnScrollChanged);
                RenderScope.Document = null;
                ClearValue(TextEditor.PageHeightProperty);
                _contentHost.Content = null; 
            }
            _contentHost = GetTemplateChild(_contentHostTemplateName) as ScrollViewer; 
            if (_contentHost != null) 
            {
                if (_contentHost.Content != null) 
                {
                    throw new NotSupportedException(SR.Get(SRID.FlowDocumentScrollViewerMarkedAsContentHostMustHaveNoContent));
                }
                _contentHost.ScrollChanged += new ScrollChangedEventHandler(OnScrollChanged); 
                CreateTwoWayBinding(_contentHost, HorizontalScrollBarVisibilityProperty, "HorizontalScrollBarVisibility");
                CreateTwoWayBinding(_contentHost, VerticalScrollBarVisibilityProperty, "VerticalScrollBarVisibility"); 
 
                // Need to make ScrollViewer non-focusable, otherwise it will eat keyboard navigation from editor.
                _contentHost.Focusable = false; 

                // Initialize the content of the ScrollViewer.
                _contentHost.Content = new FlowDocumentView();
                RenderScope.Document = Document; 
            }
 
            // Initialize TextEditor. 
            AttachTextEditor();
 
            // Apply the current zoom to the content host.
            ApplyZoom();
        }
 
        /// 
        /// Invokes the Find Toolbar. This is analogous to the ApplicationCommands.Find. 
        ///  
        public void Find()
        { 
            OnFindCommand();
        }

        ///  
        /// Invokes the Print Dialog. This is analogous to the ApplicationCommands.Print.
        ///  
        public void Print() 
        {
            OnPrintCommand(); 
        }

        /// 
        /// Cancels current printing job. This is analogous to the ApplicationCommands.CancelPrint. 
        /// 
        public void CancelPrint() 
        { 
            OnCancelPrintCommand();
        } 

        /// 
        /// Increases the current zoom.
        ///  
        public void IncreaseZoom()
        { 
            OnIncreaseZoomCommand(); 
        }
 
        /// 
        /// Decreases the current zoom.
        /// 
        public void DecreaseZoom() 
        {
            OnDecreaseZoomCommand(); 
        } 

        #endregion Public Methods 

        //--------------------------------------------------------------------
        //
        //  Public Properties 
        //
        //-------------------------------------------------------------------- 
 
        #region Public Properties
        ///  
        /// A Property representing a content of this FlowDocumentScrollViewer.
        /// 
        public FlowDocument Document
        { 
            get { return (FlowDocument)GetValue(DocumentProperty); }
            set { SetValue(DocumentProperty, value); } 
        } 

        ///  
        /// Text Selection (readonly)
        /// 
        public TextSelection Selection
        { 
            get
            { 
                ITextSelection textSelection = null; 
                FlowDocument flowDocument = Document;
                if (flowDocument != null) 
                {
                    textSelection = flowDocument.StructuralCache.TextContainer.TextSelection;
                }
                return textSelection as TextSelection; 
            }
        } 
 
        /// 
        /// The Zoom applied to all pages; this value is 100-based. 
        /// 
        public double Zoom
        {
            get { return (double)GetValue(ZoomProperty); } 
            set { SetValue(ZoomProperty, value); }
        } 
 
        /// 
        /// The maximum allowed value of the Zoom property. 
        /// 
        public double MaxZoom
        {
            get { return (double)GetValue(MaxZoomProperty); } 
            set { SetValue(MaxZoomProperty, value); }
        } 
 
        /// 
        /// The minimum allowed value of the Zoom property. 
        /// 
        public double MinZoom
        {
            get { return (double)GetValue(MinZoomProperty); } 
            set { SetValue(MinZoomProperty, value); }
        } 
 
        /// 
        /// The amount the Zoom property is incremented or decremented when 
        /// the IncreaseZoom or DecreaseZoom command is executed.
        /// 
        public double ZoomIncrement
        { 
            get { return (double)GetValue(ZoomIncrementProperty); }
            set { SetValue(ZoomIncrementProperty, value); } 
        } 

        ///  
        /// Whether the viewer can increase the current zoom.
        /// 
        public bool CanIncreaseZoom
        { 
            get { return (bool)GetValue(CanIncreaseZoomProperty); }
        } 
 
        /// 
        /// Whether the viewer can decrease the current zoom. 
        /// 
        public bool CanDecreaseZoom
        {
            get { return (bool)GetValue(CanDecreaseZoomProperty); } 
        }
 
        ///  
        /// Whether text selection is enabled or disabled.
        ///  
        public bool IsSelectionEnabled
        {
            get { return (bool)GetValue(IsSelectionEnabledProperty); }
            set { SetValue(IsSelectionEnabledProperty, value); } 
        }
 
        ///  
        /// Whether the ToolBar is visible or not.
        ///  
        public bool IsToolBarVisible
        {
            get { return (bool)GetValue(IsToolBarVisibleProperty); }
            set { SetValue(IsToolBarVisibleProperty, value); } 
        }
 
        ///  
        /// Whether or not a horizontal scrollbar is shown.
        ///  
        public ScrollBarVisibility HorizontalScrollBarVisibility
        {
            get { return (ScrollBarVisibility)GetValue(HorizontalScrollBarVisibilityProperty); }
            set { SetValue(HorizontalScrollBarVisibilityProperty, value); } 
        }
 
        ///  
        /// Whether or not a vertical scrollbar is shown.
        ///  
        public ScrollBarVisibility VerticalScrollBarVisibility
        {
            get { return (ScrollBarVisibility)GetValue(VerticalScrollBarVisibilityProperty); }
            set { SetValue(VerticalScrollBarVisibilityProperty, value); } 
        }
 
        #region Public Dynamic Properties 

        ///  
        /// 
        /// 
        public static readonly DependencyProperty DocumentProperty =
                DependencyProperty.Register( 
                        "Document",
                        typeof(FlowDocument), 
                        typeof(FlowDocumentScrollViewer), 
                        new FrameworkPropertyMetadata(
                                null, 
                                new PropertyChangedCallback(DocumentChanged)));

        /// 
        ///  
        /// 
        public static readonly DependencyProperty ZoomProperty = 
                FlowDocumentPageViewer.ZoomProperty.AddOwner( 
                        typeof(FlowDocumentScrollViewer),
                        new FrameworkPropertyMetadata( 
                                100d,
                                new PropertyChangedCallback(ZoomChanged),
                                new CoerceValueCallback(CoerceZoom)));
 
        /// 
        ///  
        ///  
        public static readonly DependencyProperty MaxZoomProperty =
                FlowDocumentPageViewer.MaxZoomProperty.AddOwner( 
                        typeof(FlowDocumentScrollViewer),
                        new FrameworkPropertyMetadata(
                                200d,
                                new PropertyChangedCallback(MaxZoomChanged), 
                                new CoerceValueCallback(CoerceMaxZoom)));
 
        ///  
        /// 
        ///  
        public static readonly DependencyProperty MinZoomProperty =
                FlowDocumentPageViewer.MinZoomProperty.AddOwner(
                        typeof(FlowDocumentScrollViewer),
                        new FrameworkPropertyMetadata( 
                                80d,
                                new PropertyChangedCallback(MinZoomChanged))); 
 
        /// 
        ///  
        /// 
        public static readonly DependencyProperty ZoomIncrementProperty =
                FlowDocumentPageViewer.ZoomIncrementProperty.AddOwner(
                        typeof(FlowDocumentScrollViewer)); 

        ///  
        ///  
        /// 
        private static readonly DependencyPropertyKey CanIncreaseZoomPropertyKey = 
                DependencyProperty.RegisterReadOnly(
                        "CanIncreaseZoom",
                        typeof(bool),
                        typeof(FlowDocumentScrollViewer), 
                        new FrameworkPropertyMetadata(BooleanBoxes.TrueBox));
 
        ///  
        /// 
        ///  
        public static readonly DependencyProperty CanIncreaseZoomProperty = CanIncreaseZoomPropertyKey.DependencyProperty;

        /// 
        ///  
        /// 
        private static readonly DependencyPropertyKey CanDecreaseZoomPropertyKey = 
                DependencyProperty.RegisterReadOnly( 
                        "CanDecreaseZoom",
                        typeof(bool), 
                        typeof(FlowDocumentScrollViewer),
                        new FrameworkPropertyMetadata(BooleanBoxes.TrueBox));

        ///  
        /// 
        ///  
        public static readonly DependencyProperty CanDecreaseZoomProperty = CanDecreaseZoomPropertyKey.DependencyProperty; 

        ///  
        /// 
        /// 
        public static readonly DependencyProperty IsSelectionEnabledProperty =
                DependencyProperty.Register( 
                        "IsSelectionEnabled",
                        typeof(bool), 
                        typeof(FlowDocumentScrollViewer), 
                        new FrameworkPropertyMetadata(
                                BooleanBoxes.TrueBox, 
                                new PropertyChangedCallback(IsSelectionEnabledChanged)));

        /// 
        ///  
        /// 
        public static readonly DependencyProperty IsToolBarVisibleProperty = 
                DependencyProperty.Register( 
                        "IsToolBarVisible",
                        typeof(bool), 
                        typeof(FlowDocumentScrollViewer),
                        new FrameworkPropertyMetadata(
                                BooleanBoxes.FalseBox,
                                new PropertyChangedCallback(IsToolBarVisibleChanged))); 

        ///  
        ///  
        /// 
        public static readonly DependencyProperty HorizontalScrollBarVisibilityProperty = 
                ScrollViewer.HorizontalScrollBarVisibilityProperty.AddOwner(
                        typeof(FlowDocumentScrollViewer),
                        new FrameworkPropertyMetadata(ScrollBarVisibility.Auto));
 
        /// 
        ///  
        ///  
        public static readonly DependencyProperty VerticalScrollBarVisibilityProperty =
                ScrollViewer.VerticalScrollBarVisibilityProperty.AddOwner( 
                        typeof(FlowDocumentScrollViewer),
                        new FrameworkPropertyMetadata(ScrollBarVisibility.Visible));

        #endregion Public Dynamic Properties 

        #endregion Public Properties 
 
        //-------------------------------------------------------------------
        // 
        //  Protected Methods
        //
        //--------------------------------------------------------------------
 
        #region Protected Methods
 
        ///  
        /// Called when print has been completed.
        ///  
        protected virtual void OnPrintCompleted()
        {
            ClearPrintingState();
        } 

        ///  
        /// Handler for the Find command 
        /// 
        protected virtual void OnFindCommand() 
        {
            if (CanShowFindToolBar)
            {
                // Toggle on the FindToolBar between visible and hidden state. 
                ToggleFindToolBar(FindToolBar == null);
            } 
        } 

        ///  
        /// Handler for the Print command.
        /// 
        protected virtual void OnPrintCommand()
        { 
#if !DONOTREFPRINTINGASMMETA
            XpsDocumentWriter docWriter; 
            PrintDocumentImageableArea ia = null; 
            FlowDocumentPaginator paginator;
            Thickness pagePadding; 

            // Only one printing job is allowed.
            if (_printingState != null)
            { 
                return;
            } 
 
            // If the document is FlowDocument, do custom printing. Otherwise go through default path.
            if (Document != null) 
            {
                // Show print dialog.
                docWriter = PrintQueue.CreateXpsDocumentWriter(ref ia);
                if (docWriter != null && ia != null) 
                {
                    // Suspend layout on FlowDocumentView. 
                    if (RenderScope != null) 
                    {
                        RenderScope.SuspendLayout(); 
                    }

                    // Store the current state of the document in the PrintingState
                    paginator = ((IDocumentPaginatorSource)Document).DocumentPaginator as FlowDocumentPaginator; 
                    _printingState = new FlowDocumentPrintingState();
                    _printingState.XpsDocumentWriter = docWriter; 
                    _printingState.PageSize = paginator.PageSize; 
                    _printingState.PagePadding = Document.PagePadding;
                    _printingState.IsSelectionEnabled = IsSelectionEnabled; 
                    _printingState.ColumnWidth = Document.ColumnWidth;

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

                    // Register for XpsDocumentWriter events. 
                    docWriter.WritingCompleted += new WritingCompletedEventHandler(HandlePrintCompleted); 
                    docWriter.WritingCancelled += new WritingCancelledEventHandler(HandlePrintCancelled);
 
                    // Add PreviewCanExecute handler to have a chance to disable UI Commands during printing.
                    if (_contentHost != null)
                    {
                        CommandManager.AddPreviewCanExecuteHandler(_contentHost, new CanExecuteRoutedEventHandler(PreviewCanExecuteRoutedEventHandler)); 
                    }
 
                    // Disable TextSelection, if currently enabled. 
                    if (IsSelectionEnabled)
                    { 
                        IsSelectionEnabled = false;
                    }

                    // Change the PageSize and PagePadding for the document to match the CanvasSize for the printer device. 
                    paginator.PageSize = new Size(ia.MediaSizeWidth, ia.MediaSizeHeight);
                    pagePadding = Document.ComputePageMargin(); 
                    Document.PagePadding = new Thickness( 
                        Math.Max(ia.OriginWidth, pagePadding.Left),
                        Math.Max(ia.OriginHeight, pagePadding.Top), 
                        Math.Max(ia.MediaSizeWidth - (ia.OriginWidth + ia.ExtentWidth), pagePadding.Right),
                        Math.Max(ia.MediaSizeHeight - (ia.OriginHeight + ia.ExtentHeight), pagePadding.Bottom));
                    Document.ColumnWidth = double.PositiveInfinity;
 
                    // Send DocumentPaginator to the printer.
                    docWriter.WriteAsync(paginator); 
                } 
                else
                { 
                    OnPrintCompleted();
                }
            }
            else 
            {
                OnPrintCompleted(); 
            } 
#endif // DONOTREFPRINTINGASMMETA
        } 

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

        ///  
        /// Handler for the IncreaseZoom command. 
        /// 
        protected virtual void OnIncreaseZoomCommand() 
        {
            // If can zoom in, increase zoom by the zoom increment value.
            if (CanIncreaseZoom)
            { 
                Zoom = Math.Min(Zoom + ZoomIncrement, MaxZoom);
            } 
        } 

        ///  
        /// Handler for the DecreaseZoom command.
        /// 
        protected virtual void OnDecreaseZoomCommand()
        { 
            // If can zoom out, decrease zoom by the zoom increment value.
            if (CanDecreaseZoom) 
            { 
                Zoom = Math.Max(Zoom - ZoomIncrement, MinZoom);
            } 
        }

        /// 
        /// This is the method that responds to the KeyDown event. 
        /// 
        /// Event arguments 
        ///  
        /// Critical: get_SearchUp is defined in a non-APTCA assembly.
        /// TreatAsSafe: call to get_SearchUp does not entail any risk. 
        /// 
        [SecurityCritical, SecurityTreatAsSafe]
        protected override void OnKeyDown(KeyEventArgs e)
        { 
            if (e.Handled) { return; }
 
            switch (e.Key) 
            {
                // Esc -- Close FindToolBar 
                case Key.Escape:
                    if (FindToolBar != null)
                    {
                        ToggleFindToolBar(false); 
                        e.Handled = true;
                    } 
                    break; 

                // F3 -- Invoke Find 
                case Key.F3:
                    if (CanShowFindToolBar)
                    {
                        if (FindToolBar != null) 
                        {
                            // If the Shift key is also pressed, then search up. 
                            FindToolBar.SearchUp = ((e.KeyboardDevice.Modifiers & ModifierKeys.Shift) == ModifierKeys.Shift); 
                            OnFindInvoked(this, EventArgs.Empty);
                        } 
                        else
                        {
                            // Make the FindToolBar visible
                            ToggleFindToolBar(true); 
                        }
                        e.Handled = true; 
                    } 
                    break;
            } 

            // If not handled, do default handling.
            if (!e.Handled)
            { 
                base.OnKeyDown(e);
            } 
        } 

        ///  
        /// Mouse wheel rotation handler.
        /// 
        /// MouseWheelEventArgs
        protected override void OnMouseWheel(MouseWheelEventArgs e) 
        {
            if (e.Handled) { return; } 
 
            if (_contentHost != null)
            { 
                //Press Ctrl and scroll mouse wheel will zoom in/out the document
                if ((Keyboard.Modifiers & ModifierKeys.Control) == ModifierKeys.Control)
                {
                    // If can zoom in, increase zoom by the zoom increment value. 
                    if (e.Delta > 0 && CanIncreaseZoom)
                    { 
                        Zoom = Math.Min(Zoom + ZoomIncrement, MaxZoom); 
                    }
                    else if (e.Delta < 0 && CanDecreaseZoom) 
                    {
                        Zoom = Math.Max(Zoom - ZoomIncrement, MinZoom);
                    }
                } 
                else
                { 
                    if (e.Delta < 0) 
                    {
                        _contentHost.LineDown(); 
                    }
                    else
                    {
                        _contentHost.LineUp(); 
                    }
                } 
                e.Handled = true; 
            }
 
            // If not handled, do default handling.
            if (!e.Handled)
            {
                base.OnMouseWheel(e); 
            }
        } 
 
        /// 
        /// Called when ContextMenuOpening is raised on this element. 
        /// 
        /// Event arguments
        protected override void OnContextMenuOpening(ContextMenuEventArgs e)
        { 
            base.OnContextMenuOpening(e);
            DocumentViewerHelper.OnContextMenuOpening(Document, this, e); 
        } 

        ///  
        /// Creates AutomationPeer ()
        /// 
        protected override AutomationPeer OnCreateAutomationPeer()
        { 
            return new FlowDocumentScrollViewerAutomationPeer(this);
        } 
 
        #endregion Protected Methods
 
        //-------------------------------------------------------------------
        //
        //  Protected Properties
        // 
        //-------------------------------------------------------------------
 
        #region Protected Properties 

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

        #endregion Protected Properties 
 
        //-------------------------------------------------------------------
        // 
        //  Internal Methods
        //
        //--------------------------------------------------------------------
 
        #region Internal Methods
 
        ///  
        /// Allows FrameworkElement to augment the EventRoute.
        ///  
        internal override bool BuildRouteCore(EventRoute route, RoutedEventArgs args)
        {
            // If FlowDocumentScrollViewer is used as embedded viewer (in FlowDocumentReader),
            // it is not part of logical tree, so default logic in FE to re-add logical 
            // tree from branched node does not work here.
            // But before FlowDocumentScrollViewer is added to the event route, logical 
            // ancestors up to Document need to be added to the route. Otherwise 
            // content will not have a chance to react to events first.
            // This breaks navigation cursor management logic, because TextEditor attached 
            // to FlowDocumentScrollViewer handles those events first.
            DependencyObject document = this.Document as DependencyObject;
            if (document != null && LogicalTreeHelper.GetParent(document) != this)
            { 
                DependencyObject branchNode = route.PeekBranchNode() as DependencyObject;
                if (branchNode != null && DocumentViewerHelper.IsLogicalDescendent(branchNode, document)) 
                { 
                    // Add intermediate ContentElements to the route.
                    FrameworkElement.AddIntermediateElementsToRoute( 
                        LogicalTreeHelper.GetParent(document), route, args, LogicalTreeHelper.GetParent(branchNode));
                }
            }
            return base.BuildRouteCore(route, args); 
        }
 
        ///  
        /// Bring specified content position into view.
        ///  
        internal object BringContentPositionIntoView(object arg)
        {
            ITextPointer contentPosition = arg as ITextPointer;
            if (contentPosition != null) 
            {
                ITextView textView = GetTextView(); 
                if (textView != null && textView.IsValid && textView.RenderScope is IScrollInfo && contentPosition.TextContainer == textView.TextContainer) 
                {
                    if (textView.Contains(contentPosition)) 
                    {
                        Rect rect = textView.GetRectangleFromTextPosition(contentPosition);
                        if (rect != Rect.Empty)
                        { 
                            IScrollInfo isi = (IScrollInfo)textView.RenderScope;
                            isi.SetVerticalOffset(rect.Top + isi.VerticalOffset); 
                        } 
                    }
                    else 
                    {
                        // Wait until ContentPosition in in the view.
                        Dispatcher.BeginInvoke(DispatcherPriority.Background, new DispatcherOperationCallback(BringContentPositionIntoView), contentPosition);
                    } 
                }
            } 
            return null; 
        }
 
        #endregion Internal Methods

        //-------------------------------------------------------------------
        // 
        //  Internal Properties
        // 
        //-------------------------------------------------------------------- 

        #region Internal Properties 

        /// 
        /// Access to the ScrollViewer in FlowDocumentScrollViewer style
        ///  
        internal ScrollViewer ScrollViewer { get { return _contentHost; } }
 
        ///  
        /// Whether FindToolBar can be enabled.
        ///  
        internal bool CanShowFindToolBar
        {
            get { return (_findToolBarHost != null && Document != null && _textEditor != null); }
        } 

        ///  
        /// Whether currently printing the content. 
        /// 
        internal bool IsPrinting 
        {
            get { return (_printingState != null); }
        }
 
        /// 
        /// Returns textpointer for upper left corner of content. 
        ///  
        internal TextPointer ContentPosition
        { 
            get
            {
                TextPointer contentPosition = null;
                ITextView textView = GetTextView(); 
                if (textView != null && textView.IsValid && textView.RenderScope is IScrollInfo)
                { 
                    contentPosition = textView.GetTextPositionFromPoint(new Point(), true) as TextPointer; 
                }
                return contentPosition; 
            }
        }

        #endregion Internal Properties 

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

        #region Private Methods
 
        /// 
        /// Enables/disables the FindToolBar. 
        ///  
        /// Whether to enable/disable FindToolBar.
        private void ToggleFindToolBar(bool enable) 
        {
            Invariant.Assert(enable == (FindToolBar == null));
            DocumentViewerHelper.ToggleFindToolBar(_findToolBarHost, new EventHandler(OnFindInvoked), enable);
            // FindToolBar is embedded inside the toolbar, so event if the ToolBar is not visible 
            // it needs to be shown when showing FindToolBar.
            if (!IsToolBarVisible && _toolBarHost != null) 
            { 
                _toolBarHost.Visibility = enable ? Visibility.Visible : Visibility.Collapsed;
            } 
        }

        /// 
        /// Apply the zoom value to the render scope. 
        /// 
        private void ApplyZoom() 
        { 
            if (RenderScope != null)
            { 
                RenderScope.LayoutTransform = new ScaleTransform(Zoom / 100, Zoom / 100);
            }
        }
 
        /// 
        /// Attach TextEditor to Document, if supports text. 
        ///  
        private void AttachTextEditor()
        { 
            ITextView textView;

            //get annotation service and state so we can restore it
            AnnotationService service = AnnotationService.GetService(this); 
            bool serviceOldState = false;
 
            //disable the service if enabled 
            if ((service != null) && service.IsEnabled)
            { 
                serviceOldState = true;
                service.Disable();
            }
 
            // This method is called when Document is changing or control template
            // is replaced, so need to clear old TextEditor data. 
            if (_textEditor != null) 
            {
                _textEditor.TextContainer.TextView = null; 
                _textEditor.OnDetach();
                _textEditor = null;
            }
 
            // If new Document supports TextEditor, create one.
            // If the Document is already attached to TextEditor (TextSelection != null), 
            // do not create TextEditor for this instance of the viewer. (This situation may happen 
            // when the same instance of Document is attached to more than one viewer).
            if (IsSelectionEnabled && 
                Document != null &&
                RenderScope != null &&
                Document.StructuralCache.TextContainer.TextSelection == null)
            { 
                textView = GetTextView();
                _textEditor = new TextEditor(Document.StructuralCache.TextContainer, this, false); 
                _textEditor.IsReadOnly = !IsEditingEnabled; 
                _textEditor.TextView = textView;
                _textEditor.TextContainer.TextView = textView; 
            }

            //restore AnnotationsService state
            if ((service != null) && serviceOldState) 
            {
                service.Enable(service.Store); 
            } 

            // If TextEditor is not enabled, FindToolBar cannot be visible. 
            if (_textEditor == null && FindToolBar != null)
            {
                ToggleFindToolBar(false);
            } 
        }
 
        ///  
        /// Handler for ScrollViewer's OnScrollChanged event.
        ///  
        private void OnScrollChanged(object sender, ScrollChangedEventArgs e)
        {
            if (e.OriginalSource == ScrollViewer)
            { 
                // If ScrollViewer.ViewportHeight has been changed, TextEditor.PageHeight must be updated
                if (!DoubleUtil.IsZero(e.ViewportHeightChange)) 
                { 
                    SetValue(TextEditor.PageHeightProperty, e.ViewportHeight);
                } 
            }
        }

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

        ///  
        /// Clear printing state. 
        /// 
        private void ClearPrintingState() 
        {
#if !DONOTREFPRINTINGASMMETA
            if (_printingState != null)
            { 
                // Resume layout on FlowDocumentView.
                if (RenderScope != null) 
                { 
                    RenderScope.ResumeLayout();
                } 

                // Enable TextSelection, if it was previously enabled.
                if (_printingState.IsSelectionEnabled)
                { 
                    IsSelectionEnabled = true;
                } 
 
                // Remove PreviewCanExecute handler (added when Print command was executed).
                if (_contentHost != null) 
                {
                    CommandManager.RemovePreviewCanExecuteHandler(_contentHost, new CanExecuteRoutedEventHandler(PreviewCanExecuteRoutedEventHandler));
                }
 
                // Unregister for XpsDocumentWriter events.
                _printingState.XpsDocumentWriter.WritingCompleted -= new WritingCompletedEventHandler(HandlePrintCompleted); 
                _printingState.XpsDocumentWriter.WritingCancelled -= new WritingCancelledEventHandler(HandlePrintCancelled); 

                // Restore old page metrics on FlowDocument. 
                Document.PagePadding = _printingState.PagePadding;
                Document.ColumnWidth = _printingState.ColumnWidth;
                ((IDocumentPaginatorSource)Document).DocumentPaginator.PageSize = _printingState.PageSize;
 
                _printingState = null;
                // Since _documentWriter value is used to determine CanExecute state, we must invalidate that state. 
                CommandManager.InvalidateRequerySuggested(); 
            }
#endif // DONOTREFPRINTINGASMMETA 
        }

        /// 
        /// Makes sure the target is visible in the client area. 
        /// 
        /// RequestBringIntoViewEventArgs indicates the element and region to scroll into view. 
        private void HandleRequestBringIntoView(RequestBringIntoViewEventArgs args) 
        {
            DependencyObject child; 
            DependencyObject document;
            IContentHost ich;
            ReadOnlyCollection rects;
            UIElement targetUIElement; 
            Rect targetRect = Rect.Empty;
 
            if (args != null && args.TargetObject != null && Document != null) 
            {
                document = Document; 

                // If the passed in object is a logical child of FlowDocumentScrollViewer's Document,
                // attempt to make it visible now.
                // Special case: TargetObject is the document itself. Then scroll to the top (page 1). 
                // This supports navigating from baseURI#anchor to just baseURI.
                if (args.TargetObject == document) 
                { 
                    if (_contentHost != null)
                    { 
                        _contentHost.ScrollToHome();
                    }
                    args.Handled = true; // Mark the event as handled.
                } 
                else if (args.TargetObject is UIElement)
                { 
                    targetUIElement = (UIElement)args.TargetObject; 
                    // Since entire content of FlowDocument is represented by
                    // bottomless page, the target has to be connected to visual tree. 
                    // Otherwise, it is not descendant of FlowDocument.
                    if (RenderScope != null && RenderScope.IsAncestorOf(targetUIElement))
                    {
                        targetRect = args.TargetRect; 
                        if (targetRect.IsEmpty)
                        { 
                            targetRect = new Rect(targetUIElement.RenderSize); 
                        }
 
                        targetRect = MakeVisible((IScrollInfo)RenderScope, targetUIElement, targetRect);

                        if(!targetRect.IsEmpty)
                        { 
                            GeneralTransform t = RenderScope.TransformToAncestor(this);
                            targetRect = t.TransformBounds(targetRect); 
                        } 
                        args.Handled = true; // Mark the event as handled.
                    } 
                }
                else if (args.TargetObject is ContentElement)
                {
                    // Verify if TargetObject is in fact a child of Document. 
                    child = args.TargetObject;
                    while (child != null && child != document) 
                    { 
                       child = LogicalTreeHelper.GetParent(child);
                    } 

                    if (child != null)
                    {
                        ich = GetIContentHost(); 
                        if (ich != null)
                        { 
                            // Get the position of the content. 
                            rects = ich.GetRectangles((ContentElement)args.TargetObject);
                            if (rects.Count > 0) 
                            {
                                targetRect = MakeVisible((IScrollInfo)RenderScope, (Visual)ich, rects[0]);

                                if(!targetRect.IsEmpty) 
                                {
                                    GeneralTransform t = RenderScope.TransformToAncestor(this); 
                                    targetRect = t.TransformBounds(targetRect); 
                                }
                            } 
                        }
                        args.Handled = true; // Mark the event as handled.
                    }
                } 

                if (args.Handled) 
                { 
                    // Create new BringIntoView request for this element, so
                    // if there is an ancestor handling BringIntoView, it can 
                    // react appropriately and bring this element into view.
                    if (targetRect.IsEmpty)
                    {
                        BringIntoView(); 
                    }
                    else 
                    { 
                        BringIntoView(targetRect);
                    } 
                }
            }
        }
 
        /// 
        /// The Document has changed and needs to be updated. 
        ///  
        private void DocumentChanged(FlowDocument oldDocument, FlowDocument newDocument)
        { 
            // Use TextSelection to determine whether the new document belongs to another
            // control or not.
            if (newDocument != null &&
                newDocument.StructuralCache.TextContainer != null && 
                newDocument.StructuralCache.TextContainer.TextSelection != null)
            { 
                throw new ArgumentException(SR.Get(SRID.FlowDocumentScrollViewerDocumentBelongsToAnotherFlowDocumentScrollViewerAlready)); 
            }
 
            // Cleanup state associated with the old document.
            if (oldDocument != null)
            {
                // If Document was added to logical tree of FlowDocumentScrollViewer before, remove it. 
                if (_documentAsLogicalChild)
                { 
                    RemoveLogicalChild(oldDocument); 
                }
                // Remove the document from the ContentHost. 
                if (RenderScope != null)
                {
                    RenderScope.Document = null;
                } 

                oldDocument.ClearValue(PathNode.HiddenParentProperty); 
                oldDocument.StructuralCache.ClearUpdateInfo(true); 
            }
 
            // If FlowDocumentScrollViewer was created through style, then do not modify
            // the logical tree. Instead, set "core parent" for the Document.
            if (newDocument != null && LogicalTreeHelper.GetParent(newDocument) != null)
            { 
                // Set the "core parent" back to us.
                ContentOperations.SetParent(newDocument, this); 
                _documentAsLogicalChild = false; 
            }
            else 
            {
                _documentAsLogicalChild = true;
            }
 
            // Initialize state associated with the new document.
            if (newDocument != null) 
            { 
                // Set the document on the ContentHost.
                if (RenderScope != null) 
                {
                    RenderScope.Document = newDocument;
                }
                // If Document should be part of FlowDocumentScrollViewer's logical tree, add it. 
                if (_documentAsLogicalChild)
                { 
                    AddLogicalChild(newDocument); 
                }
 
                // Set the hidden parent of the document
                newDocument.SetValue(PathNode.HiddenParentProperty, this);
                newDocument.StructuralCache.ClearUpdateInfo(true);
            } 

            // Attach TextEditor, if content supports it. This method will also 
            // detach TextEditor from old content. 
            AttachTextEditor();
 
            // Update the toolbar with our current document state.
            if (!CanShowFindToolBar)
            {
                // Disable FindToolBar, if the content does not support it. 
                if (FindToolBar != null)
                { 
                    ToggleFindToolBar(false); 
                }
            } 

            // Document is also represented as Automation child. Need to invalidate peer to force update.
            FlowDocumentScrollViewerAutomationPeer peer = UIElementAutomationPeer.FromElement(this) as FlowDocumentScrollViewerAutomationPeer;
            if (peer != null) 
            {
                peer.InvalidatePeer(); 
            } 
        }
 
        /// 
        /// Retrieves ITextView associated with the content.
        /// NOTE: Not retrieved from TextEditor, because it may not exist in some cases.
        ///  
        private ITextView GetTextView()
        { 
            ITextView textView = null; 
            if (RenderScope is IServiceProvider)
            { 
                textView = (ITextView)((IServiceProvider)RenderScope).GetService(typeof(ITextView));
            }
            return textView;
        } 

        ///  
        /// Retrieves IContentHost associated with the content. 
        /// 
        private IContentHost GetIContentHost() 
        {
            IContentHost ich = null;
            if (RenderScope != null && VisualTreeHelper.GetChildrenCount(RenderScope) > 0)
            { 
                ich = VisualTreeHelper.GetChild(RenderScope, 0) as IContentHost;
            } 
            return ich; 
        }
 
        /// 
        /// Create two way property binding.
        /// 
        private void CreateTwoWayBinding(FrameworkElement fe, DependencyProperty dp, string propertyPath) 
        {
            Binding binding = new Binding(propertyPath); 
            binding.Mode = BindingMode.TwoWay; 
            binding.Source = this;
            fe.SetBinding(dp, binding); 
        }

        #region Commands
 
        /// 
        /// Set up Command and RoutedCommand bindings. 
        ///  
        private static void CreateCommandBindings()
        { 
            ExecutedRoutedEventHandler executedHandler;
            CanExecuteRoutedEventHandler canExecuteHandler;

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

            // Create private commands to control content scrolling. It is required because TextEditor binds 
            // those Keys to its own commands (caret navigation), which are useless in viewing scenarios.
            // Since following commands are private, it is OK to pass String.Empty as descriptive text for the command.
            _commandLineDown = new RoutedUICommand(String.Empty, "FDSV_LineDown", typeof(FlowDocumentScrollViewer));
            _commandLineUp = new RoutedUICommand(String.Empty, "FDSV_LineUp", typeof(FlowDocumentScrollViewer)); 
            _commandLineLeft = new RoutedUICommand(String.Empty, "FDSV_LineLeft", typeof(FlowDocumentScrollViewer));
            _commandLineRight = new RoutedUICommand(String.Empty, "FDSV_LineRight", typeof(FlowDocumentScrollViewer)); 
 
            // Register editing command handlers
            TextEditor.RegisterCommandHandlers(typeof(FlowDocumentScrollViewer), /*acceptsRichContent:*/true, /*readOnly:*/!IsEditingEnabled, /*registerEventListeners*/true); 

            // Command: ApplicationCommands.Find
            CommandHelpers.RegisterCommandHandler(typeof(FlowDocumentScrollViewer), ApplicationCommands.Find,
                executedHandler, canExecuteHandler); 

            // Command: ApplicationCommands.Print 
            CommandHelpers.RegisterCommandHandler(typeof(FlowDocumentScrollViewer), ApplicationCommands.Print, 
                executedHandler, canExecuteHandler);
 
            // Command: ApplicationCommands.CancelPrint
            CommandHelpers.RegisterCommandHandler(typeof(FlowDocumentScrollViewer), ApplicationCommands.CancelPrint,
                executedHandler, canExecuteHandler); // no key gesture
 
            // Command: NavigationCommands.PreviousPage
            CommandHelpers.RegisterCommandHandler(typeof(FlowDocumentScrollViewer), NavigationCommands.PreviousPage, 
                executedHandler, canExecuteHandler, new KeyGesture(Key.PageUp)); 

            // Command: NavigationCommands.NextPage 
            CommandHelpers.RegisterCommandHandler(typeof(FlowDocumentScrollViewer), NavigationCommands.NextPage,
                executedHandler, canExecuteHandler, new KeyGesture(Key.PageDown));

            // Command: NavigationCommands.FirstPage 
            CommandHelpers.RegisterCommandHandler(typeof(FlowDocumentScrollViewer), NavigationCommands.FirstPage,
                executedHandler, canExecuteHandler, new KeyGesture(Key.Home), new KeyGesture(Key.Home, ModifierKeys.Control)); 
 
            // Command: NavigationCommands.LastPage
            CommandHelpers.RegisterCommandHandler(typeof(FlowDocumentScrollViewer), NavigationCommands.LastPage, 
                executedHandler, canExecuteHandler, new KeyGesture(Key.End), new KeyGesture(Key.End, ModifierKeys.Control));

            // Command: NavigationCommands.IncreaseZoom
            CommandHelpers.RegisterCommandHandler(typeof(FlowDocumentScrollViewer), NavigationCommands.IncreaseZoom, 
                executedHandler, canExecuteHandler, new KeyGesture(Key.OemPlus, ModifierKeys.Control));
 
            // Command: NavigationCommands.DecreaseZoom 
            CommandHelpers.RegisterCommandHandler(typeof(FlowDocumentScrollViewer), NavigationCommands.DecreaseZoom,
                executedHandler, canExecuteHandler, new KeyGesture(Key.OemMinus, ModifierKeys.Control)); 

            // Command: FDSV_LineDown
            CommandHelpers.RegisterCommandHandler(typeof(FlowDocumentScrollViewer), _commandLineDown,
                executedHandler, canExecuteHandler, new KeyGesture(Key.Down)); 

            // Command: FDSV_LineUp 
            CommandHelpers.RegisterCommandHandler(typeof(FlowDocumentScrollViewer), _commandLineUp, 
                executedHandler, canExecuteHandler, new KeyGesture(Key.Up));
 
            // Command: FDSV_LineLeft
            CommandHelpers.RegisterCommandHandler(typeof(FlowDocumentScrollViewer), _commandLineLeft,
                executedHandler, canExecuteHandler, new KeyGesture(Key.Left));
 
            // Command: FDSV_LineRight
            CommandHelpers.RegisterCommandHandler(typeof(FlowDocumentScrollViewer), _commandLineRight, 
                executedHandler, canExecuteHandler, new KeyGesture(Key.Right)); 
        }
 
        /// 
        /// Central handler for CanExecuteRouted events fired by Commands directed at FlowDocumentScrollViewer.
        /// 
        /// The target of this Command, expected to be FlowDocumentScrollViewer 
        /// The event arguments for this event.
        private static void CanExecuteRoutedEventHandler(object target, CanExecuteRoutedEventArgs args) 
        { 
            FlowDocumentScrollViewer viewer = target as FlowDocumentScrollViewer;
            Invariant.Assert(viewer != null, "Target of QueryEnabledEvent must be FlowDocumentScrollViewer."); 
            Invariant.Assert(args != null, "args cannot be null.");

            // FlowDocumentScrollViewer is capable of execution of the majority of its commands.
            // Special rules: 
            // a) during printing only CancelPrint is enabled.
            // b) Find command is enabled only when FindToolBar is enabled. 
            // c) Print command is enabled when Document is attached. 
            // d) CancelPrint command is enabled only during printing.
            if (viewer._printingState == null) 
            {
                if (args.Command == ApplicationCommands.Find)
                {
                    args.CanExecute = viewer.CanShowFindToolBar; 
                }
                else if (args.Command == ApplicationCommands.Print) 
                { 
                    args.CanExecute = (viewer.Document != null);
                } 
                else if (args.Command == ApplicationCommands.CancelPrint)
                {
                    args.CanExecute = false;
                } 
                else
                { 
                    args.CanExecute = true; 
                }
            } 
            else
            {
                args.CanExecute = (args.Command == ApplicationCommands.CancelPrint);
            } 
        }
 
        ///  
        /// Central handler for all ExecutedRoutedEvent fired by Commands directed at FlowDocumentScrollViewer.
        ///  
        /// The target of this Command, expected to be FlowDocumentScrollViewer.
        /// The event arguments associated with this event.
        private static void ExecutedRoutedEventHandler(object target, ExecutedRoutedEventArgs args)
        { 
            FlowDocumentScrollViewer viewer = target as FlowDocumentScrollViewer;
            Invariant.Assert(viewer != null, "Target of ExecuteEvent must be FlowDocumentScrollViewer."); 
            Invariant.Assert(args != null, "args cannot be null."); 

            // Now we execute the method corresponding to the Command that fired this event; 
            // each Command has its own protected virtual method that performs the operation
            // corresponding to the Command.
            if (args.Command == ApplicationCommands.Find)
            { 
                viewer.OnFindCommand();
            } 
            else if (args.Command == ApplicationCommands.Print) 
            {
                viewer.OnPrintCommand(); 
            }
            else if (args.Command == ApplicationCommands.CancelPrint)
            {
                viewer.OnCancelPrintCommand(); 
            }
            else if (args.Command == NavigationCommands.IncreaseZoom) 
            { 
                viewer.OnIncreaseZoomCommand();
            } 
            else if (args.Command == NavigationCommands.DecreaseZoom)
            {
                viewer.OnDecreaseZoomCommand();
            } 
            else if (args.Command == _commandLineDown)
            { 
                if (viewer._contentHost != null) 
                {
                    viewer._contentHost.LineDown(); 
                }
            }
            else if (args.Command == _commandLineUp)
            { 
                if (viewer._contentHost != null)
                { 
                    viewer._contentHost.LineUp(); 
                }
            } 
            else if (args.Command == _commandLineLeft)
            {
                if (viewer._contentHost != null)
                { 
                    viewer._contentHost.LineLeft();
                } 
            } 
            else if (args.Command == _commandLineRight)
            { 
                if (viewer._contentHost != null)
                {
                    viewer._contentHost.LineRight();
                } 
            }
            else if (args.Command == NavigationCommands.NextPage) 
            { 
                if (viewer._contentHost != null)
                { 
                    viewer._contentHost.PageDown();
                }
            }
            else if (args.Command == NavigationCommands.PreviousPage) 
            {
                if (viewer._contentHost != null) 
                { 
                    viewer._contentHost.PageUp();
                } 
            }
            else if (args.Command == NavigationCommands.FirstPage)
            {
                if (viewer._contentHost != null) 
                {
                    viewer._contentHost.ScrollToHome(); 
                } 
            }
            else if (args.Command == NavigationCommands.LastPage) 
            {
                if (viewer._contentHost != null)
                {
                    viewer._contentHost.ScrollToEnd(); 
                }
            } 
            else 
            {
                Invariant.Assert(false, "Command not handled in ExecutedRoutedEventHandler."); 
            }
        }

        ///  
        /// Invoked when the "Find" button in the Find Toolbar is clicked.
        /// This method invokes the actual Find process. 
        ///  
        /// The object that sent this event
        /// The Click Events associated with this event 
        private void OnFindInvoked(object sender, EventArgs e)
        {
            ITextRange findResult;
            FindToolBar findToolBar = FindToolBar; 

            if (findToolBar != null && _textEditor != null) 
            { 
                // In order to show current text selection TextEditor requires Focus to be set on the UIScope.
                // If there embedded controls, it may happen that embedded control currently has focus and find 
                // was invoked through hotkeys. To support this case we manually move focus to the appropriate element.
                Focus();

                findResult = DocumentViewerHelper.Find(findToolBar, _textEditor, _textEditor.TextView, _textEditor.TextView); 

                // If we found something, TextEditor will bring the selection into view. 
                // It is possible, because RenderScope is inside ScrollViewer. 

                // If we did not find anything, alert the user. 
                if ((findResult == null) || findResult.IsEmpty)
                {
                    DocumentViewerHelper.ShowFindUnsuccessfulMessage(findToolBar);
                } 
            }
        } 
 
        /// 
        /// Disable commands on DocumentViewerBase when this printing is in progress. 
        /// 
        private void PreviewCanExecuteRoutedEventHandler(object target, CanExecuteRoutedEventArgs args)
        {
            ScrollViewer sv = target as ScrollViewer; 
            Invariant.Assert(sv != null, "Target of PreviewCanExecuteRoutedEventHandler must be ScrollViewer.");
            Invariant.Assert(args != null, "args cannot be null."); 
 
            // Disable UI commands, if printing is in progress.
            if (_printingState != null) 
            {
                args.CanExecute = false;
                args.Handled = true;
            } 
        }
 
        ///  
        /// Called when a key event occurs.
        ///  
        private static void KeyDownHandler(object sender, KeyEventArgs e)
        {
            DocumentViewerHelper.KeyDownHelper(e, ((FlowDocumentScrollViewer)sender)._findToolBarHost);
        } 

        #endregion Commands 
 
        #region Static Methods
 
        /// 
        /// Wrapper around IScrollInfo.MakeVisible
        /// 
        /// The IScrollInfo to call MakeVisible on 
        /// visual parameter for call to MakeVisible
        /// rectangle parameter for call to MakeVisible 
        /// Rectangle representing visible portion of visual relative to scrollInfo's viewport 
        private static Rect MakeVisible(IScrollInfo scrollInfo, Visual visual, Rect rectangle)
        { 
            //


 

            Rect result; 
 
            if(scrollInfo.GetType() == typeof(System.Windows.Controls.ScrollContentPresenter))
            { 
                result = ((ScrollContentPresenter)scrollInfo).MakeVisible(visual, rectangle, false);
            }
            else
            { 
                result = scrollInfo.MakeVisible(visual, rectangle);
            } 
 
            return result;
        } 

        /// 
        /// The Document has changed and needs to be updated.
        ///  
        private static void DocumentChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        { 
            Invariant.Assert(d != null && d is FlowDocumentScrollViewer); 
            ((FlowDocumentScrollViewer)d).DocumentChanged((FlowDocument)e.OldValue, (FlowDocument)e.NewValue);
 
            // Since Document state is used to determine CanExecute state, we must invalidate that state.
            CommandManager.InvalidateRequerySuggested();
        }
 
        /// 
        /// The Zoom has changed and needs to be updated. 
        ///  
        private static void ZoomChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        { 
            Invariant.Assert(d != null && d is FlowDocumentScrollViewer);
            FlowDocumentScrollViewer viewer = (FlowDocumentScrollViewer)d;
            if (!DoubleUtil.AreClose((double)e.OldValue, (double)e.NewValue))
            { 
                // If zoom has been changed, CanIncrease/DecreaseZoom property need to be updated.
                viewer.SetValue(CanIncreaseZoomPropertyKey, BooleanBoxes.Box(DoubleUtil.GreaterThan(viewer.MaxZoom, viewer.Zoom))); 
                viewer.SetValue(CanDecreaseZoomPropertyKey, BooleanBoxes.Box(DoubleUtil.LessThan(viewer.MinZoom, viewer.Zoom))); 

                // Apply the new zoom value. 
                viewer.ApplyZoom();
            }
        }
 
        /// 
        /// Coerce Zoom with Max/MinZoom, MinZoom works as the baseline. 
        ///  
        private static object CoerceZoom(DependencyObject d, object value)
        { 
            Invariant.Assert(d != null && d is FlowDocumentScrollViewer);
            FlowDocumentScrollViewer viewer = (FlowDocumentScrollViewer)d;

            double zoom = (double)value; 

            double maxZoom = viewer.MaxZoom; 
            if (DoubleUtil.LessThan(maxZoom, zoom)) 
            {
                return maxZoom; 
            }

            double minZoom = viewer.MinZoom;
            if (DoubleUtil.GreaterThan(minZoom, zoom)) 
            {
                return minZoom; 
            } 

            return value; 
        }

        /// 
        /// The MaxZoom has changed and needs to be updated. 
        /// 
        private static void MaxZoomChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
        { 
            Invariant.Assert(d != null && d is FlowDocumentScrollViewer);
            FlowDocumentScrollViewer viewer = (FlowDocumentScrollViewer)d; 

            viewer.CoerceValue(ZoomProperty);
            viewer.SetValue(CanIncreaseZoomPropertyKey, BooleanBoxes.Box(DoubleUtil.GreaterThan(viewer.MaxZoom, viewer.Zoom)));
        } 

        ///  
        /// MaxZoom need to be coerced if MinZoom > MaxZoom 
        /// 
        private static object CoerceMaxZoom(DependencyObject d, object value) 
        {
            Invariant.Assert(d != null && d is FlowDocumentScrollViewer);
            FlowDocumentScrollViewer viewer = (FlowDocumentScrollViewer)d;
 
            double min = viewer.MinZoom;
            return ((double)value < min) ? min : value; 
        } 

        ///  
        /// The MinZoom has changed and needs to be updated.
        /// 
        private static void MinZoomChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        { 
            Invariant.Assert(d != null && d is FlowDocumentScrollViewer);
            FlowDocumentScrollViewer viewer = (FlowDocumentScrollViewer)d; 
 
            viewer.CoerceValue(MaxZoomProperty);
            viewer.CoerceValue(ZoomProperty); 
            viewer.SetValue(CanDecreaseZoomPropertyKey, BooleanBoxes.Box(DoubleUtil.LessThan(viewer.MinZoom, viewer.Zoom)));
        }

        ///  
        /// Validate Zoom, MaxZoom, MinZoom and ZoomIncrement value.
        ///  
        /// Value to validate. 
        /// True if the value is valid, false otherwise.
        private static bool ZoomValidateValue(object o) 
        {
            double value = (double)o;
            return (!Double.IsNaN(value) && !Double.IsInfinity(value) && DoubleUtil.GreaterThan(value, 0d));
        } 

        ///  
        /// Called from the event handler to make sure the target is visible in the client area. 
        /// 
        /// The instance handling the event. 
        /// RequestBringIntoViewEventArgs indicates the element and region to scroll into view.
        private static void HandleRequestBringIntoView(object sender, RequestBringIntoViewEventArgs args)
        {
            if (sender != null && sender is FlowDocumentScrollViewer) 
            {
                ((FlowDocumentScrollViewer)sender).HandleRequestBringIntoView(args); 
            } 
        }
 
        /// 
        /// The IsSelectionEnabled has changed and needs to be updated.
        /// 
        private static void IsSelectionEnabledChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
        {
            Invariant.Assert(d != null && d is FlowDocumentScrollViewer); 
            FlowDocumentScrollViewer viewer = (FlowDocumentScrollViewer)d; 

            viewer.AttachTextEditor(); 
        }

        /// 
        /// The IsToolBarVisible has changed and needs to be updated. 
        /// 
        private static void IsToolBarVisibleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
        { 
            Invariant.Assert(d != null && d is FlowDocumentScrollViewer);
            FlowDocumentScrollViewer viewer = (FlowDocumentScrollViewer)d; 

            if (viewer._toolBarHost != null)
            {
                viewer._toolBarHost.Visibility = (bool)e.NewValue ? Visibility.Visible : Visibility.Collapsed; 
            }
        } 
 
        #endregion Static Methods
 
        #endregion Private Methods

        //--------------------------------------------------------------------
        // 
        //  Private Properties
        // 
        //------------------------------------------------------------------- 

        #region Private Properties 

        /// 
        /// Returns FindToolBar, if enabled.
        ///  
        private FindToolBar FindToolBar
        { 
            get { return (_findToolBarHost != null) ? _findToolBarHost.Child as FindToolBar : null; } 
        }
 
        /// 
        /// Content of the ScrollViewer which is treated as RenderScope for the TextEditor.
        /// 
        private FlowDocumentView RenderScope 
        {
            get { return (_contentHost != null) ? _contentHost.Content as FlowDocumentView : null; } 
        } 

        #endregion Private Properties 

        //-------------------------------------------------------------------
        //
        //  Private Fields 
        //
        //------------------------------------------------------------------- 
 
        #region Private Fields
 
        private TextEditor _textEditor;             // Text editor (enables text selection)
        private Decorator _findToolBarHost;         // Host for FindToolBar
        private Decorator _toolBarHost;             // Host for ToolBar
        private ScrollViewer _contentHost;          // Host for content viewer 
        private bool _documentAsLogicalChild;       // Is Document part of logical tree
        private FlowDocumentPrintingState _printingState;   // Printing state 
 
        private const string _contentHostTemplateName = "PART_ContentHost";         // Name for ContentHost
        private const string _findToolBarHostTemplateName = "PART_FindToolBarHost"; // Name for the Find ToolBar host 
        private const string _toolBarHostTemplateName = "PART_ToolBarHost";         // Name for the ToolBar host

        private static bool IsEditingEnabled = false;       // A flag enabling text editing within the viewer
                                                            // accessible only through reflection. 
        private static RoutedUICommand _commandLineDown;    // Private LineDown command
        private static RoutedUICommand _commandLineUp;      // Private LineUp command 
        private static RoutedUICommand _commandLineLeft;    // Private LineLeft command 
        private static RoutedUICommand _commandLineRight;   // Private LineRight command
 
        #endregion Private Fields

        //--------------------------------------------------------------------
        // 
        //  IAddChild Members
        // 
        //------------------------------------------------------------------- 

        #region IAddChild Members 

        /// 
        /// Called to add the object as a Child.
        ///  
        /// Object to add as a child.
        /// FlowDocumentScrollViewer only supports a single child of type IDocumentPaginator. 
        void IAddChild.AddChild(Object value) 
        {
            if (value == null) 
            {
                throw new ArgumentNullException("value");
            }
            // Check if Content has already been set. 
            if (this.Document != null)
            { 
                throw new ArgumentException(SR.Get(SRID.FlowDocumentScrollViewerCanHaveOnlyOneChild)); 
            }
            if (!(value is FlowDocument)) 
            {
                throw new ArgumentException(SR.Get(SRID.UnexpectedParameterType, value.GetType(), typeof(FlowDocument)), "value");
            }
            Document = value as FlowDocument; 
        }
 
        ///  
        /// Called when text appears under the tag in markup
        ///  
        /// Text to add to the Object.
        /// FlowDocumentScrollViewer does not support Text children.
        void IAddChild.AddText(string text)
        { 
            XamlSerializerUtil.ThrowIfNonWhiteSpaceInAddText(text, this);
        } 
 
        #endregion IAddChild Members
 
        //--------------------------------------------------------------------
        //
        //  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) 
        {
            object service = null; 
            if (serviceType == null) 
            {
                throw new ArgumentNullException("serviceType"); 
            }

            // Following services are available:
            // (1) TextView 
            // (2) TextContainer
            if (serviceType == typeof(ITextView)) 
            { 
                service = GetTextView();
            } 
            else if (serviceType == typeof(TextContainer) || serviceType == typeof(ITextContainer))
            {
                if (Document != null)
                { 
                    service = ((IServiceProvider)Document).GetService(serviceType);
                } 
            } 
            return service;
        } 

        #endregion IServiceProvider Members

        //------------------------------------------------------------------- 
        //
        //  IJournalState Members 
        // 
        //--------------------------------------------------------------------
 
        #region IJournalState Members

        [Serializable]
        private class JournalState : CustomJournalStateInternal 
        {
            public JournalState(int contentPosition, LogicalDirection contentPositionDirection, double zoom) 
            { 
                ContentPosition = contentPosition;
                ContentPositionDirection = contentPositionDirection; 
                Zoom = zoom;
            }
            public int ContentPosition;
            public LogicalDirection ContentPositionDirection; 
            public double Zoom;
        } 
 
        /// 
        ///  
        /// 
        CustomJournalStateInternal IJournalState.GetJournalState(JournalReason journalReason)
        {
            int cp = -1; 
            LogicalDirection cpDirection = LogicalDirection.Forward;
            TextPointer contentPosition = ContentPosition; 
            if (contentPosition != null) 
            {
                cp = contentPosition.Offset; 
                cpDirection = contentPosition.LogicalDirection;
            }
            return new JournalState(cp, cpDirection, Zoom);
        } 

        ///  
        ///  
        /// 
        void IJournalState.RestoreJournalState(CustomJournalStateInternal state) 
        {
            JournalState viewerState = state as JournalState;
            if (state != null)
            { 
                Zoom = viewerState.Zoom;
                if (viewerState.ContentPosition != -1) 
                { 
                    FlowDocument document = Document;
                    if (document != null) 
                    {
                        TextContainer textContainer = document.StructuralCache.TextContainer;
                        if (viewerState.ContentPosition <= textContainer.SymbolCount)
                        { 
                            TextPointer contentPosition = textContainer.CreatePointerAtOffset(viewerState.ContentPosition, viewerState.ContentPositionDirection);
                            // This need be called because the UI may not be ready when Contentposition is set. 
                            Dispatcher.BeginInvoke(DispatcherPriority.Input, new DispatcherOperationCallback(BringContentPositionIntoView), contentPosition); 
                        }
                    } 
                }
            }
        }
 
        #endregion IJournalState Members
 
        //------------------------------------------------------------------- 
        //
        //  DTypeThemeStyleKey 
        //
        //-------------------------------------------------------------------

        #region DTypeThemeStyleKey 

        ///  
        /// Returns the DependencyObjectType for the registered ThemeStyleKey's default 
        /// value. Controls will override this method to return approriate types
        ///  
        internal override DependencyObjectType DTypeThemeStyleKey
        {
            get { return _dType; }
        } 

        private static DependencyObjectType _dType; 
 
        #endregion DTypeThemeStyleKey
    } 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK