FlowDocumentReader.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

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

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

using System;                               // Object 
using System.Collections;                   // IEnumerator 
using System.Collections.ObjectModel;       // ReadOnlyCollection
using System.Security;                      // SecurityCritical 
using System.Windows.Automation.Peers;      // AutomationPeer
using System.Windows.Data;                  // BindingOperations
using System.Windows.Controls.Primitives;   // PlacementMode
using System.Windows.Documents;             // FlowDocument 
using System.Windows.Input;                 // KeyEventArgs
using System.Windows.Media;                 // ScaleTransform, VisualTreeHelper 
using System.Windows.Markup;                // IAddChild 
using System.Windows.Threading;             // Dispatcher
using MS.Internal;                          // Invariant, DoubleUtil 
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 
{
    ///  
    /// FlowDocumentReader provides a full user experience for consuming text content.
    /// It will be used as the default viewer for loose XAML or containers that contain
    /// text content, and can be styled and re-used by developers for use within their applications.
    ///  
    [TemplatePart(Name = "PART_ContentHost", Type = typeof(Decorator))]
    [TemplatePart(Name = "PART_FindToolBarHost", Type = typeof(Decorator))] 
    [ContentProperty("Document")] 
    public class FlowDocumentReader : Control, IAddChild, IJournalState
    { 
        //-------------------------------------------------------------------
        //
        //  Constructors
        // 
        //-------------------------------------------------------------------
 
        #region Constructors 

        ///  
        /// Static Constructor
        /// 
        static FlowDocumentReader()
        { 
            DefaultStyleKeyProperty.OverrideMetadata(
                typeof(FlowDocumentReader), 
                new FrameworkPropertyMetadata(new ComponentResourceKey(typeof(PresentationUIStyleResources), "PUIFlowDocumentReader"))); 

            _dType = DependencyObjectType.FromSystemTypeInternal(typeof(FlowDocumentReader)); 

            TextBoxBase.SelectionBrushProperty.OverrideMetadata(typeof(FlowDocumentReader),
                new FrameworkPropertyMetadata(new PropertyChangedCallback(UpdateCaretElement)));
            TextBoxBase.SelectionOpacityProperty.OverrideMetadata(typeof(FlowDocumentReader), 
                new FrameworkPropertyMetadata(new PropertyChangedCallback(UpdateCaretElement)));
 
            CreateCommandBindings(); 

            EventManager.RegisterClassHandler(typeof(FlowDocumentReader), Keyboard.KeyDownEvent, new KeyEventHandler(KeyDownHandler), true); 
        }

        /// 
        /// Default Constructor 
        /// 
        public FlowDocumentReader() 
            : base() 
        {
        } 

        #endregion Constructors

        //-------------------------------------------------------------------- 
        //
        //  Public Methods 
        // 
        //-------------------------------------------------------------------
 
        #region Public Methods

        /// 
        /// Build Visual tree 
        /// 
        public override void OnApplyTemplate() 
        { 
            base.OnApplyTemplate();
 
            // Initialize ContentHost.
            // If old ContentHost is enabled, disable it first to ensure appropriate cleanup.
            if (CurrentViewer != null)
            { 
                DetachViewer(CurrentViewer);
                _contentHost.Child = null; 
            } 
            _contentHost = GetTemplateChild(_contentHostTemplateName) as Decorator;
            if (_contentHost != null) 
            {
                if (_contentHost.Child != null)
                {
                    throw new NotSupportedException(SR.Get(SRID.FlowDocumentReaderDecoratorMarkedAsContentHostMustHaveNoContent)); 
                }
 
                SwitchViewingModeCore(ViewingMode); 
            }
 
            // 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; 
            _findButton = GetTemplateChild(_findButtonTemplateName) as ToggleButton;
        } 

        /// 
        /// Whether the master page can be moved to the specified page.
        ///  
        /// Page number.
        public bool CanGoToPage(int pageNumber) 
        { 
            bool canGoToPage = false;
            if (CurrentViewer != null) 
            {
                canGoToPage = CurrentViewer.CanGoToPage(pageNumber);
            }
            return canGoToPage; 
        }
 
        ///  
        /// 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();
        } 

        /// 
        /// Switches the current viewing mode. This is analogous to the SwitchViewingModeCommand.
        ///  
        /// Viewing mode.
        public void SwitchViewingMode(FlowDocumentReaderViewingMode viewingMode) 
        { 
            OnSwitchViewingModeCommand(viewingMode);
        } 

        #endregion Public Methods

        //-------------------------------------------------------------------- 
        //
        //  Public Properties 
        // 
        //--------------------------------------------------------------------
 
        #region Public Properties

        /// 
        /// ViewingMode of FlowDocumentReader. 
        /// 
        public FlowDocumentReaderViewingMode ViewingMode 
        { 
            get { return (FlowDocumentReaderViewingMode)GetValue(ViewingModeProperty); }
            set { SetValue(ViewingModeProperty, value); } 
        }

        /// 
        /// Text Selection (readonly) 
        /// 
        public TextSelection Selection 
        { 
            get
            { 
                TextSelection result = null;
                IFlowDocumentViewer viewer;
                if (_contentHost != null)
                { 
                    viewer = _contentHost.Child as IFlowDocumentViewer;
                    if(viewer != null) 
                    { 
                        result = viewer.TextSelection as TextSelection;
                    } 
                }
                return result;
            }
        } 

        ///  
        /// Whether Page view can be enabled or not. 
        /// 
        public bool IsPageViewEnabled 
        {
            get { return (bool)GetValue(IsPageViewEnabledProperty); }
            set { SetValue(IsPageViewEnabledProperty, BooleanBoxes.Box(value)); }
        } 

        ///  
        /// Whether TwoPage view can be enabled or not. 
        /// 
        public bool IsTwoPageViewEnabled 
        {
            get { return (bool)GetValue(IsTwoPageViewEnabledProperty); }
            set { SetValue(IsTwoPageViewEnabledProperty, BooleanBoxes.Box(value)); }
        } 

        ///  
        /// Whether Scroll view can be enabled or not. 
        /// 
        public bool IsScrollViewEnabled 
        {
            get { return (bool)GetValue(IsScrollViewEnabledProperty); }
            set { SetValue(IsScrollViewEnabledProperty, BooleanBoxes.Box(value)); }
        } 

        ///  
        /// The number of pages currently available for viewing. This value 
        /// is updated as content is paginated, and will change dramatically
        /// when the content is resized, or edited. 
        /// 
        public int PageCount
        {
            get { return (int)GetValue(PageCountProperty); } 
        }
 
        ///  
        /// The one-based page number of the page being displayed. If there is no content,
        /// this value will be 0. 
        /// 
        public int PageNumber
        {
            get { return (int)GetValue(PageNumberProperty); } 
        }
 
        ///  
        /// Whether the viewer can move the master page to the previous page.
        ///  
        public bool CanGoToPreviousPage
        {
            get { return (bool)GetValue(CanGoToPreviousPageProperty); }
        } 

        ///  
        /// Whether the viewer can advance the master page to the next page. 
        /// 
        public bool CanGoToNextPage 
        {
            get { return (bool)GetValue(CanGoToNextPageProperty); }
        }
 
        /// 
        /// Is find function enabled or not 
        ///  
        public bool IsFindEnabled
        { 
            get { return (bool)GetValue(IsFindEnabledProperty); }
            set { SetValue(IsFindEnabledProperty, BooleanBoxes.Box(value)); }
        }
 
        /// 
        /// Is print function enabled or not 
        ///  
        public bool IsPrintEnabled
        { 
            get { return (bool)GetValue(IsPrintEnabledProperty); }
            set { SetValue(IsPrintEnabledProperty, BooleanBoxes.Box(value)); }
        }
 
        /// 
        /// A Property representing a content of this FlowDocumentScrollViewer. 
        ///  
        public FlowDocument Document
        { 
            get { return (FlowDocument)GetValue(DocumentProperty); }
            set { SetValue(DocumentProperty, value); }
        }
 
        /// 
        /// 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); }
        }

        ///  
        /// 
        ///  
        public Brush SelectionBrush 
        {
            get { return (Brush)GetValue(SelectionBrushProperty); } 
            set { SetValue(SelectionBrushProperty, value); }
        }

        ///  
        /// 
        ///  
        public double SelectionOpacity 
        {
            get { return (double)GetValue(SelectionOpacityProperty); } 
            set { SetValue(SelectionOpacityProperty, value); }
        }

        #region Public Dynamic Properties 

        ///  
        ///  
        /// 
        public static readonly DependencyProperty ViewingModeProperty = 
                DependencyProperty.Register(
                        "ViewingMode",
                        typeof(FlowDocumentReaderViewingMode),
                        typeof(FlowDocumentReader), 
                        new FrameworkPropertyMetadata(
                                FlowDocumentReaderViewingMode.Page, 
                                FrameworkPropertyMetadataOptions.AffectsMeasure, 
                                new PropertyChangedCallback(ViewingModeChanged)),
                        new ValidateValueCallback(IsValidViewingMode)); 

        /// 
        /// 
        ///  
        public static readonly DependencyProperty IsPageViewEnabledProperty =
                DependencyProperty.Register( 
                        "IsPageViewEnabled", 
                        typeof(bool),
                        typeof(FlowDocumentReader), 
                        new FrameworkPropertyMetadata(
                                BooleanBoxes.TrueBox,
                                new PropertyChangedCallback(ViewingModeEnabledChanged)));
 
        /// 
        ///  
        ///  
        public static readonly DependencyProperty IsTwoPageViewEnabledProperty =
                DependencyProperty.Register( 
                        "IsTwoPageViewEnabled",
                        typeof(bool),
                        typeof(FlowDocumentReader),
                        new FrameworkPropertyMetadata( 
                                BooleanBoxes.TrueBox,
                                new PropertyChangedCallback(ViewingModeEnabledChanged))); 
 
        /// 
        ///  
        /// 
        public static readonly DependencyProperty IsScrollViewEnabledProperty =
                DependencyProperty.Register(
                        "IsScrollViewEnabled", 
                        typeof(bool),
                        typeof(FlowDocumentReader), 
                        new FrameworkPropertyMetadata( 
                                BooleanBoxes.TrueBox,
                                new PropertyChangedCallback(ViewingModeEnabledChanged))); 

        /// 
        /// 
        ///  
        private static readonly DependencyPropertyKey PageCountPropertyKey =
                DependencyProperty.RegisterReadOnly( 
                        "PageCount", 
                        typeof(int),
                        typeof(FlowDocumentReader), 
                        new FrameworkPropertyMetadata(0));

        /// 
        ///  
        /// 
        public static readonly DependencyProperty PageCountProperty = PageCountPropertyKey.DependencyProperty; 
 
        /// 
        ///  
        /// 
        private static readonly DependencyPropertyKey PageNumberPropertyKey =
                DependencyProperty.RegisterReadOnly(
                        "PageNumber", 
                        typeof(int),
                        typeof(FlowDocumentReader), 
                        new FrameworkPropertyMetadata(0)); 

        ///  
        /// 
        /// 
        public static readonly DependencyProperty PageNumberProperty = PageNumberPropertyKey.DependencyProperty;
        ///  
        /// 
        ///  
        private static readonly DependencyPropertyKey CanGoToPreviousPagePropertyKey = 
                DependencyProperty.RegisterReadOnly(
                        "CanGoToPreviousPage", 
                        typeof(bool),
                        typeof(FlowDocumentReader),
                        new FrameworkPropertyMetadata(BooleanBoxes.FalseBox));
 
        /// 
        ///  
        ///  
        public static readonly DependencyProperty CanGoToPreviousPageProperty = CanGoToPreviousPagePropertyKey.DependencyProperty;
 
        /// 
        /// 
        /// 
        private static readonly DependencyPropertyKey CanGoToNextPagePropertyKey = 
                DependencyProperty.RegisterReadOnly(
                        "CanGoToNextPage", 
                        typeof(bool), 
                        typeof(FlowDocumentReader),
                        new FrameworkPropertyMetadata(BooleanBoxes.FalseBox)); 

        /// 
        /// 
        ///  
        public static readonly DependencyProperty CanGoToNextPageProperty = CanGoToNextPagePropertyKey.DependencyProperty;
 
        ///  
        /// 
        ///  
        public static readonly DependencyProperty IsFindEnabledProperty =
                DependencyProperty.Register(
                        "IsFindEnabled",
                        typeof(bool), 
                        typeof(FlowDocumentReader),
                        new FrameworkPropertyMetadata( 
                                BooleanBoxes.TrueBox, 
                                new PropertyChangedCallback(IsFindEnabledChanged)));
 
        /// 
        /// 
        /// 
        public static readonly DependencyProperty IsPrintEnabledProperty = 
                DependencyProperty.Register(
                        "IsPrintEnabled", 
                        typeof(bool), 
                        typeof(FlowDocumentReader),
                        new FrameworkPropertyMetadata( 
                                BooleanBoxes.TrueBox,
                                new PropertyChangedCallback(IsPrintEnabledChanged)));

        ///  
        /// 
        ///  
        public static readonly DependencyProperty DocumentProperty = 
                DependencyProperty.Register(
                        "Document", 
                        typeof(FlowDocument),
                        typeof(FlowDocumentReader),
                        new FrameworkPropertyMetadata(
                                null, 
                                new PropertyChangedCallback(DocumentChanged)));
 
        ///  
        /// 
        ///  
        public static readonly DependencyProperty ZoomProperty =
                FlowDocumentPageViewer.ZoomProperty.AddOwner(
                        typeof(FlowDocumentReader),
                        new FrameworkPropertyMetadata( 
                                100d,
                                new PropertyChangedCallback(ZoomChanged), 
                                new CoerceValueCallback(CoerceZoom))); 

        ///  
        /// 
        /// 
        public static readonly DependencyProperty MaxZoomProperty =
                FlowDocumentPageViewer.MaxZoomProperty.AddOwner( 
                        typeof(FlowDocumentReader),
                        new FrameworkPropertyMetadata( 
                                200d, 
                                new PropertyChangedCallback(MaxZoomChanged),
                                new CoerceValueCallback(CoerceMaxZoom))); 

        /// 
        /// 
        ///  
        public static readonly DependencyProperty MinZoomProperty =
                FlowDocumentPageViewer.MinZoomProperty.AddOwner( 
                        typeof(FlowDocumentReader), 
                        new FrameworkPropertyMetadata(
                                80d, 
                                new PropertyChangedCallback(MinZoomChanged)));

        /// 
        ///  
        /// 
        public static readonly DependencyProperty ZoomIncrementProperty = 
                FlowDocumentPageViewer.ZoomIncrementProperty.AddOwner( 
                        typeof(FlowDocumentReader));
 
        /// 
        /// 
        /// 
        private static readonly DependencyPropertyKey CanIncreaseZoomPropertyKey = 
                DependencyProperty.RegisterReadOnly(
                        "CanIncreaseZoom", 
                        typeof(bool), 
                        typeof(FlowDocumentReader),
                        new FrameworkPropertyMetadata(BooleanBoxes.TrueBox)); 

        /// 
        /// 
        ///  
        public static readonly DependencyProperty CanIncreaseZoomProperty = CanIncreaseZoomPropertyKey.DependencyProperty;
 
        ///  
        /// 
        ///  
        private static readonly DependencyPropertyKey CanDecreaseZoomPropertyKey =
                DependencyProperty.RegisterReadOnly(
                        "CanDecreaseZoom",
                        typeof(bool), 
                        typeof(FlowDocumentReader),
                        new FrameworkPropertyMetadata(BooleanBoxes.TrueBox)); 
 
        /// 
        ///  
        /// 
        public static readonly DependencyProperty CanDecreaseZoomProperty = CanDecreaseZoomPropertyKey.DependencyProperty;

        ///  
        /// 
        ///  
        public static readonly DependencyProperty SelectionBrushProperty = 
            TextBoxBase.SelectionBrushProperty.AddOwner(typeof(FlowDocumentReader));
 
        /// 
        /// 
        /// 
        public static readonly DependencyProperty SelectionOpacityProperty = 
            TextBoxBase.SelectionOpacityProperty.AddOwner(typeof(FlowDocumentReader));
 
        #endregion Public Dynamic Properties 

        #endregion Public Properties 

        //-------------------------------------------------------------------
        //
        //  Public Commands 
        //
        //-------------------------------------------------------------------- 
 
        #region Public Commands
 
        /// 
        /// Switch ViewingMode command
        /// 
        public static readonly RoutedUICommand SwitchViewingModeCommand = new RoutedUICommand(SR.Get(SRID.SwitchViewingMode), "SwitchViewingMode", typeof(FlowDocumentReader), null); 

        #endregion 
 
        //-------------------------------------------------------------------
        // 
        //  Protected Methods
        //
        //-------------------------------------------------------------------
 
        #region Protected Methods
 
        ///  
        /// Called when print has been completed.
        ///  
        protected virtual void OnPrintCompleted()
        {
            if (_printInProgress)
            { 
                _printInProgress = false;
                // Since _printInProgress value is used to determine CanExecute state, we must invalidate that state. 
                CommandManager.InvalidateRequerySuggested(); 
            }
        } 

        /// 
        /// 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 (CurrentViewer != null)
            {
                CurrentViewer.Print();
            } 
        }
 
        ///  
        /// Handler for the CancelPrint command.
        ///  
        protected virtual void OnCancelPrintCommand()
        {
            if (CurrentViewer != null)
            { 
                CurrentViewer.CancelPrint();
            } 
        } 

        ///  
        /// Handler for the IncreaseZoom command.
        /// 
        protected virtual void OnIncreaseZoomCommand()
        { 
            // If can zoom in, increase zoom by the zoom increment value.
            if (CanIncreaseZoom) 
            { 
                SetCurrentValueInternal(ZoomProperty, 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) 
            {
                SetCurrentValueInternal(ZoomProperty, Math.Max(Zoom - ZoomIncrement, MinZoom));
            }
        } 

        ///  
        /// Handler for the SwitchViewingMode command. 
        /// 
        /// Viewing mode. 
        protected virtual void OnSwitchViewingModeCommand(FlowDocumentReaderViewingMode viewingMode)
        {
            SwitchViewingModeCore(viewingMode);
        } 

        ///  
        /// Called when IsInitialized is set to true. 
        /// 
        /// Event arguments 
        protected override void OnInitialized(EventArgs e)
        {
            base.OnInitialized(e);
 
            // Defer the Is*ViewEnabled & ViewingMode conflict exception.
            // Otherwise  won't work. 
            if (IsInitialized && !CanSwitchToViewingMode(ViewingMode)) 
            {
                throw new ArgumentException(SR.Get(SRID.FlowDocumentReaderViewingModeEnabledConflict)); 
            }
        }

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

        /// 
        /// An event reporting that the IsKeyboardFocusWithin property changed. 
        /// 
        protected override void OnIsKeyboardFocusWithinChanged(DependencyPropertyChangedEventArgs e) 
        { 
            base.OnIsKeyboardFocusWithinChanged(e);
 
            // In order to enable selection rendering and other similar services, the embedded viewer
            // needs to get focus, when any part of the control gets focused.
            // But if the focus is within the Document, do not change it. Otherwise it
            // will interfere with input handling inside the Document. 
            if (IsKeyboardFocusWithin && CurrentViewer != null)
            { 
                bool isFocusWithinDocument = IsFocusWithinDocument(); 
                if (!isFocusWithinDocument)
                { 
                    ((FrameworkElement)CurrentViewer).Focus();
                }
            }
        } 

        ///  
        /// 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);
            } 
        }

        #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)
        { 
            // Do not add intermediate ContentElements to the route, 
            // because they were added by embedded viewer.
            return BuildRouteCoreHelper(route, args, false); 
        }

        #endregion Internal Methods
 
        //--------------------------------------------------------------------
        // 
        //  Private Methods 
        //
        //------------------------------------------------------------------- 

        #region Private Methods

        ///  
        /// Handler for the SwitchViewingMode command.
        ///  
        /// Viewing mode. 
        protected virtual void SwitchViewingModeCore(FlowDocumentReaderViewingMode viewingMode)
        { 
            ITextSelection textSelection = null;
            ContentPosition contentPosition = null;
            IFlowDocumentViewer viewer;
            FrameworkElement feViewer; 
            bool isKeyboardFocusWithin;
            DependencyObject focusedElement = null; 
 
            if (_contentHost != null)
            { 
                // Remember the current keyboard focus state.
                isKeyboardFocusWithin = IsKeyboardFocusWithin;

                // Detach old viewer 
                viewer = _contentHost.Child as IFlowDocumentViewer;
                if (viewer != null) 
                { 
                    // Remember focused element, if the focus is within the Document.
                    // After switching to a different viewer, this focus needs to be restored. 
                    if (isKeyboardFocusWithin)
                    {
                        bool isFocusWithinDocument = IsFocusWithinDocument();
                        if (isFocusWithinDocument) 
                        {
                            focusedElement = Keyboard.FocusedElement as DependencyObject; 
                        } 
                    }
 
                    // Retrieve the current viewing state from the old viewer.
                    textSelection = viewer.TextSelection;
                    contentPosition = viewer.ContentPosition;
 
                    // Detach old viewer
                    DetachViewer(viewer); 
                } 

                viewer = GetViewerFromMode(viewingMode); 
                feViewer = (FrameworkElement)viewer;
                if (viewer != null)
                {
                    // Attach new viewer 
                    _contentHost.Child = feViewer;
                    AttachViewer(viewer); 
 
                    // Restore viewing state.
                    viewer.TextSelection = textSelection; 
                    viewer.ContentPosition = contentPosition;

                    // Bring the focus to previously focused element within the document
                    // or to the current viewer. 
                    if (isKeyboardFocusWithin)
                    { 
                        if (focusedElement is UIElement) 
                        {
                            ((UIElement)focusedElement).Focus(); 
                        }
                        else if (focusedElement is ContentElement)
                        {
                            ((ContentElement)focusedElement).Focus(); 
                        }
                        else 
                        { 
                            feViewer.Focus();
                        } 
                    }
                }

                // Viewer changes invalidates following properties: 
                //      - PageCount
                //      - PageNumber 
                //      - CanGoToPreviousPage 
                //      - CanGoToNextPage
                UpdateReadOnlyProperties(true, true); 
            }
        }

        ///  
        /// Determines whether focus is within Document.
        ///  
        private bool IsFocusWithinDocument() 
        {
            DependencyObject focusedElement = Keyboard.FocusedElement as DependencyObject; 
            while (focusedElement != null && focusedElement != Document)
            {
                // Skip elements in the control's template (if such exists) and
                // walk up logical tree to find if the focused element is within 
                // the document.
                FrameworkElement fe = focusedElement as FrameworkElement; 
                if (fe != null && fe.TemplatedParent != null) 
                {
                    focusedElement = fe.TemplatedParent; 
                }
                else
                {
                    focusedElement = LogicalTreeHelper.GetParent(focusedElement); 
                }
            } 
            return (focusedElement != null); 
        }
 
        /// 
        /// The Document has changed and needs to be updated.
        /// 
        private void DocumentChanged(FlowDocument oldDocument, FlowDocument newDocument) 
        {
            // Cleanup state associated with the old document. 
            if (oldDocument != null) 
            {
                // If Document was added to logical tree before, remove it. 
                if (_documentAsLogicalChild)
                {
                    RemoveLogicalChild(oldDocument);
                } 
            }
 
            // If FlowDocumentReader was created through style, then do not modify 
            // the logical tree. Instead, set "core parent" for the Document.
            if (TemplatedParent != null && 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)
            { 
                // If Document should be part of DocumentViewer's logical tree, add it.
                if (_documentAsLogicalChild) 
                { 
                    AddLogicalChild(newDocument);
                } 
            }

            // Attach document to the current viewer.
            if (CurrentViewer != null) 
            {
                CurrentViewer.SetDocument(newDocument); 
            } 

            // Document invalidation invalidates following properties: 
            //      - PageCount
            //      - PageNumber
            //      - CanGoToPreviousPage
            //      - CanGoToNextPage 
            UpdateReadOnlyProperties(true, true);
 
            // 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.
            FlowDocumentReaderAutomationPeer peer = UIElementAutomationPeer.FromElement(this) as FlowDocumentReaderAutomationPeer; 
            if (peer != null)
            {
                peer.InvalidatePeer();
            } 
        }
 
        ///  
        /// Detach embedded viewer form the reader control.
        ///  
        private void DetachViewer(IFlowDocumentViewer viewer)
        {
            Invariant.Assert(viewer != null && viewer is FrameworkElement);
            FrameworkElement feViewer = (FrameworkElement)viewer; 
            // Clear property bindings.
            BindingOperations.ClearBinding(feViewer, ZoomProperty); 
            BindingOperations.ClearBinding(feViewer, MaxZoomProperty); 
            BindingOperations.ClearBinding(feViewer, MinZoomProperty);
            BindingOperations.ClearBinding(feViewer, ZoomIncrementProperty); 
            // Unregister event handlers.
            viewer.PageCountChanged -= new EventHandler(OnPageCountChanged);
            viewer.PageNumberChanged -= new EventHandler(OnPageNumberChanged);
            viewer.PrintStarted -= new EventHandler(OnViewerPrintStarted); 
            viewer.PrintCompleted -= new EventHandler(OnViewerPrintCompleted);
            // Clear TemplatedParent 
            //feViewer._templatedParent = null; 
            // Detach document
            viewer.SetDocument(null); 
        }

        /// 
        /// Attach embedded viewer to the reader control. 
        /// 
        private void AttachViewer(IFlowDocumentViewer viewer) 
        { 
            Invariant.Assert(viewer != null && viewer is FrameworkElement);
            FrameworkElement feViewer = (FrameworkElement)viewer; 
            // Set document
            viewer.SetDocument(Document);
            // Set TemplatedParent
            //feViewer._templatedParent = TemplatedParent; 
            // Register event handlers.
            viewer.PageCountChanged += new EventHandler(OnPageCountChanged); 
            viewer.PageNumberChanged += new EventHandler(OnPageNumberChanged); 
            viewer.PrintStarted += new EventHandler(OnViewerPrintStarted);
            viewer.PrintCompleted += new EventHandler(OnViewerPrintCompleted); 
            // Create property bindings.
            CreateTwoWayBinding(feViewer, ZoomProperty, "Zoom");
            CreateTwoWayBinding(feViewer, MaxZoomProperty, "MaxZoom");
            CreateTwoWayBinding(feViewer, MinZoomProperty, "MinZoom"); 
            CreateTwoWayBinding(feViewer, ZoomIncrementProperty, "ZoomIncrement");
        } 
 
        /// 
        /// 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); 
        }
 
        /// 
        /// Determines whether can switch to specified ViewingMode or not.
        /// 
        private bool CanSwitchToViewingMode(FlowDocumentReaderViewingMode mode) 
        {
            bool canSwitch = false; 
            switch (mode) 
            {
                case FlowDocumentReaderViewingMode.Page: 
                    canSwitch = IsPageViewEnabled;
                    break;
                case FlowDocumentReaderViewingMode.TwoPage:
                    canSwitch = IsTwoPageViewEnabled; 
                    break;
                case FlowDocumentReaderViewingMode.Scroll: 
                    canSwitch = IsScrollViewEnabled; 
                    break;
            } 
            return canSwitch;
        }

        ///  
        /// Retrieves viewer form specified ViewingMode.
        ///  
        private IFlowDocumentViewer GetViewerFromMode(FlowDocumentReaderViewingMode mode) 
        {
            IFlowDocumentViewer viewer = null; 
            switch (mode)
            {
                case FlowDocumentReaderViewingMode.Page:
                    if (_pageViewer == null) 
                    {
                        _pageViewer = new ReaderPageViewer(); 
                        _pageViewer.SetResourceReference(StyleProperty, PageViewStyleKey); 
                        _pageViewer.Name = "PageViewer";
                        CommandManager.AddPreviewCanExecuteHandler(_pageViewer, new CanExecuteRoutedEventHandler(PreviewCanExecuteRoutedEventHandler)); 
                    }
                    viewer = _pageViewer;
                    break;
                case FlowDocumentReaderViewingMode.TwoPage: 
                    if (_twoPageViewer == null)
                    { 
                        _twoPageViewer = new ReaderTwoPageViewer(); 
                        _twoPageViewer.SetResourceReference(StyleProperty, TwoPageViewStyleKey);
                        _twoPageViewer.Name = "TwoPageViewer"; 
                        CommandManager.AddPreviewCanExecuteHandler(_twoPageViewer, new CanExecuteRoutedEventHandler(PreviewCanExecuteRoutedEventHandler));
                    }
                    viewer = _twoPageViewer;
                    break; 
                case FlowDocumentReaderViewingMode.Scroll:
                    if (_scrollViewer == null) 
                    { 
                        _scrollViewer = new ReaderScrollViewer();
                        _scrollViewer.SetResourceReference(StyleProperty, ScrollViewStyleKey); 
                        _scrollViewer.Name = "ScrollViewer";
                        CommandManager.AddPreviewCanExecuteHandler(_scrollViewer, new CanExecuteRoutedEventHandler(PreviewCanExecuteRoutedEventHandler));
                    }
                    viewer = _scrollViewer; 
                    break;
            } 
            return viewer; 
        }
 
        /// 
        /// Update values for readonly properties.
        /// 
        /// Whether PageCount has been changed. 
        /// Whether PageNumber has been changed.
        private void UpdateReadOnlyProperties(bool pageCountChanged, bool pageNumberChanged) 
        { 
            if (pageCountChanged)
            { 
                SetValue(PageCountPropertyKey, (CurrentViewer != null) ? CurrentViewer.PageCount : 0);
            }

            if (pageNumberChanged) 
            {
                SetValue(PageNumberPropertyKey, (CurrentViewer != null) ? CurrentViewer.PageNumber : 0); 
                SetValue(CanGoToPreviousPagePropertyKey, (CurrentViewer != null) ? CurrentViewer.CanGoToPreviousPage : false); 
            }
 
            if (pageCountChanged || pageNumberChanged)
            {
                SetValue(CanGoToNextPagePropertyKey, (CurrentViewer != null) ? CurrentViewer.CanGoToNextPage : false);
            } 
        }
 
        ///  
        /// Event handler for IFlowDocumentViewer.PageCountChanged.
        ///  
        private void OnPageCountChanged(object sender, EventArgs e)
        {
            Invariant.Assert(CurrentViewer != null && sender == CurrentViewer);
            UpdateReadOnlyProperties(true, false); 
        }
 
        ///  
        /// Event handler for IFlowDocumentViewer.PageNumberChanged.
        ///  
        private void OnPageNumberChanged(object sender, EventArgs e)
        {
            Invariant.Assert(CurrentViewer != null && sender == CurrentViewer);
            UpdateReadOnlyProperties(false, true); 
        }
 
        ///  
        /// Event handler for IFlowDocumentViewer.PrintStarted.
        ///  
        private void OnViewerPrintStarted(object sender, EventArgs e)
        {
            Invariant.Assert(CurrentViewer != null && sender == CurrentViewer);
            _printInProgress = true; 
            // Since _printInProgress value is used to determine CanExecute state, we must invalidate that state.
            CommandManager.InvalidateRequerySuggested(); 
        } 

        ///  
        /// Event handler for IFlowDocumentViewer.PrintCompleted.
        /// 
        private void OnViewerPrintCompleted(object sender, EventArgs e)
        { 
            Invariant.Assert(CurrentViewer != null && sender == CurrentViewer);
            OnPrintCompleted(); 
        } 

        ///  
        /// Convert object value to FlowDocumentReaderViewingMode.
        /// 
        private bool ConvertToViewingMode(object value, out FlowDocumentReaderViewingMode mode)
        { 
            bool success;
            if (value is FlowDocumentReaderViewingMode) 
            { 
                mode = (FlowDocumentReaderViewingMode)value;
                success = true; 
            }
            else if (value is String)
            {
                String str = (String)value; 
                if (str == FlowDocumentReaderViewingMode.Page.ToString())
                { 
                    mode = FlowDocumentReaderViewingMode.Page; 
                    success = true;
                } 
                else if (str == FlowDocumentReaderViewingMode.TwoPage.ToString())
                {
                    mode = FlowDocumentReaderViewingMode.TwoPage;
                    success = true; 
                }
                else if (str == FlowDocumentReaderViewingMode.Scroll.ToString()) 
                { 
                    mode = FlowDocumentReaderViewingMode.Scroll;
                    success = true; 
                }
                else
                {
                    mode = FlowDocumentReaderViewingMode.Page; 
                    success = false;
                } 
            } 
            else
            { 
                mode = FlowDocumentReaderViewingMode.Page;
                success = false;
            }
            return success; 
        }
 
        ///  
        /// Enables/disables the FindToolBar.
        ///  
        /// Whether to enable/disable FindToolBar.
        private void ToggleFindToolBar(bool enable)
        {
            Invariant.Assert(enable == (FindToolBar == null)); 

            // Command event for toggle button is only fired in OnClick - Therefore we just need to change the state 
            if(_findButton != null && _findButton.IsChecked.HasValue && _findButton.IsChecked.Value != enable) 
            {
                _findButton.IsChecked = enable; 
            }
            DocumentViewerHelper.ToggleFindToolBar(_findToolBarHost, new EventHandler(OnFindInvoked), enable);
        }
 
        #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 CanExecuteRoutedEventHandler
            canExecuteHandler = new CanExecuteRoutedEventHandler(CanExecuteRoutedEventHandler); 

            // Command: SwitchViewingMode
            CommandHelpers.RegisterCommandHandler(typeof(FlowDocumentReader), FlowDocumentReader.SwitchViewingModeCommand,
                executedHandler, canExecuteHandler, SRID.KeySwitchViewingMode, SRID.KeySwitchViewingModeDisplayString); 

            // Command: ApplicationCommands.Find 
            CommandHelpers.RegisterCommandHandler(typeof(FlowDocumentReader), ApplicationCommands.Find, 
                executedHandler, canExecuteHandler);
 
            // Command: ApplicationCommands.Print
            CommandHelpers.RegisterCommandHandler(typeof(FlowDocumentReader), ApplicationCommands.Print,
                executedHandler, canExecuteHandler);
 
            // Command: ApplicationCommands.CancelPrint
            CommandHelpers.RegisterCommandHandler(typeof(FlowDocumentReader), ApplicationCommands.CancelPrint, 
                executedHandler, canExecuteHandler); 

            // Command: NavigationCommands.PreviousPage 
            CommandHelpers.RegisterCommandHandler(typeof(FlowDocumentReader), NavigationCommands.PreviousPage,
                executedHandler, canExecuteHandler);

            // Command: NavigationCommands.NextPage 
            CommandHelpers.RegisterCommandHandler(typeof(FlowDocumentReader), NavigationCommands.NextPage,
                executedHandler, canExecuteHandler); 
 
            // Command: NavigationCommands.FirstPage
            CommandHelpers.RegisterCommandHandler(typeof(FlowDocumentReader), NavigationCommands.FirstPage, 
                executedHandler, canExecuteHandler);

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

            // Command: NavigationCommands.DecreaseZoom
            CommandHelpers.RegisterCommandHandler(typeof(FlowDocumentReader), NavigationCommands.DecreaseZoom,
                executedHandler, canExecuteHandler, new KeyGesture(Key.OemMinus, ModifierKeys.Control)); 
        }
 
        ///  
        /// Central handler for CanExecute events fired by Commands directed at FlowDocumentReader.
        ///  
        /// The target of this Command, expected to be FlowDocumentReader
        /// The event arguments for this event.
        private static void CanExecuteRoutedEventHandler(object target, CanExecuteRoutedEventArgs args)
        { 
            FlowDocumentReader viewer = target as FlowDocumentReader;
            Invariant.Assert(viewer != null, "Target of CanExecuteRoutedEventHandler must be FlowDocumentReader."); 
            Invariant.Assert(args != null, "args cannot be null."); 

            // FlowDocumentReader 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 and printing is enabled. 
            // d) CancelPrint command is enabled only during printing.
            // e) SwitchViewingMode command is enabled if the viewing mode is enabled, or 
            //    the command has no parameters (will switch to the next available view). 
            if (!viewer._printInProgress)
            { 
                if (args.Command == FlowDocumentReader.SwitchViewingModeCommand)
                {
                    // This command is enabled if the viewing mode is enabled, or the command
                    // has no parameters (will switch to the next available view). 
                    FlowDocumentReaderViewingMode mode;
                    if (viewer.ConvertToViewingMode(args.Parameter, out mode)) 
                    { 
                        args.CanExecute = viewer.CanSwitchToViewingMode(mode);
                    } 
                    else
                    {
                        args.CanExecute = (args.Parameter == null);
                    } 
                }
                else if (args.Command == ApplicationCommands.Find) 
                { 
                    args.CanExecute = viewer.CanShowFindToolBar;
                } 
                else if (args.Command == ApplicationCommands.Print)
                {
                    args.CanExecute = (viewer.Document != null) && viewer.IsPrintEnabled;
                } 
                else if (args.Command == ApplicationCommands.CancelPrint)
                { 
                    args.CanExecute = false; 
                }
                else 
                {
                    args.CanExecute = true;
                }
            } 
            else
            { 
                args.CanExecute = (args.Command == ApplicationCommands.CancelPrint); 
            }
        } 

        /// 
        /// Central handler for all ExecuteEvents fired by Commands directed at FlowDocumentReader.
        ///  
        /// The target of this Command, expected to be FlowDocumentReader.
        /// The event arguments associated with this event. 
        private static void ExecutedRoutedEventHandler(object target, ExecutedRoutedEventArgs args) 
        {
            FlowDocumentReader viewer = target as FlowDocumentReader; 
            Invariant.Assert(viewer != null, "Target of ExecutedRoutedEventHandler must be FlowDocumentReader.");
            Invariant.Assert(args != null, "args cannot be null.");

            if (args.Command == FlowDocumentReader.SwitchViewingModeCommand) 
            {
                viewer.TrySwitchViewingMode(args.Parameter); 
            } 
            else 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 == NavigationCommands.PreviousPage)
            {
                viewer.OnPreviousPageCommand();
            } 
            else if (args.Command == NavigationCommands.NextPage)
            { 
                viewer.OnNextPageCommand(); 
            }
            else if (args.Command == NavigationCommands.FirstPage) 
            {
                viewer.OnFirstPageCommand();
            }
            else if (args.Command == NavigationCommands.LastPage) 
            {
                viewer.OnLastPageCommand(); 
            } 
            else
            { 
                Invariant.Assert(false, "Command not handled in ExecutedRoutedEventHandler.");
            }
        }
 
        /// 
        /// Changes the current viewing mode. 
        ///  
        private void TrySwitchViewingMode(object parameter)
        { 
            FlowDocumentReaderViewingMode mode;
            // Convert command parameter to viewing mode value.
            // If parameter is not provided, the viewing mode is the next one available.
            // If parameter cannot be converted, the command is ignored. 
            if (!ConvertToViewingMode(parameter, out mode))
            { 
                if (parameter == null) 
                {
                    mode = (FlowDocumentReaderViewingMode)((((int)ViewingMode) + 1) % 3); 
                }
                else
                {
                    return; 
                }
            } 
            // If the current ViewingMode is disabled, go to next one. 
            while (!CanSwitchToViewingMode(mode))
            { 
                mode = (FlowDocumentReaderViewingMode)((((int)mode) + 1) % 3);
            }
            // Set new ViewingMode value.
            SetCurrentValueInternal(ViewingModeProperty, mode); 
        }
 
        ///  
        /// Handler for the PreviousPage command.
        ///  
        private void OnPreviousPageCommand()
        {
            if (CurrentViewer != null)
            { 
                CurrentViewer.PreviousPage();
            } 
        } 

        ///  
        /// Handler for the NextPage command.
        /// 
        private void OnNextPageCommand()
        { 
            if (CurrentViewer != null)
            { 
                CurrentViewer.NextPage(); 
            }
        } 

        /// 
        /// Handler for the FirstPage command.
        ///  
        private void OnFirstPageCommand()
        { 
            if (CurrentViewer != null) 
            {
                CurrentViewer.FirstPage(); 
            }
        }

        ///  
        /// Handler for the LastPage command.
        ///  
        private void OnLastPageCommand() 
        {
            if (CurrentViewer != null) 
            {
                CurrentViewer.LastPage();
            }
        } 

        ///  
        /// 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;
            TextEditor textEditor = TextEditor; 
            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. 
                if (CurrentViewer != null && CurrentViewer is UIElement)
                { 
                    ((UIElement)CurrentViewer).Focus(); 
                }
 
                findResult = DocumentViewerHelper.Find(findToolBar, textEditor, textEditor.TextView, textEditor.TextView);

                // If we found something, bring it into the view. Otherwise alert the user.
                if ((findResult != null) && (!findResult.IsEmpty)) 
                {
                    // Bring find result into view. 
                    if (CurrentViewer != null) 
                    {
                        CurrentViewer.ShowFindResult(findResult); 
                    }
                }
                else
                { 
                    DocumentViewerHelper.ShowFindUnsuccessfulMessage(findToolBar);
                } 
            } 
        }
 
        /// 
        /// Disable commands on IFlowDocumentViewer when this funcionality is explicitly
        /// disabled on the reader control.
        ///  
        private void PreviewCanExecuteRoutedEventHandler(object target, CanExecuteRoutedEventArgs args)
        { 
            if (args.Command == ApplicationCommands.Find) 
            {
                // Find is handled by FlowDocumentReader. 
                args.CanExecute = false;
                args.Handled = true;
            }
            else if (args.Command == ApplicationCommands.Print) 
            {
                args.CanExecute = IsPrintEnabled; 
                args.Handled = !IsPrintEnabled; 
            }
        } 

        /// 
        /// Called when a key event occurs.
        ///  
        private static void KeyDownHandler(object sender, KeyEventArgs e)
        { 
            DocumentViewerHelper.KeyDownHelper(e, ((FlowDocumentReader)sender)._findToolBarHost); 
        }
 
        #endregion Commands

        #region Static Methods
 
        /// 
        /// ViewingMode has been changed. 
        ///  
        private static void ViewingModeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        { 
            Invariant.Assert(d != null && d is FlowDocumentReader);
            FlowDocumentReader viewer = (FlowDocumentReader)d;
            if (viewer.CanSwitchToViewingMode((FlowDocumentReaderViewingMode)e.NewValue))
            { 
                viewer.SwitchViewingModeCore((FlowDocumentReaderViewingMode)e.NewValue);
            } 
            else if (viewer.IsInitialized) 
            {
                throw new ArgumentException(SR.Get(SRID.FlowDocumentReaderViewingModeEnabledConflict)); 
            }

            // Fire automation events if automation is active.
            FlowDocumentReaderAutomationPeer peer = UIElementAutomationPeer.FromElement(viewer) as FlowDocumentReaderAutomationPeer; 
            if (peer != null)
            { 
                peer.RaiseCurrentViewChangedEvent((FlowDocumentReaderViewingMode)e.NewValue, (FlowDocumentReaderViewingMode)e.OldValue); 
            }
        } 

        /// 
        /// Validate value of ViewingMode property.
        ///  
        private static bool IsValidViewingMode(object o)
        { 
            FlowDocumentReaderViewingMode value = (FlowDocumentReaderViewingMode)o; 
            return (value == FlowDocumentReaderViewingMode.Page ||
                    value == FlowDocumentReaderViewingMode.TwoPage || 
                    value == FlowDocumentReaderViewingMode.Scroll);
        }

        ///  
        /// One of viewing modes has been enabled/disabled.
        ///  
        private static void ViewingModeEnabledChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
        {
            Invariant.Assert(d != null && d is FlowDocumentReader); 
            FlowDocumentReader viewer = (FlowDocumentReader)d;

            // Cannot disable all viewing modes.
            if (!viewer.IsPageViewEnabled && 
                !viewer.IsTwoPageViewEnabled &&
                !viewer.IsScrollViewEnabled) 
            { 
                throw new ArgumentException(SR.Get(SRID.FlowDocumentReaderCannotDisableAllViewingModes));
            } 

            // Cannot disable the current viewing mode.
            if (viewer.IsInitialized && !viewer.CanSwitchToViewingMode(viewer.ViewingMode))
            { 
                throw new ArgumentException(SR.Get(SRID.FlowDocumentReaderViewingModeEnabledConflict));
            } 
 
            // Fire automation events if automation is active.
            FlowDocumentReaderAutomationPeer peer = UIElementAutomationPeer.FromElement(viewer) as FlowDocumentReaderAutomationPeer; 
            if (peer != null)
            {
                peer.RaiseSupportedViewsChangedEvent(e);
            } 
        }
 
        ///  
        /// IsFindEnabled value has changed.
        ///  
        private static void IsFindEnabledChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            Invariant.Assert(d != null && d is FlowDocumentReader);
            FlowDocumentReader viewer = (FlowDocumentReader)d; 

            // Update the toolbar with our current state. 
            if (!viewer.CanShowFindToolBar) 
            {
                if (viewer.FindToolBar != null) 
                {
                    viewer.ToggleFindToolBar(false);
                }
            } 

            // Since IsFindEnabled state is used to determine CanExecute state, we must invalidate that state. 
            CommandManager.InvalidateRequerySuggested(); 
        }
 
        /// 
        /// IsPrintEnabled value has changed.
        /// 
        private static void IsPrintEnabledChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
        {
            Invariant.Assert(d != null && d is FlowDocumentReader); 
            FlowDocumentReader viewer = (FlowDocumentReader)d; 

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

        ///  
        /// The Document has changed and needs to be updated.
        ///  
        private static void DocumentChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
        {
            Invariant.Assert(d != null && d is FlowDocumentReader); 
            FlowDocumentReader viewer = (FlowDocumentReader)d;
            viewer.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 FlowDocumentReader); 
            FlowDocumentReader viewer = (FlowDocumentReader)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)));
            }
        }
 
        /// 
        /// Coerce Zoom with Max/MinZoom, MinZoom works as the baseline. 
        ///  
        private static object CoerceZoom(DependencyObject d, object value)
        { 
            Invariant.Assert(d != null && d is FlowDocumentReader);
            FlowDocumentReader viewer = (FlowDocumentReader)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 FlowDocumentReader);
            FlowDocumentReader viewer = (FlowDocumentReader)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 FlowDocumentReader);
            FlowDocumentReader viewer = (FlowDocumentReader)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 FlowDocumentReader);
            FlowDocumentReader viewer = (FlowDocumentReader)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));
        } 

        ///  
        /// PropertyChanged callback for a property that affects the selection or caret rendering. 
        /// 
        private static void UpdateCaretElement(DependencyObject d, DependencyPropertyChangedEventArgs e) 
        {
            FlowDocumentReader reader = (FlowDocumentReader)d;

            if (reader.Selection != null) 
            {
                CaretElement caretElement = reader.Selection.CaretElement; 
                if (caretElement != null) 
                {
                    caretElement.InvalidateVisual(); 
                }
            }
        }
 
        #endregion Static Methods
 
        #endregion Private Methods 

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

        #region Private Properties 
 
        /// 
        /// Whether FindToolBar can be enabled. 
        /// 
        private bool CanShowFindToolBar
        {
            get { return ((_findToolBarHost != null) && IsFindEnabled && (Document != null)); } 
        }
 
        ///  
        /// Returns TextEditor, if availabe.
        ///  
        private TextEditor TextEditor
        {
            get
            { 
                TextEditor textEditor = null;
                IFlowDocumentViewer currentViewer = CurrentViewer; 
                if (currentViewer != null && currentViewer.TextSelection != null) 
                {
                    textEditor = currentViewer.TextSelection.TextEditor; 
                }
                return textEditor;
            }
        } 

        ///  
        /// Returns FindToolBar, if enabled. 
        /// 
        private FindToolBar FindToolBar 
        {
            get { return (_findToolBarHost != null) ? _findToolBarHost.Child as FindToolBar : null; }
        }
 
        /// 
        /// Returns the current content viewer. 
        ///  
        private IFlowDocumentViewer CurrentViewer
        { 
            get
            {
                if (_contentHost != null)
                { 
                    return (IFlowDocumentViewer)_contentHost.Child;
                } 
                return null; 
            }
        } 

        #endregion Private Properties

        //------------------------------------------------------------------- 
        //
        //  Private Fields 
        // 
        //-------------------------------------------------------------------
 
        #region Private Fields

        private Decorator _contentHost;                 // Host for content viewer
        private Decorator _findToolBarHost;             // Host for FindToolBar 
        private ToggleButton _findButton;               // Find toggle button
        private ReaderPageViewer _pageViewer;           // Viewer for Page viewing mode 
        private ReaderTwoPageViewer _twoPageViewer;     // Viewer for TwoPage viewing mode 
        private ReaderScrollViewer _scrollViewer;       // Viewer for Scroll viewing mode
        private bool _documentAsLogicalChild;           // Is Document part of logical tree 
        private bool _printInProgress;                  // Whether print is currently in progress.

        private const string _contentHostTemplateName = "PART_ContentHost";         // Name for ContentHost
        private const string _findToolBarHostTemplateName = "PART_FindToolBarHost"; // Name for the Find ToolBar host 
        private const string _findButtonTemplateName = "FindButton"; // Name for the Find Button
 
        #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.FlowDocumentReaderCanHaveOnlyOneChild)); 
            }
            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
 
        //-------------------------------------------------------------------- 
        //
        //  IJournalState Members 
        //
        //--------------------------------------------------------------------

        #region IJournalState Members 

        [Serializable] 
        private class JournalState : CustomJournalStateInternal 
        {
            public JournalState(int contentPosition, LogicalDirection contentPositionDirection, double zoom, FlowDocumentReaderViewingMode viewingMode) 
            {
                ContentPosition = contentPosition;
                ContentPositionDirection = contentPositionDirection;
                Zoom = zoom; 
                ViewingMode = viewingMode;
            } 
            public int ContentPosition; 
            public LogicalDirection ContentPositionDirection;
            public double Zoom; 
            public FlowDocumentReaderViewingMode ViewingMode;
        }

        ///  
        /// 
        ///  
        CustomJournalStateInternal IJournalState.GetJournalState(JournalReason journalReason) 
        {
            int cp = -1; 
            LogicalDirection cpDirection = LogicalDirection.Forward;
            IFlowDocumentViewer viewer = CurrentViewer;
            if (viewer != null)
            { 
                TextPointer contentPosition = viewer.ContentPosition as TextPointer;
                if (contentPosition != null) 
                { 
                    cp = contentPosition.Offset;
                    cpDirection = contentPosition.LogicalDirection; 
                }
            }
            return new JournalState(cp, cpDirection, Zoom, ViewingMode);
        } 

        ///  
        ///  
        /// 
        void IJournalState.RestoreJournalState(CustomJournalStateInternal state) 
        {
            JournalState viewerState = state as JournalState;
            if (state != null)
            { 
                SetCurrentValueInternal(ZoomProperty, viewerState.Zoom);
                SetCurrentValueInternal(ViewingModeProperty, viewerState.ViewingMode); 
                if (viewerState.ContentPosition != -1) 
                {
                    IFlowDocumentViewer viewer = CurrentViewer; 
                    FlowDocument document = Document;
                    if (viewer != null && document != null)
                    {
                        TextContainer textContainer = document.StructuralCache.TextContainer; 
                        if (viewerState.ContentPosition <= textContainer.SymbolCount)
                        { 
                            TextPointer contentPosition = textContainer.CreatePointerAtOffset(viewerState.ContentPosition, viewerState.ContentPositionDirection); 
                            viewer.ContentPosition = 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 

        //-------------------------------------------------------------------
        //
        //  Style Keys 
        //
        //------------------------------------------------------------------- 
 
        #region Style Keys
 
        /// 
        /// Key used to mark the style for use by the PageView
        /// 
        private static ResourceKey PageViewStyleKey 
        {
            get 
            { 
                if (_pageViewStyleKey == null)
                { 
                    _pageViewStyleKey = new ComponentResourceKey(typeof(PresentationUIStyleResources), "PUIPageViewStyleKey");
                }

                return _pageViewStyleKey; 
            }
        } 
 
        /// 
        /// Key used to mark the style for use by the TwoPageView 
        /// 
        private static ResourceKey TwoPageViewStyleKey
        {
            get 
            {
                if (_twoPageViewStyleKey == null) 
                { 
                    _twoPageViewStyleKey = new ComponentResourceKey(typeof(PresentationUIStyleResources), "PUITwoPageViewStyleKey");
                } 

                return _twoPageViewStyleKey;
            }
        } 

        ///  
        /// Key used to mark the style for use by the ScrollView 
        /// 
        private static ResourceKey ScrollViewStyleKey 
        {
            get
            {
                if (_scrollViewStyleKey == null) 
                {
                    _scrollViewStyleKey = new ComponentResourceKey(typeof(PresentationUIStyleResources), "PUIScrollViewStyleKey"); 
                } 

                return _scrollViewStyleKey; 
            }
        }

 
        private static ComponentResourceKey _pageViewStyleKey;
        private static ComponentResourceKey _twoPageViewStyleKey; 
        private static ComponentResourceKey _scrollViewStyleKey; 

        #endregion 
    }

    /// 
    /// 

    public enum FlowDocumentReaderViewingMode 
    { 
        /// 
        /// 

        Page,

        ///  
        ///
 
        TwoPage, 

        ///  
        ///

        Scroll
    } 
}

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

using System;                               // Object 
using System.Collections;                   // IEnumerator 
using System.Collections.ObjectModel;       // ReadOnlyCollection
using System.Security;                      // SecurityCritical 
using System.Windows.Automation.Peers;      // AutomationPeer
using System.Windows.Data;                  // BindingOperations
using System.Windows.Controls.Primitives;   // PlacementMode
using System.Windows.Documents;             // FlowDocument 
using System.Windows.Input;                 // KeyEventArgs
using System.Windows.Media;                 // ScaleTransform, VisualTreeHelper 
using System.Windows.Markup;                // IAddChild 
using System.Windows.Threading;             // Dispatcher
using MS.Internal;                          // Invariant, DoubleUtil 
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 
{
    ///  
    /// FlowDocumentReader provides a full user experience for consuming text content.
    /// It will be used as the default viewer for loose XAML or containers that contain
    /// text content, and can be styled and re-used by developers for use within their applications.
    ///  
    [TemplatePart(Name = "PART_ContentHost", Type = typeof(Decorator))]
    [TemplatePart(Name = "PART_FindToolBarHost", Type = typeof(Decorator))] 
    [ContentProperty("Document")] 
    public class FlowDocumentReader : Control, IAddChild, IJournalState
    { 
        //-------------------------------------------------------------------
        //
        //  Constructors
        // 
        //-------------------------------------------------------------------
 
        #region Constructors 

        ///  
        /// Static Constructor
        /// 
        static FlowDocumentReader()
        { 
            DefaultStyleKeyProperty.OverrideMetadata(
                typeof(FlowDocumentReader), 
                new FrameworkPropertyMetadata(new ComponentResourceKey(typeof(PresentationUIStyleResources), "PUIFlowDocumentReader"))); 

            _dType = DependencyObjectType.FromSystemTypeInternal(typeof(FlowDocumentReader)); 

            TextBoxBase.SelectionBrushProperty.OverrideMetadata(typeof(FlowDocumentReader),
                new FrameworkPropertyMetadata(new PropertyChangedCallback(UpdateCaretElement)));
            TextBoxBase.SelectionOpacityProperty.OverrideMetadata(typeof(FlowDocumentReader), 
                new FrameworkPropertyMetadata(new PropertyChangedCallback(UpdateCaretElement)));
 
            CreateCommandBindings(); 

            EventManager.RegisterClassHandler(typeof(FlowDocumentReader), Keyboard.KeyDownEvent, new KeyEventHandler(KeyDownHandler), true); 
        }

        /// 
        /// Default Constructor 
        /// 
        public FlowDocumentReader() 
            : base() 
        {
        } 

        #endregion Constructors

        //-------------------------------------------------------------------- 
        //
        //  Public Methods 
        // 
        //-------------------------------------------------------------------
 
        #region Public Methods

        /// 
        /// Build Visual tree 
        /// 
        public override void OnApplyTemplate() 
        { 
            base.OnApplyTemplate();
 
            // Initialize ContentHost.
            // If old ContentHost is enabled, disable it first to ensure appropriate cleanup.
            if (CurrentViewer != null)
            { 
                DetachViewer(CurrentViewer);
                _contentHost.Child = null; 
            } 
            _contentHost = GetTemplateChild(_contentHostTemplateName) as Decorator;
            if (_contentHost != null) 
            {
                if (_contentHost.Child != null)
                {
                    throw new NotSupportedException(SR.Get(SRID.FlowDocumentReaderDecoratorMarkedAsContentHostMustHaveNoContent)); 
                }
 
                SwitchViewingModeCore(ViewingMode); 
            }
 
            // 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; 
            _findButton = GetTemplateChild(_findButtonTemplateName) as ToggleButton;
        } 

        /// 
        /// Whether the master page can be moved to the specified page.
        ///  
        /// Page number.
        public bool CanGoToPage(int pageNumber) 
        { 
            bool canGoToPage = false;
            if (CurrentViewer != null) 
            {
                canGoToPage = CurrentViewer.CanGoToPage(pageNumber);
            }
            return canGoToPage; 
        }
 
        ///  
        /// 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();
        } 

        /// 
        /// Switches the current viewing mode. This is analogous to the SwitchViewingModeCommand.
        ///  
        /// Viewing mode.
        public void SwitchViewingMode(FlowDocumentReaderViewingMode viewingMode) 
        { 
            OnSwitchViewingModeCommand(viewingMode);
        } 

        #endregion Public Methods

        //-------------------------------------------------------------------- 
        //
        //  Public Properties 
        // 
        //--------------------------------------------------------------------
 
        #region Public Properties

        /// 
        /// ViewingMode of FlowDocumentReader. 
        /// 
        public FlowDocumentReaderViewingMode ViewingMode 
        { 
            get { return (FlowDocumentReaderViewingMode)GetValue(ViewingModeProperty); }
            set { SetValue(ViewingModeProperty, value); } 
        }

        /// 
        /// Text Selection (readonly) 
        /// 
        public TextSelection Selection 
        { 
            get
            { 
                TextSelection result = null;
                IFlowDocumentViewer viewer;
                if (_contentHost != null)
                { 
                    viewer = _contentHost.Child as IFlowDocumentViewer;
                    if(viewer != null) 
                    { 
                        result = viewer.TextSelection as TextSelection;
                    } 
                }
                return result;
            }
        } 

        ///  
        /// Whether Page view can be enabled or not. 
        /// 
        public bool IsPageViewEnabled 
        {
            get { return (bool)GetValue(IsPageViewEnabledProperty); }
            set { SetValue(IsPageViewEnabledProperty, BooleanBoxes.Box(value)); }
        } 

        ///  
        /// Whether TwoPage view can be enabled or not. 
        /// 
        public bool IsTwoPageViewEnabled 
        {
            get { return (bool)GetValue(IsTwoPageViewEnabledProperty); }
            set { SetValue(IsTwoPageViewEnabledProperty, BooleanBoxes.Box(value)); }
        } 

        ///  
        /// Whether Scroll view can be enabled or not. 
        /// 
        public bool IsScrollViewEnabled 
        {
            get { return (bool)GetValue(IsScrollViewEnabledProperty); }
            set { SetValue(IsScrollViewEnabledProperty, BooleanBoxes.Box(value)); }
        } 

        ///  
        /// The number of pages currently available for viewing. This value 
        /// is updated as content is paginated, and will change dramatically
        /// when the content is resized, or edited. 
        /// 
        public int PageCount
        {
            get { return (int)GetValue(PageCountProperty); } 
        }
 
        ///  
        /// The one-based page number of the page being displayed. If there is no content,
        /// this value will be 0. 
        /// 
        public int PageNumber
        {
            get { return (int)GetValue(PageNumberProperty); } 
        }
 
        ///  
        /// Whether the viewer can move the master page to the previous page.
        ///  
        public bool CanGoToPreviousPage
        {
            get { return (bool)GetValue(CanGoToPreviousPageProperty); }
        } 

        ///  
        /// Whether the viewer can advance the master page to the next page. 
        /// 
        public bool CanGoToNextPage 
        {
            get { return (bool)GetValue(CanGoToNextPageProperty); }
        }
 
        /// 
        /// Is find function enabled or not 
        ///  
        public bool IsFindEnabled
        { 
            get { return (bool)GetValue(IsFindEnabledProperty); }
            set { SetValue(IsFindEnabledProperty, BooleanBoxes.Box(value)); }
        }
 
        /// 
        /// Is print function enabled or not 
        ///  
        public bool IsPrintEnabled
        { 
            get { return (bool)GetValue(IsPrintEnabledProperty); }
            set { SetValue(IsPrintEnabledProperty, BooleanBoxes.Box(value)); }
        }
 
        /// 
        /// A Property representing a content of this FlowDocumentScrollViewer. 
        ///  
        public FlowDocument Document
        { 
            get { return (FlowDocument)GetValue(DocumentProperty); }
            set { SetValue(DocumentProperty, value); }
        }
 
        /// 
        /// 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); }
        }

        ///  
        /// 
        ///  
        public Brush SelectionBrush 
        {
            get { return (Brush)GetValue(SelectionBrushProperty); } 
            set { SetValue(SelectionBrushProperty, value); }
        }

        ///  
        /// 
        ///  
        public double SelectionOpacity 
        {
            get { return (double)GetValue(SelectionOpacityProperty); } 
            set { SetValue(SelectionOpacityProperty, value); }
        }

        #region Public Dynamic Properties 

        ///  
        ///  
        /// 
        public static readonly DependencyProperty ViewingModeProperty = 
                DependencyProperty.Register(
                        "ViewingMode",
                        typeof(FlowDocumentReaderViewingMode),
                        typeof(FlowDocumentReader), 
                        new FrameworkPropertyMetadata(
                                FlowDocumentReaderViewingMode.Page, 
                                FrameworkPropertyMetadataOptions.AffectsMeasure, 
                                new PropertyChangedCallback(ViewingModeChanged)),
                        new ValidateValueCallback(IsValidViewingMode)); 

        /// 
        /// 
        ///  
        public static readonly DependencyProperty IsPageViewEnabledProperty =
                DependencyProperty.Register( 
                        "IsPageViewEnabled", 
                        typeof(bool),
                        typeof(FlowDocumentReader), 
                        new FrameworkPropertyMetadata(
                                BooleanBoxes.TrueBox,
                                new PropertyChangedCallback(ViewingModeEnabledChanged)));
 
        /// 
        ///  
        ///  
        public static readonly DependencyProperty IsTwoPageViewEnabledProperty =
                DependencyProperty.Register( 
                        "IsTwoPageViewEnabled",
                        typeof(bool),
                        typeof(FlowDocumentReader),
                        new FrameworkPropertyMetadata( 
                                BooleanBoxes.TrueBox,
                                new PropertyChangedCallback(ViewingModeEnabledChanged))); 
 
        /// 
        ///  
        /// 
        public static readonly DependencyProperty IsScrollViewEnabledProperty =
                DependencyProperty.Register(
                        "IsScrollViewEnabled", 
                        typeof(bool),
                        typeof(FlowDocumentReader), 
                        new FrameworkPropertyMetadata( 
                                BooleanBoxes.TrueBox,
                                new PropertyChangedCallback(ViewingModeEnabledChanged))); 

        /// 
        /// 
        ///  
        private static readonly DependencyPropertyKey PageCountPropertyKey =
                DependencyProperty.RegisterReadOnly( 
                        "PageCount", 
                        typeof(int),
                        typeof(FlowDocumentReader), 
                        new FrameworkPropertyMetadata(0));

        /// 
        ///  
        /// 
        public static readonly DependencyProperty PageCountProperty = PageCountPropertyKey.DependencyProperty; 
 
        /// 
        ///  
        /// 
        private static readonly DependencyPropertyKey PageNumberPropertyKey =
                DependencyProperty.RegisterReadOnly(
                        "PageNumber", 
                        typeof(int),
                        typeof(FlowDocumentReader), 
                        new FrameworkPropertyMetadata(0)); 

        ///  
        /// 
        /// 
        public static readonly DependencyProperty PageNumberProperty = PageNumberPropertyKey.DependencyProperty;
        ///  
        /// 
        ///  
        private static readonly DependencyPropertyKey CanGoToPreviousPagePropertyKey = 
                DependencyProperty.RegisterReadOnly(
                        "CanGoToPreviousPage", 
                        typeof(bool),
                        typeof(FlowDocumentReader),
                        new FrameworkPropertyMetadata(BooleanBoxes.FalseBox));
 
        /// 
        ///  
        ///  
        public static readonly DependencyProperty CanGoToPreviousPageProperty = CanGoToPreviousPagePropertyKey.DependencyProperty;
 
        /// 
        /// 
        /// 
        private static readonly DependencyPropertyKey CanGoToNextPagePropertyKey = 
                DependencyProperty.RegisterReadOnly(
                        "CanGoToNextPage", 
                        typeof(bool), 
                        typeof(FlowDocumentReader),
                        new FrameworkPropertyMetadata(BooleanBoxes.FalseBox)); 

        /// 
        /// 
        ///  
        public static readonly DependencyProperty CanGoToNextPageProperty = CanGoToNextPagePropertyKey.DependencyProperty;
 
        ///  
        /// 
        ///  
        public static readonly DependencyProperty IsFindEnabledProperty =
                DependencyProperty.Register(
                        "IsFindEnabled",
                        typeof(bool), 
                        typeof(FlowDocumentReader),
                        new FrameworkPropertyMetadata( 
                                BooleanBoxes.TrueBox, 
                                new PropertyChangedCallback(IsFindEnabledChanged)));
 
        /// 
        /// 
        /// 
        public static readonly DependencyProperty IsPrintEnabledProperty = 
                DependencyProperty.Register(
                        "IsPrintEnabled", 
                        typeof(bool), 
                        typeof(FlowDocumentReader),
                        new FrameworkPropertyMetadata( 
                                BooleanBoxes.TrueBox,
                                new PropertyChangedCallback(IsPrintEnabledChanged)));

        ///  
        /// 
        ///  
        public static readonly DependencyProperty DocumentProperty = 
                DependencyProperty.Register(
                        "Document", 
                        typeof(FlowDocument),
                        typeof(FlowDocumentReader),
                        new FrameworkPropertyMetadata(
                                null, 
                                new PropertyChangedCallback(DocumentChanged)));
 
        ///  
        /// 
        ///  
        public static readonly DependencyProperty ZoomProperty =
                FlowDocumentPageViewer.ZoomProperty.AddOwner(
                        typeof(FlowDocumentReader),
                        new FrameworkPropertyMetadata( 
                                100d,
                                new PropertyChangedCallback(ZoomChanged), 
                                new CoerceValueCallback(CoerceZoom))); 

        ///  
        /// 
        /// 
        public static readonly DependencyProperty MaxZoomProperty =
                FlowDocumentPageViewer.MaxZoomProperty.AddOwner( 
                        typeof(FlowDocumentReader),
                        new FrameworkPropertyMetadata( 
                                200d, 
                                new PropertyChangedCallback(MaxZoomChanged),
                                new CoerceValueCallback(CoerceMaxZoom))); 

        /// 
        /// 
        ///  
        public static readonly DependencyProperty MinZoomProperty =
                FlowDocumentPageViewer.MinZoomProperty.AddOwner( 
                        typeof(FlowDocumentReader), 
                        new FrameworkPropertyMetadata(
                                80d, 
                                new PropertyChangedCallback(MinZoomChanged)));

        /// 
        ///  
        /// 
        public static readonly DependencyProperty ZoomIncrementProperty = 
                FlowDocumentPageViewer.ZoomIncrementProperty.AddOwner( 
                        typeof(FlowDocumentReader));
 
        /// 
        /// 
        /// 
        private static readonly DependencyPropertyKey CanIncreaseZoomPropertyKey = 
                DependencyProperty.RegisterReadOnly(
                        "CanIncreaseZoom", 
                        typeof(bool), 
                        typeof(FlowDocumentReader),
                        new FrameworkPropertyMetadata(BooleanBoxes.TrueBox)); 

        /// 
        /// 
        ///  
        public static readonly DependencyProperty CanIncreaseZoomProperty = CanIncreaseZoomPropertyKey.DependencyProperty;
 
        ///  
        /// 
        ///  
        private static readonly DependencyPropertyKey CanDecreaseZoomPropertyKey =
                DependencyProperty.RegisterReadOnly(
                        "CanDecreaseZoom",
                        typeof(bool), 
                        typeof(FlowDocumentReader),
                        new FrameworkPropertyMetadata(BooleanBoxes.TrueBox)); 
 
        /// 
        ///  
        /// 
        public static readonly DependencyProperty CanDecreaseZoomProperty = CanDecreaseZoomPropertyKey.DependencyProperty;

        ///  
        /// 
        ///  
        public static readonly DependencyProperty SelectionBrushProperty = 
            TextBoxBase.SelectionBrushProperty.AddOwner(typeof(FlowDocumentReader));
 
        /// 
        /// 
        /// 
        public static readonly DependencyProperty SelectionOpacityProperty = 
            TextBoxBase.SelectionOpacityProperty.AddOwner(typeof(FlowDocumentReader));
 
        #endregion Public Dynamic Properties 

        #endregion Public Properties 

        //-------------------------------------------------------------------
        //
        //  Public Commands 
        //
        //-------------------------------------------------------------------- 
 
        #region Public Commands
 
        /// 
        /// Switch ViewingMode command
        /// 
        public static readonly RoutedUICommand SwitchViewingModeCommand = new RoutedUICommand(SR.Get(SRID.SwitchViewingMode), "SwitchViewingMode", typeof(FlowDocumentReader), null); 

        #endregion 
 
        //-------------------------------------------------------------------
        // 
        //  Protected Methods
        //
        //-------------------------------------------------------------------
 
        #region Protected Methods
 
        ///  
        /// Called when print has been completed.
        ///  
        protected virtual void OnPrintCompleted()
        {
            if (_printInProgress)
            { 
                _printInProgress = false;
                // Since _printInProgress value is used to determine CanExecute state, we must invalidate that state. 
                CommandManager.InvalidateRequerySuggested(); 
            }
        } 

        /// 
        /// 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 (CurrentViewer != null)
            {
                CurrentViewer.Print();
            } 
        }
 
        ///  
        /// Handler for the CancelPrint command.
        ///  
        protected virtual void OnCancelPrintCommand()
        {
            if (CurrentViewer != null)
            { 
                CurrentViewer.CancelPrint();
            } 
        } 

        ///  
        /// Handler for the IncreaseZoom command.
        /// 
        protected virtual void OnIncreaseZoomCommand()
        { 
            // If can zoom in, increase zoom by the zoom increment value.
            if (CanIncreaseZoom) 
            { 
                SetCurrentValueInternal(ZoomProperty, 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) 
            {
                SetCurrentValueInternal(ZoomProperty, Math.Max(Zoom - ZoomIncrement, MinZoom));
            }
        } 

        ///  
        /// Handler for the SwitchViewingMode command. 
        /// 
        /// Viewing mode. 
        protected virtual void OnSwitchViewingModeCommand(FlowDocumentReaderViewingMode viewingMode)
        {
            SwitchViewingModeCore(viewingMode);
        } 

        ///  
        /// Called when IsInitialized is set to true. 
        /// 
        /// Event arguments 
        protected override void OnInitialized(EventArgs e)
        {
            base.OnInitialized(e);
 
            // Defer the Is*ViewEnabled & ViewingMode conflict exception.
            // Otherwise  won't work. 
            if (IsInitialized && !CanSwitchToViewingMode(ViewingMode)) 
            {
                throw new ArgumentException(SR.Get(SRID.FlowDocumentReaderViewingModeEnabledConflict)); 
            }
        }

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

        /// 
        /// An event reporting that the IsKeyboardFocusWithin property changed. 
        /// 
        protected override void OnIsKeyboardFocusWithinChanged(DependencyPropertyChangedEventArgs e) 
        { 
            base.OnIsKeyboardFocusWithinChanged(e);
 
            // In order to enable selection rendering and other similar services, the embedded viewer
            // needs to get focus, when any part of the control gets focused.
            // But if the focus is within the Document, do not change it. Otherwise it
            // will interfere with input handling inside the Document. 
            if (IsKeyboardFocusWithin && CurrentViewer != null)
            { 
                bool isFocusWithinDocument = IsFocusWithinDocument(); 
                if (!isFocusWithinDocument)
                { 
                    ((FrameworkElement)CurrentViewer).Focus();
                }
            }
        } 

        ///  
        /// 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);
            } 
        }

        #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)
        { 
            // Do not add intermediate ContentElements to the route, 
            // because they were added by embedded viewer.
            return BuildRouteCoreHelper(route, args, false); 
        }

        #endregion Internal Methods
 
        //--------------------------------------------------------------------
        // 
        //  Private Methods 
        //
        //------------------------------------------------------------------- 

        #region Private Methods

        ///  
        /// Handler for the SwitchViewingMode command.
        ///  
        /// Viewing mode. 
        protected virtual void SwitchViewingModeCore(FlowDocumentReaderViewingMode viewingMode)
        { 
            ITextSelection textSelection = null;
            ContentPosition contentPosition = null;
            IFlowDocumentViewer viewer;
            FrameworkElement feViewer; 
            bool isKeyboardFocusWithin;
            DependencyObject focusedElement = null; 
 
            if (_contentHost != null)
            { 
                // Remember the current keyboard focus state.
                isKeyboardFocusWithin = IsKeyboardFocusWithin;

                // Detach old viewer 
                viewer = _contentHost.Child as IFlowDocumentViewer;
                if (viewer != null) 
                { 
                    // Remember focused element, if the focus is within the Document.
                    // After switching to a different viewer, this focus needs to be restored. 
                    if (isKeyboardFocusWithin)
                    {
                        bool isFocusWithinDocument = IsFocusWithinDocument();
                        if (isFocusWithinDocument) 
                        {
                            focusedElement = Keyboard.FocusedElement as DependencyObject; 
                        } 
                    }
 
                    // Retrieve the current viewing state from the old viewer.
                    textSelection = viewer.TextSelection;
                    contentPosition = viewer.ContentPosition;
 
                    // Detach old viewer
                    DetachViewer(viewer); 
                } 

                viewer = GetViewerFromMode(viewingMode); 
                feViewer = (FrameworkElement)viewer;
                if (viewer != null)
                {
                    // Attach new viewer 
                    _contentHost.Child = feViewer;
                    AttachViewer(viewer); 
 
                    // Restore viewing state.
                    viewer.TextSelection = textSelection; 
                    viewer.ContentPosition = contentPosition;

                    // Bring the focus to previously focused element within the document
                    // or to the current viewer. 
                    if (isKeyboardFocusWithin)
                    { 
                        if (focusedElement is UIElement) 
                        {
                            ((UIElement)focusedElement).Focus(); 
                        }
                        else if (focusedElement is ContentElement)
                        {
                            ((ContentElement)focusedElement).Focus(); 
                        }
                        else 
                        { 
                            feViewer.Focus();
                        } 
                    }
                }

                // Viewer changes invalidates following properties: 
                //      - PageCount
                //      - PageNumber 
                //      - CanGoToPreviousPage 
                //      - CanGoToNextPage
                UpdateReadOnlyProperties(true, true); 
            }
        }

        ///  
        /// Determines whether focus is within Document.
        ///  
        private bool IsFocusWithinDocument() 
        {
            DependencyObject focusedElement = Keyboard.FocusedElement as DependencyObject; 
            while (focusedElement != null && focusedElement != Document)
            {
                // Skip elements in the control's template (if such exists) and
                // walk up logical tree to find if the focused element is within 
                // the document.
                FrameworkElement fe = focusedElement as FrameworkElement; 
                if (fe != null && fe.TemplatedParent != null) 
                {
                    focusedElement = fe.TemplatedParent; 
                }
                else
                {
                    focusedElement = LogicalTreeHelper.GetParent(focusedElement); 
                }
            } 
            return (focusedElement != null); 
        }
 
        /// 
        /// The Document has changed and needs to be updated.
        /// 
        private void DocumentChanged(FlowDocument oldDocument, FlowDocument newDocument) 
        {
            // Cleanup state associated with the old document. 
            if (oldDocument != null) 
            {
                // If Document was added to logical tree before, remove it. 
                if (_documentAsLogicalChild)
                {
                    RemoveLogicalChild(oldDocument);
                } 
            }
 
            // If FlowDocumentReader was created through style, then do not modify 
            // the logical tree. Instead, set "core parent" for the Document.
            if (TemplatedParent != null && 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)
            { 
                // If Document should be part of DocumentViewer's logical tree, add it.
                if (_documentAsLogicalChild) 
                { 
                    AddLogicalChild(newDocument);
                } 
            }

            // Attach document to the current viewer.
            if (CurrentViewer != null) 
            {
                CurrentViewer.SetDocument(newDocument); 
            } 

            // Document invalidation invalidates following properties: 
            //      - PageCount
            //      - PageNumber
            //      - CanGoToPreviousPage
            //      - CanGoToNextPage 
            UpdateReadOnlyProperties(true, true);
 
            // 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.
            FlowDocumentReaderAutomationPeer peer = UIElementAutomationPeer.FromElement(this) as FlowDocumentReaderAutomationPeer; 
            if (peer != null)
            {
                peer.InvalidatePeer();
            } 
        }
 
        ///  
        /// Detach embedded viewer form the reader control.
        ///  
        private void DetachViewer(IFlowDocumentViewer viewer)
        {
            Invariant.Assert(viewer != null && viewer is FrameworkElement);
            FrameworkElement feViewer = (FrameworkElement)viewer; 
            // Clear property bindings.
            BindingOperations.ClearBinding(feViewer, ZoomProperty); 
            BindingOperations.ClearBinding(feViewer, MaxZoomProperty); 
            BindingOperations.ClearBinding(feViewer, MinZoomProperty);
            BindingOperations.ClearBinding(feViewer, ZoomIncrementProperty); 
            // Unregister event handlers.
            viewer.PageCountChanged -= new EventHandler(OnPageCountChanged);
            viewer.PageNumberChanged -= new EventHandler(OnPageNumberChanged);
            viewer.PrintStarted -= new EventHandler(OnViewerPrintStarted); 
            viewer.PrintCompleted -= new EventHandler(OnViewerPrintCompleted);
            // Clear TemplatedParent 
            //feViewer._templatedParent = null; 
            // Detach document
            viewer.SetDocument(null); 
        }

        /// 
        /// Attach embedded viewer to the reader control. 
        /// 
        private void AttachViewer(IFlowDocumentViewer viewer) 
        { 
            Invariant.Assert(viewer != null && viewer is FrameworkElement);
            FrameworkElement feViewer = (FrameworkElement)viewer; 
            // Set document
            viewer.SetDocument(Document);
            // Set TemplatedParent
            //feViewer._templatedParent = TemplatedParent; 
            // Register event handlers.
            viewer.PageCountChanged += new EventHandler(OnPageCountChanged); 
            viewer.PageNumberChanged += new EventHandler(OnPageNumberChanged); 
            viewer.PrintStarted += new EventHandler(OnViewerPrintStarted);
            viewer.PrintCompleted += new EventHandler(OnViewerPrintCompleted); 
            // Create property bindings.
            CreateTwoWayBinding(feViewer, ZoomProperty, "Zoom");
            CreateTwoWayBinding(feViewer, MaxZoomProperty, "MaxZoom");
            CreateTwoWayBinding(feViewer, MinZoomProperty, "MinZoom"); 
            CreateTwoWayBinding(feViewer, ZoomIncrementProperty, "ZoomIncrement");
        } 
 
        /// 
        /// 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); 
        }
 
        /// 
        /// Determines whether can switch to specified ViewingMode or not.
        /// 
        private bool CanSwitchToViewingMode(FlowDocumentReaderViewingMode mode) 
        {
            bool canSwitch = false; 
            switch (mode) 
            {
                case FlowDocumentReaderViewingMode.Page: 
                    canSwitch = IsPageViewEnabled;
                    break;
                case FlowDocumentReaderViewingMode.TwoPage:
                    canSwitch = IsTwoPageViewEnabled; 
                    break;
                case FlowDocumentReaderViewingMode.Scroll: 
                    canSwitch = IsScrollViewEnabled; 
                    break;
            } 
            return canSwitch;
        }

        ///  
        /// Retrieves viewer form specified ViewingMode.
        ///  
        private IFlowDocumentViewer GetViewerFromMode(FlowDocumentReaderViewingMode mode) 
        {
            IFlowDocumentViewer viewer = null; 
            switch (mode)
            {
                case FlowDocumentReaderViewingMode.Page:
                    if (_pageViewer == null) 
                    {
                        _pageViewer = new ReaderPageViewer(); 
                        _pageViewer.SetResourceReference(StyleProperty, PageViewStyleKey); 
                        _pageViewer.Name = "PageViewer";
                        CommandManager.AddPreviewCanExecuteHandler(_pageViewer, new CanExecuteRoutedEventHandler(PreviewCanExecuteRoutedEventHandler)); 
                    }
                    viewer = _pageViewer;
                    break;
                case FlowDocumentReaderViewingMode.TwoPage: 
                    if (_twoPageViewer == null)
                    { 
                        _twoPageViewer = new ReaderTwoPageViewer(); 
                        _twoPageViewer.SetResourceReference(StyleProperty, TwoPageViewStyleKey);
                        _twoPageViewer.Name = "TwoPageViewer"; 
                        CommandManager.AddPreviewCanExecuteHandler(_twoPageViewer, new CanExecuteRoutedEventHandler(PreviewCanExecuteRoutedEventHandler));
                    }
                    viewer = _twoPageViewer;
                    break; 
                case FlowDocumentReaderViewingMode.Scroll:
                    if (_scrollViewer == null) 
                    { 
                        _scrollViewer = new ReaderScrollViewer();
                        _scrollViewer.SetResourceReference(StyleProperty, ScrollViewStyleKey); 
                        _scrollViewer.Name = "ScrollViewer";
                        CommandManager.AddPreviewCanExecuteHandler(_scrollViewer, new CanExecuteRoutedEventHandler(PreviewCanExecuteRoutedEventHandler));
                    }
                    viewer = _scrollViewer; 
                    break;
            } 
            return viewer; 
        }
 
        /// 
        /// Update values for readonly properties.
        /// 
        /// Whether PageCount has been changed. 
        /// Whether PageNumber has been changed.
        private void UpdateReadOnlyProperties(bool pageCountChanged, bool pageNumberChanged) 
        { 
            if (pageCountChanged)
            { 
                SetValue(PageCountPropertyKey, (CurrentViewer != null) ? CurrentViewer.PageCount : 0);
            }

            if (pageNumberChanged) 
            {
                SetValue(PageNumberPropertyKey, (CurrentViewer != null) ? CurrentViewer.PageNumber : 0); 
                SetValue(CanGoToPreviousPagePropertyKey, (CurrentViewer != null) ? CurrentViewer.CanGoToPreviousPage : false); 
            }
 
            if (pageCountChanged || pageNumberChanged)
            {
                SetValue(CanGoToNextPagePropertyKey, (CurrentViewer != null) ? CurrentViewer.CanGoToNextPage : false);
            } 
        }
 
        ///  
        /// Event handler for IFlowDocumentViewer.PageCountChanged.
        ///  
        private void OnPageCountChanged(object sender, EventArgs e)
        {
            Invariant.Assert(CurrentViewer != null && sender == CurrentViewer);
            UpdateReadOnlyProperties(true, false); 
        }
 
        ///  
        /// Event handler for IFlowDocumentViewer.PageNumberChanged.
        ///  
        private void OnPageNumberChanged(object sender, EventArgs e)
        {
            Invariant.Assert(CurrentViewer != null && sender == CurrentViewer);
            UpdateReadOnlyProperties(false, true); 
        }
 
        ///  
        /// Event handler for IFlowDocumentViewer.PrintStarted.
        ///  
        private void OnViewerPrintStarted(object sender, EventArgs e)
        {
            Invariant.Assert(CurrentViewer != null && sender == CurrentViewer);
            _printInProgress = true; 
            // Since _printInProgress value is used to determine CanExecute state, we must invalidate that state.
            CommandManager.InvalidateRequerySuggested(); 
        } 

        ///  
        /// Event handler for IFlowDocumentViewer.PrintCompleted.
        /// 
        private void OnViewerPrintCompleted(object sender, EventArgs e)
        { 
            Invariant.Assert(CurrentViewer != null && sender == CurrentViewer);
            OnPrintCompleted(); 
        } 

        ///  
        /// Convert object value to FlowDocumentReaderViewingMode.
        /// 
        private bool ConvertToViewingMode(object value, out FlowDocumentReaderViewingMode mode)
        { 
            bool success;
            if (value is FlowDocumentReaderViewingMode) 
            { 
                mode = (FlowDocumentReaderViewingMode)value;
                success = true; 
            }
            else if (value is String)
            {
                String str = (String)value; 
                if (str == FlowDocumentReaderViewingMode.Page.ToString())
                { 
                    mode = FlowDocumentReaderViewingMode.Page; 
                    success = true;
                } 
                else if (str == FlowDocumentReaderViewingMode.TwoPage.ToString())
                {
                    mode = FlowDocumentReaderViewingMode.TwoPage;
                    success = true; 
                }
                else if (str == FlowDocumentReaderViewingMode.Scroll.ToString()) 
                { 
                    mode = FlowDocumentReaderViewingMode.Scroll;
                    success = true; 
                }
                else
                {
                    mode = FlowDocumentReaderViewingMode.Page; 
                    success = false;
                } 
            } 
            else
            { 
                mode = FlowDocumentReaderViewingMode.Page;
                success = false;
            }
            return success; 
        }
 
        ///  
        /// Enables/disables the FindToolBar.
        ///  
        /// Whether to enable/disable FindToolBar.
        private void ToggleFindToolBar(bool enable)
        {
            Invariant.Assert(enable == (FindToolBar == null)); 

            // Command event for toggle button is only fired in OnClick - Therefore we just need to change the state 
            if(_findButton != null && _findButton.IsChecked.HasValue && _findButton.IsChecked.Value != enable) 
            {
                _findButton.IsChecked = enable; 
            }
            DocumentViewerHelper.ToggleFindToolBar(_findToolBarHost, new EventHandler(OnFindInvoked), enable);
        }
 
        #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 CanExecuteRoutedEventHandler
            canExecuteHandler = new CanExecuteRoutedEventHandler(CanExecuteRoutedEventHandler); 

            // Command: SwitchViewingMode
            CommandHelpers.RegisterCommandHandler(typeof(FlowDocumentReader), FlowDocumentReader.SwitchViewingModeCommand,
                executedHandler, canExecuteHandler, SRID.KeySwitchViewingMode, SRID.KeySwitchViewingModeDisplayString); 

            // Command: ApplicationCommands.Find 
            CommandHelpers.RegisterCommandHandler(typeof(FlowDocumentReader), ApplicationCommands.Find, 
                executedHandler, canExecuteHandler);
 
            // Command: ApplicationCommands.Print
            CommandHelpers.RegisterCommandHandler(typeof(FlowDocumentReader), ApplicationCommands.Print,
                executedHandler, canExecuteHandler);
 
            // Command: ApplicationCommands.CancelPrint
            CommandHelpers.RegisterCommandHandler(typeof(FlowDocumentReader), ApplicationCommands.CancelPrint, 
                executedHandler, canExecuteHandler); 

            // Command: NavigationCommands.PreviousPage 
            CommandHelpers.RegisterCommandHandler(typeof(FlowDocumentReader), NavigationCommands.PreviousPage,
                executedHandler, canExecuteHandler);

            // Command: NavigationCommands.NextPage 
            CommandHelpers.RegisterCommandHandler(typeof(FlowDocumentReader), NavigationCommands.NextPage,
                executedHandler, canExecuteHandler); 
 
            // Command: NavigationCommands.FirstPage
            CommandHelpers.RegisterCommandHandler(typeof(FlowDocumentReader), NavigationCommands.FirstPage, 
                executedHandler, canExecuteHandler);

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

            // Command: NavigationCommands.DecreaseZoom
            CommandHelpers.RegisterCommandHandler(typeof(FlowDocumentReader), NavigationCommands.DecreaseZoom,
                executedHandler, canExecuteHandler, new KeyGesture(Key.OemMinus, ModifierKeys.Control)); 
        }
 
        ///  
        /// Central handler for CanExecute events fired by Commands directed at FlowDocumentReader.
        ///  
        /// The target of this Command, expected to be FlowDocumentReader
        /// The event arguments for this event.
        private static void CanExecuteRoutedEventHandler(object target, CanExecuteRoutedEventArgs args)
        { 
            FlowDocumentReader viewer = target as FlowDocumentReader;
            Invariant.Assert(viewer != null, "Target of CanExecuteRoutedEventHandler must be FlowDocumentReader."); 
            Invariant.Assert(args != null, "args cannot be null."); 

            // FlowDocumentReader 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 and printing is enabled. 
            // d) CancelPrint command is enabled only during printing.
            // e) SwitchViewingMode command is enabled if the viewing mode is enabled, or 
            //    the command has no parameters (will switch to the next available view). 
            if (!viewer._printInProgress)
            { 
                if (args.Command == FlowDocumentReader.SwitchViewingModeCommand)
                {
                    // This command is enabled if the viewing mode is enabled, or the command
                    // has no parameters (will switch to the next available view). 
                    FlowDocumentReaderViewingMode mode;
                    if (viewer.ConvertToViewingMode(args.Parameter, out mode)) 
                    { 
                        args.CanExecute = viewer.CanSwitchToViewingMode(mode);
                    } 
                    else
                    {
                        args.CanExecute = (args.Parameter == null);
                    } 
                }
                else if (args.Command == ApplicationCommands.Find) 
                { 
                    args.CanExecute = viewer.CanShowFindToolBar;
                } 
                else if (args.Command == ApplicationCommands.Print)
                {
                    args.CanExecute = (viewer.Document != null) && viewer.IsPrintEnabled;
                } 
                else if (args.Command == ApplicationCommands.CancelPrint)
                { 
                    args.CanExecute = false; 
                }
                else 
                {
                    args.CanExecute = true;
                }
            } 
            else
            { 
                args.CanExecute = (args.Command == ApplicationCommands.CancelPrint); 
            }
        } 

        /// 
        /// Central handler for all ExecuteEvents fired by Commands directed at FlowDocumentReader.
        ///  
        /// The target of this Command, expected to be FlowDocumentReader.
        /// The event arguments associated with this event. 
        private static void ExecutedRoutedEventHandler(object target, ExecutedRoutedEventArgs args) 
        {
            FlowDocumentReader viewer = target as FlowDocumentReader; 
            Invariant.Assert(viewer != null, "Target of ExecutedRoutedEventHandler must be FlowDocumentReader.");
            Invariant.Assert(args != null, "args cannot be null.");

            if (args.Command == FlowDocumentReader.SwitchViewingModeCommand) 
            {
                viewer.TrySwitchViewingMode(args.Parameter); 
            } 
            else 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 == NavigationCommands.PreviousPage)
            {
                viewer.OnPreviousPageCommand();
            } 
            else if (args.Command == NavigationCommands.NextPage)
            { 
                viewer.OnNextPageCommand(); 
            }
            else if (args.Command == NavigationCommands.FirstPage) 
            {
                viewer.OnFirstPageCommand();
            }
            else if (args.Command == NavigationCommands.LastPage) 
            {
                viewer.OnLastPageCommand(); 
            } 
            else
            { 
                Invariant.Assert(false, "Command not handled in ExecutedRoutedEventHandler.");
            }
        }
 
        /// 
        /// Changes the current viewing mode. 
        ///  
        private void TrySwitchViewingMode(object parameter)
        { 
            FlowDocumentReaderViewingMode mode;
            // Convert command parameter to viewing mode value.
            // If parameter is not provided, the viewing mode is the next one available.
            // If parameter cannot be converted, the command is ignored. 
            if (!ConvertToViewingMode(parameter, out mode))
            { 
                if (parameter == null) 
                {
                    mode = (FlowDocumentReaderViewingMode)((((int)ViewingMode) + 1) % 3); 
                }
                else
                {
                    return; 
                }
            } 
            // If the current ViewingMode is disabled, go to next one. 
            while (!CanSwitchToViewingMode(mode))
            { 
                mode = (FlowDocumentReaderViewingMode)((((int)mode) + 1) % 3);
            }
            // Set new ViewingMode value.
            SetCurrentValueInternal(ViewingModeProperty, mode); 
        }
 
        ///  
        /// Handler for the PreviousPage command.
        ///  
        private void OnPreviousPageCommand()
        {
            if (CurrentViewer != null)
            { 
                CurrentViewer.PreviousPage();
            } 
        } 

        ///  
        /// Handler for the NextPage command.
        /// 
        private void OnNextPageCommand()
        { 
            if (CurrentViewer != null)
            { 
                CurrentViewer.NextPage(); 
            }
        } 

        /// 
        /// Handler for the FirstPage command.
        ///  
        private void OnFirstPageCommand()
        { 
            if (CurrentViewer != null) 
            {
                CurrentViewer.FirstPage(); 
            }
        }

        ///  
        /// Handler for the LastPage command.
        ///  
        private void OnLastPageCommand() 
        {
            if (CurrentViewer != null) 
            {
                CurrentViewer.LastPage();
            }
        } 

        ///  
        /// 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;
            TextEditor textEditor = TextEditor; 
            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. 
                if (CurrentViewer != null && CurrentViewer is UIElement)
                { 
                    ((UIElement)CurrentViewer).Focus(); 
                }
 
                findResult = DocumentViewerHelper.Find(findToolBar, textEditor, textEditor.TextView, textEditor.TextView);

                // If we found something, bring it into the view. Otherwise alert the user.
                if ((findResult != null) && (!findResult.IsEmpty)) 
                {
                    // Bring find result into view. 
                    if (CurrentViewer != null) 
                    {
                        CurrentViewer.ShowFindResult(findResult); 
                    }
                }
                else
                { 
                    DocumentViewerHelper.ShowFindUnsuccessfulMessage(findToolBar);
                } 
            } 
        }
 
        /// 
        /// Disable commands on IFlowDocumentViewer when this funcionality is explicitly
        /// disabled on the reader control.
        ///  
        private void PreviewCanExecuteRoutedEventHandler(object target, CanExecuteRoutedEventArgs args)
        { 
            if (args.Command == ApplicationCommands.Find) 
            {
                // Find is handled by FlowDocumentReader. 
                args.CanExecute = false;
                args.Handled = true;
            }
            else if (args.Command == ApplicationCommands.Print) 
            {
                args.CanExecute = IsPrintEnabled; 
                args.Handled = !IsPrintEnabled; 
            }
        } 

        /// 
        /// Called when a key event occurs.
        ///  
        private static void KeyDownHandler(object sender, KeyEventArgs e)
        { 
            DocumentViewerHelper.KeyDownHelper(e, ((FlowDocumentReader)sender)._findToolBarHost); 
        }
 
        #endregion Commands

        #region Static Methods
 
        /// 
        /// ViewingMode has been changed. 
        ///  
        private static void ViewingModeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        { 
            Invariant.Assert(d != null && d is FlowDocumentReader);
            FlowDocumentReader viewer = (FlowDocumentReader)d;
            if (viewer.CanSwitchToViewingMode((FlowDocumentReaderViewingMode)e.NewValue))
            { 
                viewer.SwitchViewingModeCore((FlowDocumentReaderViewingMode)e.NewValue);
            } 
            else if (viewer.IsInitialized) 
            {
                throw new ArgumentException(SR.Get(SRID.FlowDocumentReaderViewingModeEnabledConflict)); 
            }

            // Fire automation events if automation is active.
            FlowDocumentReaderAutomationPeer peer = UIElementAutomationPeer.FromElement(viewer) as FlowDocumentReaderAutomationPeer; 
            if (peer != null)
            { 
                peer.RaiseCurrentViewChangedEvent((FlowDocumentReaderViewingMode)e.NewValue, (FlowDocumentReaderViewingMode)e.OldValue); 
            }
        } 

        /// 
        /// Validate value of ViewingMode property.
        ///  
        private static bool IsValidViewingMode(object o)
        { 
            FlowDocumentReaderViewingMode value = (FlowDocumentReaderViewingMode)o; 
            return (value == FlowDocumentReaderViewingMode.Page ||
                    value == FlowDocumentReaderViewingMode.TwoPage || 
                    value == FlowDocumentReaderViewingMode.Scroll);
        }

        ///  
        /// One of viewing modes has been enabled/disabled.
        ///  
        private static void ViewingModeEnabledChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
        {
            Invariant.Assert(d != null && d is FlowDocumentReader); 
            FlowDocumentReader viewer = (FlowDocumentReader)d;

            // Cannot disable all viewing modes.
            if (!viewer.IsPageViewEnabled && 
                !viewer.IsTwoPageViewEnabled &&
                !viewer.IsScrollViewEnabled) 
            { 
                throw new ArgumentException(SR.Get(SRID.FlowDocumentReaderCannotDisableAllViewingModes));
            } 

            // Cannot disable the current viewing mode.
            if (viewer.IsInitialized && !viewer.CanSwitchToViewingMode(viewer.ViewingMode))
            { 
                throw new ArgumentException(SR.Get(SRID.FlowDocumentReaderViewingModeEnabledConflict));
            } 
 
            // Fire automation events if automation is active.
            FlowDocumentReaderAutomationPeer peer = UIElementAutomationPeer.FromElement(viewer) as FlowDocumentReaderAutomationPeer; 
            if (peer != null)
            {
                peer.RaiseSupportedViewsChangedEvent(e);
            } 
        }
 
        ///  
        /// IsFindEnabled value has changed.
        ///  
        private static void IsFindEnabledChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            Invariant.Assert(d != null && d is FlowDocumentReader);
            FlowDocumentReader viewer = (FlowDocumentReader)d; 

            // Update the toolbar with our current state. 
            if (!viewer.CanShowFindToolBar) 
            {
                if (viewer.FindToolBar != null) 
                {
                    viewer.ToggleFindToolBar(false);
                }
            } 

            // Since IsFindEnabled state is used to determine CanExecute state, we must invalidate that state. 
            CommandManager.InvalidateRequerySuggested(); 
        }
 
        /// 
        /// IsPrintEnabled value has changed.
        /// 
        private static void IsPrintEnabledChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
        {
            Invariant.Assert(d != null && d is FlowDocumentReader); 
            FlowDocumentReader viewer = (FlowDocumentReader)d; 

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

        ///  
        /// The Document has changed and needs to be updated.
        ///  
        private static void DocumentChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
        {
            Invariant.Assert(d != null && d is FlowDocumentReader); 
            FlowDocumentReader viewer = (FlowDocumentReader)d;
            viewer.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 FlowDocumentReader); 
            FlowDocumentReader viewer = (FlowDocumentReader)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)));
            }
        }
 
        /// 
        /// Coerce Zoom with Max/MinZoom, MinZoom works as the baseline. 
        ///  
        private static object CoerceZoom(DependencyObject d, object value)
        { 
            Invariant.Assert(d != null && d is FlowDocumentReader);
            FlowDocumentReader viewer = (FlowDocumentReader)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 FlowDocumentReader);
            FlowDocumentReader viewer = (FlowDocumentReader)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 FlowDocumentReader);
            FlowDocumentReader viewer = (FlowDocumentReader)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 FlowDocumentReader);
            FlowDocumentReader viewer = (FlowDocumentReader)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));
        } 

        ///  
        /// PropertyChanged callback for a property that affects the selection or caret rendering. 
        /// 
        private static void UpdateCaretElement(DependencyObject d, DependencyPropertyChangedEventArgs e) 
        {
            FlowDocumentReader reader = (FlowDocumentReader)d;

            if (reader.Selection != null) 
            {
                CaretElement caretElement = reader.Selection.CaretElement; 
                if (caretElement != null) 
                {
                    caretElement.InvalidateVisual(); 
                }
            }
        }
 
        #endregion Static Methods
 
        #endregion Private Methods 

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

        #region Private Properties 
 
        /// 
        /// Whether FindToolBar can be enabled. 
        /// 
        private bool CanShowFindToolBar
        {
            get { return ((_findToolBarHost != null) && IsFindEnabled && (Document != null)); } 
        }
 
        ///  
        /// Returns TextEditor, if availabe.
        ///  
        private TextEditor TextEditor
        {
            get
            { 
                TextEditor textEditor = null;
                IFlowDocumentViewer currentViewer = CurrentViewer; 
                if (currentViewer != null && currentViewer.TextSelection != null) 
                {
                    textEditor = currentViewer.TextSelection.TextEditor; 
                }
                return textEditor;
            }
        } 

        ///  
        /// Returns FindToolBar, if enabled. 
        /// 
        private FindToolBar FindToolBar 
        {
            get { return (_findToolBarHost != null) ? _findToolBarHost.Child as FindToolBar : null; }
        }
 
        /// 
        /// Returns the current content viewer. 
        ///  
        private IFlowDocumentViewer CurrentViewer
        { 
            get
            {
                if (_contentHost != null)
                { 
                    return (IFlowDocumentViewer)_contentHost.Child;
                } 
                return null; 
            }
        } 

        #endregion Private Properties

        //------------------------------------------------------------------- 
        //
        //  Private Fields 
        // 
        //-------------------------------------------------------------------
 
        #region Private Fields

        private Decorator _contentHost;                 // Host for content viewer
        private Decorator _findToolBarHost;             // Host for FindToolBar 
        private ToggleButton _findButton;               // Find toggle button
        private ReaderPageViewer _pageViewer;           // Viewer for Page viewing mode 
        private ReaderTwoPageViewer _twoPageViewer;     // Viewer for TwoPage viewing mode 
        private ReaderScrollViewer _scrollViewer;       // Viewer for Scroll viewing mode
        private bool _documentAsLogicalChild;           // Is Document part of logical tree 
        private bool _printInProgress;                  // Whether print is currently in progress.

        private const string _contentHostTemplateName = "PART_ContentHost";         // Name for ContentHost
        private const string _findToolBarHostTemplateName = "PART_FindToolBarHost"; // Name for the Find ToolBar host 
        private const string _findButtonTemplateName = "FindButton"; // Name for the Find Button
 
        #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.FlowDocumentReaderCanHaveOnlyOneChild)); 
            }
            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
 
        //-------------------------------------------------------------------- 
        //
        //  IJournalState Members 
        //
        //--------------------------------------------------------------------

        #region IJournalState Members 

        [Serializable] 
        private class JournalState : CustomJournalStateInternal 
        {
            public JournalState(int contentPosition, LogicalDirection contentPositionDirection, double zoom, FlowDocumentReaderViewingMode viewingMode) 
            {
                ContentPosition = contentPosition;
                ContentPositionDirection = contentPositionDirection;
                Zoom = zoom; 
                ViewingMode = viewingMode;
            } 
            public int ContentPosition; 
            public LogicalDirection ContentPositionDirection;
            public double Zoom; 
            public FlowDocumentReaderViewingMode ViewingMode;
        }

        ///  
        /// 
        ///  
        CustomJournalStateInternal IJournalState.GetJournalState(JournalReason journalReason) 
        {
            int cp = -1; 
            LogicalDirection cpDirection = LogicalDirection.Forward;
            IFlowDocumentViewer viewer = CurrentViewer;
            if (viewer != null)
            { 
                TextPointer contentPosition = viewer.ContentPosition as TextPointer;
                if (contentPosition != null) 
                { 
                    cp = contentPosition.Offset;
                    cpDirection = contentPosition.LogicalDirection; 
                }
            }
            return new JournalState(cp, cpDirection, Zoom, ViewingMode);
        } 

        ///  
        ///  
        /// 
        void IJournalState.RestoreJournalState(CustomJournalStateInternal state) 
        {
            JournalState viewerState = state as JournalState;
            if (state != null)
            { 
                SetCurrentValueInternal(ZoomProperty, viewerState.Zoom);
                SetCurrentValueInternal(ViewingModeProperty, viewerState.ViewingMode); 
                if (viewerState.ContentPosition != -1) 
                {
                    IFlowDocumentViewer viewer = CurrentViewer; 
                    FlowDocument document = Document;
                    if (viewer != null && document != null)
                    {
                        TextContainer textContainer = document.StructuralCache.TextContainer; 
                        if (viewerState.ContentPosition <= textContainer.SymbolCount)
                        { 
                            TextPointer contentPosition = textContainer.CreatePointerAtOffset(viewerState.ContentPosition, viewerState.ContentPositionDirection); 
                            viewer.ContentPosition = 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 

        //-------------------------------------------------------------------
        //
        //  Style Keys 
        //
        //------------------------------------------------------------------- 
 
        #region Style Keys
 
        /// 
        /// Key used to mark the style for use by the PageView
        /// 
        private static ResourceKey PageViewStyleKey 
        {
            get 
            { 
                if (_pageViewStyleKey == null)
                { 
                    _pageViewStyleKey = new ComponentResourceKey(typeof(PresentationUIStyleResources), "PUIPageViewStyleKey");
                }

                return _pageViewStyleKey; 
            }
        } 
 
        /// 
        /// Key used to mark the style for use by the TwoPageView 
        /// 
        private static ResourceKey TwoPageViewStyleKey
        {
            get 
            {
                if (_twoPageViewStyleKey == null) 
                { 
                    _twoPageViewStyleKey = new ComponentResourceKey(typeof(PresentationUIStyleResources), "PUITwoPageViewStyleKey");
                } 

                return _twoPageViewStyleKey;
            }
        } 

        ///  
        /// Key used to mark the style for use by the ScrollView 
        /// 
        private static ResourceKey ScrollViewStyleKey 
        {
            get
            {
                if (_scrollViewStyleKey == null) 
                {
                    _scrollViewStyleKey = new ComponentResourceKey(typeof(PresentationUIStyleResources), "PUIScrollViewStyleKey"); 
                } 

                return _scrollViewStyleKey; 
            }
        }

 
        private static ComponentResourceKey _pageViewStyleKey;
        private static ComponentResourceKey _twoPageViewStyleKey; 
        private static ComponentResourceKey _scrollViewStyleKey; 

        #endregion 
    }

    /// 
    /// 

    public enum FlowDocumentReaderViewingMode 
    { 
        /// 
        /// 

        Page,

        ///  
        ///
 
        TwoPage, 

        ///  
        ///

        Scroll
    } 
}

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