Code:
/ Net / Net / 3.5.50727.3053 / DEVDIV / depot / DevDiv / releases / Orcas / SP / wpf / src / Framework / System / Windows / Controls / SinglePageViewer.cs / 1 / SinglePageViewer.cs
//---------------------------------------------------------------------------- // // Copyright (C) Microsoft Corporation. All rights reserved. // // File: FlowDocumentPageViewer.cs // // Description: FlowDocumentPageViewer provides a simple user experience for viewing // one page of content at a time. The experience is optimized for // FlowDocument scenarios, however any IDocumentPaginatorSource // can be viewed using this control. // //--------------------------------------------------------------------------- using System.Collections.ObjectModel; // ReadOnlyCollectionusing System.Printing; // WritingCompletedEventArgs using System.Windows.Automation.Peers; // AutomationPeer using System.Windows.Documents; // IDocumentPaginatorSouce, ... using System.Windows.Documents.Serialization; // WritingCompletedEventArgs using System.Windows.Input; // UICommand using System.Windows.Media; // VisualTreeHelper using System.Windows.Controls.Primitives; // DocumentViewerBase, DocumentPageView using System.Windows.Xps; // XpsDocumentWriter using System.Windows.Threading; using MS.Internal; // Invariant, DoubleUtil using MS.Internal.Commands; // CommandHelpers using MS.Internal.Documents; // FindToolBar using MS.Internal.KnownBoxes; // BooleanBoxes using MS.Internal.PresentationFramework; // SecurityHelper using MS.Internal.AppModel; // IJournalState using System.Security; // SecurityCritical, SecurityTreatAsSafe namespace System.Windows.Controls { /// /// FlowDocumentPageViewer provides a simple user experience for viewing one page /// of content at a time. The experience is optimized for FlowDocument scenarios, /// however any IDocumentPaginatorSource can be viewed using this control. /// [TemplatePart(Name = "PART_FindToolBarHost", Type = typeof(Decorator))] public class FlowDocumentPageViewer : DocumentViewerBase, IJournalState { //------------------------------------------------------------------- // // Constructors // //------------------------------------------------------------------- #region Constructors ////// Initializes class-wide settings. /// static FlowDocumentPageViewer() { DefaultStyleKeyProperty.OverrideMetadata( typeof(FlowDocumentPageViewer), new FrameworkPropertyMetadata(new ComponentResourceKey(typeof(PresentationUIStyleResources), "PUIFlowDocumentPageViewer"))); _dType = DependencyObjectType.FromSystemTypeInternal(typeof(FlowDocumentPageViewer)); // Create our CommandBindings CreateCommandBindings(); EventManager.RegisterClassHandler(typeof(FlowDocumentPageViewer), Keyboard.KeyDownEvent, new KeyEventHandler(KeyDownHandler), true); } ////// Instantiates a new instance of a FlowDocumentPageViewer. /// public FlowDocumentPageViewer() : base() { this.LayoutUpdated += new EventHandler(HandleLayoutUpdated); } #endregion Constructors //-------------------------------------------------------------------- // // Public Methods // //------------------------------------------------------------------- #region Public Methods ////// Called when the Template's tree has been generated /// ///Whether Visuals were added to the tree. public override void OnApplyTemplate() { base.OnApplyTemplate(); // 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; } ////// Increases the current zoom. /// public void IncreaseZoom() { OnIncreaseZoomCommand(); } ////// Decreases the current zoom. /// public void DecreaseZoom() { OnDecreaseZoomCommand(); } ////// Invokes the Find Toolbar. This is analogous to the ApplicationCommands.Find. /// public void Find() { OnFindCommand(); } #endregion Public Methods //-------------------------------------------------------------------- // // Public Properties // //-------------------------------------------------------------------- #region Public Properties ////// Text Selection (readonly) /// public TextSelection Selection { get { ITextSelection textSelection = null; FlowDocument flowDocument = Document as FlowDocument; if (flowDocument != null) { textSelection = flowDocument.StructuralCache.TextContainer.TextSelection; } return textSelection as TextSelection; } } ////// The Zoom applied to all pages; this value is 100-based. /// public double Zoom { get { return (double) GetValue(ZoomProperty); } set { SetValue(ZoomProperty, value); } } ////// The maximum allowed value of the Zoom property. /// public double MaxZoom { get { return (double) GetValue(MaxZoomProperty); } set { SetValue(MaxZoomProperty, value); } } ////// The minimum allowed value of the Zoom property. /// public double MinZoom { get { return (double) GetValue(MinZoomProperty); } set { SetValue(MinZoomProperty, value); } } ////// The amount the Zoom property is incremented or decremented when /// the IncreaseZoom or DecreaseZoom command is executed. /// public double ZoomIncrement { get { return (double) GetValue(ZoomIncrementProperty); } set { SetValue(ZoomIncrementProperty, value); } } ////// Whether the viewer can increase the current zoom. /// public virtual bool CanIncreaseZoom { get { return (bool) GetValue(CanIncreaseZoomProperty); } } ////// Whether the viewer can decrease the current zoom. /// public virtual bool CanDecreaseZoom { get { return (bool) GetValue(CanDecreaseZoomProperty); } } #region Public Dynamic Properties ////// public static readonly DependencyProperty ZoomProperty = DependencyProperty.Register( "Zoom", typeof(double), typeof(FlowDocumentPageViewer), new FrameworkPropertyMetadata( 100d, new PropertyChangedCallback(ZoomChanged), new CoerceValueCallback(CoerceZoom)), new ValidateValueCallback(ZoomValidateValue)); ////// /// public static readonly DependencyProperty MaxZoomProperty = DependencyProperty.Register( "MaxZoom", typeof(double), typeof(FlowDocumentPageViewer), new FrameworkPropertyMetadata( 200d, new PropertyChangedCallback(MaxZoomChanged), new CoerceValueCallback(CoerceMaxZoom)), new ValidateValueCallback(ZoomValidateValue)); ////// /// public static readonly DependencyProperty MinZoomProperty = DependencyProperty.Register( "MinZoom", typeof(double), typeof(FlowDocumentPageViewer), new FrameworkPropertyMetadata( 80d, new PropertyChangedCallback(MinZoomChanged)), new ValidateValueCallback(ZoomValidateValue)); ////// /// public static readonly DependencyProperty ZoomIncrementProperty = DependencyProperty.Register( "ZoomIncrement", typeof(double), typeof(FlowDocumentPageViewer), new FrameworkPropertyMetadata(10d), new ValidateValueCallback(ZoomValidateValue)); ////// /// protected static readonly DependencyPropertyKey CanIncreaseZoomPropertyKey = DependencyProperty.RegisterReadOnly( "CanIncreaseZoom", typeof(bool), typeof(FlowDocumentPageViewer), new FrameworkPropertyMetadata(true)); ////// /// public static readonly DependencyProperty CanIncreaseZoomProperty = CanIncreaseZoomPropertyKey.DependencyProperty; ////// /// protected static readonly DependencyPropertyKey CanDecreaseZoomPropertyKey = DependencyProperty.RegisterReadOnly( "CanDecreaseZoom", typeof(bool), typeof(FlowDocumentPageViewer), new FrameworkPropertyMetadata(true)); ////// /// public static readonly DependencyProperty CanDecreaseZoomProperty = CanDecreaseZoomPropertyKey.DependencyProperty; #endregion Public Dynamic Properties #endregion Public Properties //------------------------------------------------------------------- // // Protected Methods // //-------------------------------------------------------------------- #region Protected Methods ////// /// Creates AutomationPeer ( protected override AutomationPeer OnCreateAutomationPeer() { return new FlowDocumentPageViewerAutomationPeer(this); } ///) /// /// 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) { // Esc -- Close FindToolBar if (e.Key == Key.Escape) { if (FindToolBar != null) { ToggleFindToolBar(false); e.Handled = true; } } // F3 -- Invoke Find if (e.Key == 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; } } // If not handled, do default handling. if (!e.Handled) { base.OnKeyDown(e); } } ////// An event reporting a mouse wheel rotation. /// protected override void OnMouseWheel(MouseWheelEventArgs e) { // [Mouse Wheel + Control] - zooming // [Mouse Wheel] - page navigation if (e.Delta != 0) { if ((Keyboard.Modifiers & ModifierKeys.Control) == ModifierKeys.Control) { if (e.Delta > 0) { IncreaseZoom(); } else { DecreaseZoom(); } } else { if (e.Delta > 0) { PreviousPage(); } else { NextPage(); } } e.Handled = false; } // If not handled, do default handling. if (!e.Handled) { base.OnMouseWheel(e); } } ////// Called when ContextMenuOpening is raised on this element. /// /// Event arguments protected override void OnContextMenuOpening(ContextMenuEventArgs e) { base.OnContextMenuOpening(e); DocumentViewerHelper.OnContextMenuOpening(Document as FlowDocument, this, e); } ////// Called when the PageViews collection is modified; this occurs when GetPageViewsCollection /// returns True or if the control's template is modified. /// protected override void OnPageViewsChanged() { // Change of DocumentPageView collection resets current ContentPosition. // This position is updated when layout process is done. _contentPosition = null; // Apply zoom value to new DocumentPageViews ApplyZoom(); base.OnPageViewsChanged(); } ////// Called when the Document property is changed. /// protected override void OnDocumentChanged() { // Document change resets current ContentPosition. _contentPosition = null; // _oldDocument is cached from previous document changed notification. if (_oldDocument != null) { DynamicDocumentPaginator dynamicDocumentPaginator = _oldDocument.DocumentPaginator as DynamicDocumentPaginator; if (dynamicDocumentPaginator != null) { dynamicDocumentPaginator.GetPageNumberCompleted -= new GetPageNumberCompletedEventHandler(HandleGetPageNumberCompleted); } FlowDocumentPaginator flowDocumentPaginator = _oldDocument.DocumentPaginator as FlowDocumentPaginator; if (flowDocumentPaginator != null) { flowDocumentPaginator.BreakRecordTableInvalidated -= new BreakRecordTableInvalidatedEventHandler(HandleAllBreakRecordsInvalidated); } } base.OnDocumentChanged(); _oldDocument = Document; // Validate the new document type if (Document != null && !(Document is FlowDocument)) { // Undo new document assignment. Document = null; // Throw exception. throw new NotSupportedException(SR.Get(SRID.FlowDocumentPageViewerOnlySupportsFlowDocument)); } if(Document != null) { DynamicDocumentPaginator dynamicDocumentPaginator = Document.DocumentPaginator as DynamicDocumentPaginator; if (dynamicDocumentPaginator != null) { dynamicDocumentPaginator.GetPageNumberCompleted += new GetPageNumberCompletedEventHandler(HandleGetPageNumberCompleted); } FlowDocumentPaginator flowDocumentPaginator = Document.DocumentPaginator as FlowDocumentPaginator; if (flowDocumentPaginator != null) { flowDocumentPaginator.BreakRecordTableInvalidated += new BreakRecordTableInvalidatedEventHandler(HandleAllBreakRecordsInvalidated); } } // Update the toolbar with our current document state. if (!CanShowFindToolBar) { // Disable FindToolBar, if the content does not support it. if (FindToolBar != null) { ToggleFindToolBar(false); } } // Go to the first page of new content. OnGoToPageCommand(1); } ////// Called when print has been completed. /// protected virtual void OnPrintCompleted() { ClearPrintingState(); } ////// Handler for the PreviousPage command. /// protected override void OnPreviousPageCommand() { if (this.CanGoToPreviousPage) { // Page navigation resets current ContentPosition. // This position is updated when layout process is done. _contentPosition = null; base.OnPreviousPageCommand(); } } ////// Handler for the NextPage command. /// protected override void OnNextPageCommand() { if (this.CanGoToNextPage) { // Page navigation resets current ContentPosition. // This position is updated when layout process is done. _contentPosition = null; base.OnNextPageCommand(); } } ////// Handler for the FirstPage command. /// protected override void OnFirstPageCommand() { if (this.CanGoToPreviousPage) { // Page navigation resets current ContentPosition. // This position is updated when layout process is done. _contentPosition = null; base.OnFirstPageCommand(); } } ////// Handler for the LastPage command. /// protected override void OnLastPageCommand() { if (this.CanGoToNextPage) { // Page navigation resets current ContentPosition. // This position is updated when layout process is done. _contentPosition = null; base.OnLastPageCommand(); } } ////// Handler for the GoToPage command. /// protected override void OnGoToPageCommand(int pageNumber) { if (CanGoToPage(pageNumber) && this.MasterPageNumber != pageNumber) { // Page navigation resets current ContentPosition. // This position is updated when layout process is done. _contentPosition = null; base.OnGoToPageCommand(pageNumber); } } ////// 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 override void OnPrintCommand() { #if !DONOTREFPRINTINGASMMETA XpsDocumentWriter docWriter; PrintDocumentImageableArea ia = null; FlowDocumentPaginator paginator; FlowDocument document = Document as FlowDocument; Thickness pagePadding; // Only one printing job is allowed. if (_printingState != null) { return; } // If the document is FlowDocument, do custom printing. Otherwise go through default path. if (document != null) { // Show print dialog. docWriter = PrintQueue.CreateXpsDocumentWriter(ref ia); if (docWriter != null && ia != null) { // Store the current state of the document in the PrintingState paginator = ((IDocumentPaginatorSource)document).DocumentPaginator as FlowDocumentPaginator; _printingState = new FlowDocumentPrintingState(); _printingState.XpsDocumentWriter = docWriter; _printingState.PageSize = paginator.PageSize; _printingState.PagePadding = document.PagePadding; _printingState.IsSelectionEnabled = IsSelectionEnabled; // Since _printingState value is used to determine CanExecute state, we must invalidate that state. CommandManager.InvalidateRequerySuggested(); // Register for XpsDocumentWriter events. docWriter.WritingCompleted += new WritingCompletedEventHandler(HandlePrintCompleted); docWriter.WritingCancelled += new WritingCancelledEventHandler(HandlePrintCancelled); // Add PreviewCanExecute handler to have a chance to disable UI Commands during printing. CommandManager.AddPreviewCanExecuteHandler(this, new CanExecuteRoutedEventHandler(PreviewCanExecuteRoutedEventHandler)); // Suspend layout on DocumentPageViews. ReadOnlyCollectionpageViews = PageViews; for (int index = 0; index < pageViews.Count; index++) { pageViews[index].SuspendLayout(); } // Disable TextSelection, if currently enabled. if (IsSelectionEnabled) { IsSelectionEnabled = false; } // Change the PageSize and PagePadding for the document to match the CanvasSize for the printer device. paginator.PageSize = new Size(ia.MediaSizeWidth, ia.MediaSizeHeight); pagePadding = document.ComputePageMargin(); document.PagePadding = new Thickness( Math.Max(ia.OriginWidth, pagePadding.Left), Math.Max(ia.OriginHeight, pagePadding.Top), Math.Max(ia.MediaSizeWidth - (ia.OriginWidth + ia.ExtentWidth), pagePadding.Right), Math.Max(ia.MediaSizeHeight - (ia.OriginHeight + ia.ExtentHeight), pagePadding.Bottom)); // Send DocumentPaginator to the printer. docWriter.WriteAsync(paginator); } } else { base.OnPrintCommand(); } #endif // DONOTREFPRINTINGASMMETA } /// /// Handler for the CancelPrint command. /// protected override void OnCancelPrintCommand() { #if !DONOTREFPRINTINGASMMETA if (_printingState != null) { _printingState.XpsDocumentWriter.CancelAsync(); } else { base.OnCancelPrintCommand(); } #endif // DONOTREFPRINTINGASMMETA } ////// Handler for the IncreaseZoom command. /// protected virtual void OnIncreaseZoomCommand() { // If can zoom in, increase zoom by the zoom increment value. if (this.CanIncreaseZoom) { Zoom = Math.Min(Zoom + ZoomIncrement, MaxZoom); } } ////// Handler for the DecreaseZoom command. /// protected virtual void OnDecreaseZoomCommand() { // If can zoom out, decrease zoom by the zoom increment value. if (this.CanDecreaseZoom) { Zoom = Math.Max(Zoom - ZoomIncrement, MinZoom); } } #endregion Protected Methods //------------------------------------------------------------------- // // Internal Methods // //------------------------------------------------------------------- #region Internal Methods ////// Allows FrameworkElement to augment the EventRoute. /// internal override bool BuildRouteCore(EventRoute route, RoutedEventArgs args) { // If FlowDocumentPageViewer is used as embedded viewer (in FlowDocumentReader), // it is not part of logical tree, so default logic in FE to re-add logical // tree from branched node does not work here. // But before FlowDocumentPageViewer is added to the event route, logical // ancestors up to Document need to be added to the route. Otherwise // content will not have a chance to react to events first. // This breaks navigation cursor management logic, because TextEditor attached // to FlowDocumentPageViewer handles those events first. DependencyObject document = this.Document as DependencyObject; if (document != null && LogicalTreeHelper.GetParent(document) != this) { DependencyObject branchNode = route.PeekBranchNode() as DependencyObject; if (branchNode != null && DocumentViewerHelper.IsLogicalDescendent(branchNode, document)) { // Add intermediate ContentElements to the route. FrameworkElement.AddIntermediateElementsToRoute( LogicalTreeHelper.GetParent(document), route, args, LogicalTreeHelper.GetParent(branchNode)); } } return base.BuildRouteCore(route, args); } ////// Brings specified point into view. /// /// Point in the viewer's coordinate system. ///Whether operation is pending or not. ////// It is guaranteed that Point is not over any existing pages. /// internal bool BringPointIntoView(Point point) { int index; Rect[] pageRects; Rect pageRect; ReadOnlyCollectionpageViews = this.PageViews; bool bringIntoViewPending = false; if (pageViews.Count > 0) { // Calculate rectangles for all pages. pageRects = new Rect[pageViews.Count]; for (index = 0; index < pageViews.Count; index++) { pageRect = new Rect(pageViews[index].RenderSize); pageRect = pageViews[index].TransformToAncestor(this).TransformBounds(pageRect); pageRects[index] = pageRect; } // Try to find exact hit for (index = 0; index < pageRects.Length; index++) { if (pageRects[index].Contains(point)) { break; } } if (index >= pageRects.Length) { // Union all rects. pageRect = pageRects[0]; for (index = 1; index < pageRects.Length; index++) { pageRect.Union(pageRects[index]); } // if (DoubleUtil.LessThan(point.X, pageRect.Left)) { if (this.CanGoToPreviousPage) { OnPreviousPageCommand(); bringIntoViewPending = true; } } else if (DoubleUtil.GreaterThan(point.X, pageRect.Right)) { if (this.CanGoToNextPage) { OnNextPageCommand(); bringIntoViewPending = true; } } else if (DoubleUtil.LessThan(point.Y, pageRect.Top)) { if (this.CanGoToPreviousPage) { OnPreviousPageCommand(); bringIntoViewPending = true; } } else if (DoubleUtil.GreaterThan(point.Y, pageRect.Bottom)) { if (this.CanGoToNextPage) { OnNextPageCommand(); bringIntoViewPending = true; } } } } return bringIntoViewPending; } /// /// Bring specified content position into view. /// internal object BringContentPositionIntoView(object arg) { PrivateBringContentPositionIntoView(arg, false); return null; } #endregion Internal Methods //------------------------------------------------------------------- // // Internal Properties // //-------------------------------------------------------------------- #region Internal Properties ////// ContentPosition representing currently viewed content. /// internal ContentPosition ContentPosition { get { return _contentPosition; } } ////// Whether FindToolBar can be enabled. /// internal bool CanShowFindToolBar { get { return (_findToolBarHost != null && this.Document != null && this.TextEditor != null); } } ////// Whether currently printing the content. /// internal bool IsPrinting { get { return (_printingState != null); } } #endregion Internal Properties //------------------------------------------------------------------- // // Private Methods // //-------------------------------------------------------------------- #region Private Methods ////// Handler for LayoutUpdated event raised by the LayoutSystem. /// private void HandleLayoutUpdated(object sender, EventArgs e) { DocumentPageView masterPageView; DynamicDocumentPaginator documentPaginator; // Ignore LayoutUpdated during printing. if (this.Document != null && _printingState == null) { documentPaginator = this.Document.DocumentPaginator as DynamicDocumentPaginator; if (documentPaginator != null) { // Update ContentPosition, if not cached. if (_contentPosition == null) { masterPageView = GetMasterPageView(); if (masterPageView != null && masterPageView.DocumentPage != null) { _contentPosition = documentPaginator.GetPagePosition(masterPageView.DocumentPage); } if (_contentPosition == ContentPosition.Missing) { _contentPosition = null; } } // Otherwise bring this position into view. else { PrivateBringContentPositionIntoView(_contentPosition, true); } } } } ////// Handler for GetPageNumberCompleted event raised by the Document. /// private void HandleGetPageNumberCompleted(object sender, GetPageNumberCompletedEventArgs e) { if (Document != null && sender == Document.DocumentPaginator && e != null) { if (!e.Cancelled && e.Error == null && e.UserState == _bringContentPositionIntoViewToken) { int newMasterPageNumber = e.PageNumber + 1; OnGoToPageCommand(newMasterPageNumber); } } } ////// Handler for BreakRecordTableInvalidated event raised by the Paginator. /// private void HandleAllBreakRecordsInvalidated(object sender, EventArgs e) { ReadOnlyCollectionpageViews = PageViews; for (int index = 0; index < pageViews.Count; index++) { pageViews[index].DuplicateVisual(); } } /// /// Handle the case when the position is no longer valid for the current document, conservatively returns true if /// is uknown. /// private bool IsValidContentPositionForDocument(IDocumentPaginatorSource document, ContentPosition contentPosition) { FlowDocument flowDocument = document as FlowDocument; TextPointer textPointer = contentPosition as TextPointer; if(flowDocument != null && textPointer != null) { return flowDocument.ContentStart.TextContainer == textPointer.TextContainer; } return true; } ////// Bring specified content position into view. (If async, cancel any previous async request to bring into view.) /// private void PrivateBringContentPositionIntoView(object arg, bool isAsyncRequest) { ContentPosition contentPosition = arg as ContentPosition; if (contentPosition != null && Document != null) { DynamicDocumentPaginator documentPaginator = this.Document.DocumentPaginator as DynamicDocumentPaginator; if (documentPaginator != null && IsValidContentPositionForDocument(Document, contentPosition)) { documentPaginator.CancelAsync(_bringContentPositionIntoViewToken); if(isAsyncRequest) { documentPaginator.GetPageNumberAsync(contentPosition, _bringContentPositionIntoViewToken); } else { int newMasterPageNumber = documentPaginator.GetPageNumber(contentPosition) + 1; OnGoToPageCommand(newMasterPageNumber); } _contentPosition = contentPosition; } } } ////// Called when WritingCompleted event raised by a DocumentWriter (during printing). /// /// Sender of the event. /// Event arguments. private void HandlePrintCompleted(object sender, WritingCompletedEventArgs e) { OnPrintCompleted(); } ////// Called when WritingCancelled event raised by a DocumentWriter (during printing). /// /// Sender of the event. /// Event arguments. private void HandlePrintCancelled(object sender, WritingCancelledEventArgs e) { ClearPrintingState(); } ////// Clears printing state. /// private void ClearPrintingState() { #if !DONOTREFPRINTINGASMMETA if (_printingState != null) { // Resume layout on DocumentPageViews. ReadOnlyCollectionpageViews = PageViews; for (int index = 0; index < pageViews.Count; index++) { pageViews[index].ResumeLayout(); } // Enable TextSelection, if it was previously enabled. if (_printingState.IsSelectionEnabled) { IsSelectionEnabled = true; } // Remove PreviewCanExecute handler (added when Print command was executed). CommandManager.RemovePreviewCanExecuteHandler(this, new CanExecuteRoutedEventHandler(PreviewCanExecuteRoutedEventHandler)); // Unregister for XpsDocumentWriter events. _printingState.XpsDocumentWriter.WritingCompleted -= new WritingCompletedEventHandler(HandlePrintCompleted); _printingState.XpsDocumentWriter.WritingCancelled -= new WritingCancelledEventHandler(HandlePrintCancelled); // Restore old page metrics on FlowDocument. ((FlowDocument)Document).PagePadding = _printingState.PagePadding; Document.DocumentPaginator.PageSize = _printingState.PageSize; _printingState = null; // Since _documentWriter value is used to determine CanExecute state, we must invalidate that state. CommandManager.InvalidateRequerySuggested(); } #endif // DONOTREFPRINTINGASMMETA } /// /// Apply zoom value to all existing DocumentPageViews. /// private void ApplyZoom() { int index; ReadOnlyCollectionpageViews; // Apply zoom value to all DocumentPageViews. pageViews = this.PageViews; for (index = 0; index < pageViews.Count; index++) { pageViews[index].SetPageZoom(Zoom / 100.0); } } /// /// Enables/disables the FindToolbar. /// /// Whether to enable/disable FindToolBar. private void ToggleFindToolBar(bool enable) { Invariant.Assert(enable == (FindToolBar == null)); DocumentViewerHelper.ToggleFindToolBar(_findToolBarHost, new EventHandler(OnFindInvoked), enable); } ////// 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; int newMasterPageNumber; FindToolBar findToolBar = FindToolBar; if (findToolBar != null && this.TextEditor != null) { // In order to show current text selection TextEditor requires Focus to be set on the UIScope. // If there embedded controls, it may happen that embedded control currently has focus and find // was invoked through hotkeys. To support this case we manually move focus to the appropriate element. Focus(); findResult = Find(findToolBar); // If we found something, bring it into the view. Otherwise alert the user. if ((findResult != null) && (!findResult.IsEmpty)) { if (findResult.Start is ContentPosition) { // Bring find result into view. Set also _contentPosition to the beginning of the // result, so it is visible during resizing. _contentPosition = (ContentPosition)findResult.Start; newMasterPageNumber = ((DynamicDocumentPaginator)this.Document.DocumentPaginator).GetPageNumber(_contentPosition) + 1; OnBringIntoView(this, Rect.Empty, newMasterPageNumber); } } else { DocumentViewerHelper.ShowFindUnsuccessfulMessage(findToolBar); } } } ////// The Zoom has changed and needs to be updated. /// private void ZoomChanged(double oldValue, double newValue) { if (!DoubleUtil.AreClose(oldValue, newValue)) { UpdateCanIncreaseZoom(); UpdateCanDecreaseZoom(); // Changes to Zoom may potentially cause content reflowing. // In such case Paginator will notify DocumentViewerBase // about content changes through PagesChanged event and viewer // will invalidate appropriate properties. // Hence there is no need to invalidate any properties on // DocumentViewerBase right now. ApplyZoom(); } } ////// Update CanIncreaseZoom property. /// private void UpdateCanIncreaseZoom() { SetValue(CanIncreaseZoomPropertyKey, BooleanBoxes.Box(DoubleUtil.GreaterThan(MaxZoom, Zoom))); } ////// Update CanDecreaseZoom property. /// private void UpdateCanDecreaseZoom() { SetValue(CanDecreaseZoomPropertyKey, BooleanBoxes.Box(DoubleUtil.LessThan(MinZoom, Zoom))); } ////// The MaxZoom has changed and needs to be updated. /// private void MaxZoomChanged(double oldValue, double newValue) { CoerceValue(ZoomProperty); UpdateCanIncreaseZoom(); } ////// The MinZoom has changed and needs to be updated. /// private void MinZoomChanged(double oldValue, double newValue) { CoerceValue(MaxZoomProperty); CoerceValue(ZoomProperty); UpdateCanIncreaseZoom(); UpdateCanDecreaseZoom(); } #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: ApplicationCommands.Find CommandHelpers.RegisterCommandHandler(typeof(FlowDocumentPageViewer), ApplicationCommands.Find, executedHandler, canExecuteHandler); // Command: NavigationCommands.IncreaseZoom CommandHelpers.RegisterCommandHandler(typeof(FlowDocumentPageViewer), NavigationCommands.IncreaseZoom, executedHandler, canExecuteHandler, new KeyGesture(Key.OemPlus, ModifierKeys.Control)); // Command: NavigationCommands.DecreaseZoom CommandHelpers.RegisterCommandHandler(typeof(FlowDocumentPageViewer), NavigationCommands.DecreaseZoom, executedHandler, canExecuteHandler, new KeyGesture(Key.OemMinus, ModifierKeys.Control)); // Register input bindings CommandManager.RegisterClassInputBinding(typeof(FlowDocumentPageViewer), new InputBinding(NavigationCommands.PreviousPage, new KeyGesture(Key.Left))); CommandManager.RegisterClassInputBinding(typeof(FlowDocumentPageViewer), new InputBinding(NavigationCommands.PreviousPage, new KeyGesture(Key.Up))); CommandManager.RegisterClassInputBinding(typeof(FlowDocumentPageViewer), new InputBinding(NavigationCommands.PreviousPage, new KeyGesture(Key.PageUp))); CommandManager.RegisterClassInputBinding(typeof(FlowDocumentPageViewer), new InputBinding(NavigationCommands.NextPage, new KeyGesture(Key.Right))); CommandManager.RegisterClassInputBinding(typeof(FlowDocumentPageViewer), new InputBinding(NavigationCommands.NextPage, new KeyGesture(Key.Down))); CommandManager.RegisterClassInputBinding(typeof(FlowDocumentPageViewer), new InputBinding(NavigationCommands.NextPage, new KeyGesture(Key.PageDown))); CommandManager.RegisterClassInputBinding(typeof(FlowDocumentPageViewer), new InputBinding(NavigationCommands.FirstPage, new KeyGesture(Key.Home))); CommandManager.RegisterClassInputBinding(typeof(FlowDocumentPageViewer), new InputBinding(NavigationCommands.FirstPage, new KeyGesture(Key.Home, ModifierKeys.Control))); CommandManager.RegisterClassInputBinding(typeof(FlowDocumentPageViewer), new InputBinding(NavigationCommands.LastPage, new KeyGesture(Key.End))); CommandManager.RegisterClassInputBinding(typeof(FlowDocumentPageViewer), new InputBinding(NavigationCommands.LastPage, new KeyGesture(Key.End, ModifierKeys.Control))); } ////// Central handler for CanExecuteRouted events fired by Commands directed at FlowDocumentPageViewer. /// /// The target of this Command, expected to be FlowDocumentPageViewer /// The event arguments for this event. private static void CanExecuteRoutedEventHandler(object target, CanExecuteRoutedEventArgs args) { FlowDocumentPageViewer fdpv = target as FlowDocumentPageViewer; Invariant.Assert(fdpv != null, "Target of QueryEnabledEvent must be FlowDocumentPageViewer."); Invariant.Assert(args != null, "args cannot be null."); // DocumentViewerBase is capable of execution of the majority of its commands. // Special rules: // a) Find command is enabled when Document is attached and printing is not in progress. if (args.Command == ApplicationCommands.Find) { args.CanExecute = fdpv.CanShowFindToolBar; } else { args.CanExecute = true; } } ////// Central handler for all ExecutedRouted events fired by Commands directed at FlowDocumentPageViewer. /// /// The target of this Command, expected to be FlowDocumentPageViewer. /// The event arguments associated with this event. private static void ExecutedRoutedEventHandler(object target, ExecutedRoutedEventArgs args) { FlowDocumentPageViewer fdpv = target as FlowDocumentPageViewer; Invariant.Assert(fdpv != null, "Target of ExecuteEvent must be FlowDocumentPageViewer."); Invariant.Assert(args != null, "args cannot be null."); // Now we execute the method corresponding to the Command that fired this event; // each Command has its own protected virtual method that performs the operation // corresponding to the Command. if (args.Command == NavigationCommands.IncreaseZoom) { fdpv.OnIncreaseZoomCommand(); } else if (args.Command == NavigationCommands.DecreaseZoom) { fdpv.OnDecreaseZoomCommand(); } else if (args.Command == ApplicationCommands.Find) { fdpv.OnFindCommand(); } else { Invariant.Assert(false, "Command not handled in ExecutedRoutedEventHandler."); } } ////// Disable commands on DocumentViewerBase when this printing is in progress. /// private void PreviewCanExecuteRoutedEventHandler(object target, CanExecuteRoutedEventArgs args) { FlowDocumentPageViewer fdpv = target as FlowDocumentPageViewer; Invariant.Assert(fdpv != null, "Target of PreviewCanExecuteRoutedEventHandler must be FlowDocumentPageViewer."); Invariant.Assert(args != null, "args cannot be null."); // Disable UI commands, if printing is in progress. if (fdpv._printingState != null) { if (args.Command != ApplicationCommands.CancelPrint) { args.CanExecute = false; args.Handled = true; } } } ////// Called when a key event occurs. /// private static void KeyDownHandler(object sender, KeyEventArgs e) { DocumentViewerHelper.KeyDownHelper(e, ((FlowDocumentPageViewer)sender)._findToolBarHost); } #endregion Commands #region Static Methods ////// Coerce the value for Zoom property. /// private static object CoerceZoom(DependencyObject d, object value) { Invariant.Assert(d != null && d is FlowDocumentPageViewer); double maxZoom, minZoom; FlowDocumentPageViewer v = (FlowDocumentPageViewer) d; double zoom = (double)value; maxZoom = v.MaxZoom; if (DoubleUtil.LessThan(maxZoom, zoom)) { return maxZoom; } minZoom = v.MinZoom; if (DoubleUtil.GreaterThan(minZoom, zoom)) { return minZoom; } return value; } ////// Coerce the value for MaxZoom property. /// private static object CoerceMaxZoom(DependencyObject d, object value) { Invariant.Assert(d != null && d is FlowDocumentPageViewer); FlowDocumentPageViewer v = (FlowDocumentPageViewer) d; double minZoom = v.MinZoom; if (DoubleUtil.LessThan((double)value, minZoom)) { return minZoom; } return value; } ////// The Zoom has changed and needs to be updated. /// private static void ZoomChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { Invariant.Assert(d != null && d is FlowDocumentPageViewer); ((FlowDocumentPageViewer)d).ZoomChanged((double) e.OldValue, (double) e.NewValue); } ////// The MaxZoom has changed and needs to be updated. /// private static void MaxZoomChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { Invariant.Assert(d != null && d is FlowDocumentPageViewer); ((FlowDocumentPageViewer)d).MaxZoomChanged((double) e.OldValue, (double) e.NewValue); } ////// The MinZoom has changed and needs to be updated. /// private static void MinZoomChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { Invariant.Assert(d != null && d is FlowDocumentPageViewer); ((FlowDocumentPageViewer)d).MinZoomChanged((double) e.OldValue, (double) e.NewValue); } ////// 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)); } #endregion Static Methods #endregion Private Methods //-------------------------------------------------------------------- // // Private Properties // //------------------------------------------------------------------- #region Private Properties ////// Returns FindToolBar, if enabled. /// private FindToolBar FindToolBar { get { return (_findToolBarHost != null) ? _findToolBarHost.Child as FindToolBar : null; } } #endregion Private Properties //-------------------------------------------------------------------- // // Private Fields // //------------------------------------------------------------------- #region Private Fields private Decorator _findToolBarHost; // Host for FindToolbar private ContentPosition _contentPosition; // Current position to be maintained during zooming and resizing. private FlowDocumentPrintingState _printingState; // Printing state private IDocumentPaginatorSource _oldDocument; // IDocumentPaginatorSource representing Document. Cached separately from DocumentViewerBase // due to lifetime issues. private object _bringContentPositionIntoViewToken = new object(); // Bring content position into view user state private const string _findToolBarHostTemplateName = "PART_FindToolBarHost"; //Name for the Find Toolbar host. #endregion Private Fields //------------------------------------------------------------------- // // IJournalState Members // //------------------------------------------------------------------- #region IJournalState Members [Serializable] private class JournalState : CustomJournalStateInternal { public JournalState(int contentPosition, LogicalDirection contentPositionDirection, double zoom) { ContentPosition = contentPosition; ContentPositionDirection = contentPositionDirection; Zoom = zoom; } public int ContentPosition; public LogicalDirection ContentPositionDirection; public double Zoom; } ////// CustomJournalStateInternal IJournalState.GetJournalState(JournalReason journalReason) { int cp = -1; LogicalDirection cpDirection = LogicalDirection.Forward; TextPointer contentPosition = ContentPosition as TextPointer; if (contentPosition != null) { cp = contentPosition.Offset; cpDirection = contentPosition.LogicalDirection; } return new JournalState(cp, cpDirection, Zoom); } ////// /// void IJournalState.RestoreJournalState(CustomJournalStateInternal state) { JournalState viewerState = state as JournalState; if (state != null) { Zoom = viewerState.Zoom; if (viewerState.ContentPosition != -1) { FlowDocument document = Document as FlowDocument; if (document != null) { TextContainer textContainer = document.StructuralCache.TextContainer; if (viewerState.ContentPosition <= textContainer.SymbolCount) { TextPointer contentPosition = textContainer.CreatePointerAtOffset(viewerState.ContentPosition, viewerState.ContentPositionDirection); // This need be called because the UI may not be ready when Contentposition is set. Dispatcher.BeginInvoke(DispatcherPriority.Input, new DispatcherOperationCallback(BringContentPositionIntoView), contentPosition); } } } } } #endregion IJournalState Members //-------------------------------------------------------------------- // // DTypeThemeStyleKey // //------------------------------------------------------------------- #region DTypeThemeStyleKey ////// /// Returns the DependencyObjectType for the registered ThemeStyleKey's default /// value. Controls will override this method to return approriate types /// internal override DependencyObjectType DTypeThemeStyleKey { get { return _dType; } } private static DependencyObjectType _dType; #endregion DTypeThemeStyleKey } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved. //---------------------------------------------------------------------------- // // Copyright (C) Microsoft Corporation. All rights reserved. // // File: FlowDocumentPageViewer.cs // // Description: FlowDocumentPageViewer provides a simple user experience for viewing // one page of content at a time. The experience is optimized for // FlowDocument scenarios, however any IDocumentPaginatorSource // can be viewed using this control. // //--------------------------------------------------------------------------- using System.Collections.ObjectModel; // ReadOnlyCollectionusing System.Printing; // WritingCompletedEventArgs using System.Windows.Automation.Peers; // AutomationPeer using System.Windows.Documents; // IDocumentPaginatorSouce, ... using System.Windows.Documents.Serialization; // WritingCompletedEventArgs using System.Windows.Input; // UICommand using System.Windows.Media; // VisualTreeHelper using System.Windows.Controls.Primitives; // DocumentViewerBase, DocumentPageView using System.Windows.Xps; // XpsDocumentWriter using System.Windows.Threading; using MS.Internal; // Invariant, DoubleUtil using MS.Internal.Commands; // CommandHelpers using MS.Internal.Documents; // FindToolBar using MS.Internal.KnownBoxes; // BooleanBoxes using MS.Internal.PresentationFramework; // SecurityHelper using MS.Internal.AppModel; // IJournalState using System.Security; // SecurityCritical, SecurityTreatAsSafe namespace System.Windows.Controls { /// /// FlowDocumentPageViewer provides a simple user experience for viewing one page /// of content at a time. The experience is optimized for FlowDocument scenarios, /// however any IDocumentPaginatorSource can be viewed using this control. /// [TemplatePart(Name = "PART_FindToolBarHost", Type = typeof(Decorator))] public class FlowDocumentPageViewer : DocumentViewerBase, IJournalState { //------------------------------------------------------------------- // // Constructors // //------------------------------------------------------------------- #region Constructors ////// Initializes class-wide settings. /// static FlowDocumentPageViewer() { DefaultStyleKeyProperty.OverrideMetadata( typeof(FlowDocumentPageViewer), new FrameworkPropertyMetadata(new ComponentResourceKey(typeof(PresentationUIStyleResources), "PUIFlowDocumentPageViewer"))); _dType = DependencyObjectType.FromSystemTypeInternal(typeof(FlowDocumentPageViewer)); // Create our CommandBindings CreateCommandBindings(); EventManager.RegisterClassHandler(typeof(FlowDocumentPageViewer), Keyboard.KeyDownEvent, new KeyEventHandler(KeyDownHandler), true); } ////// Instantiates a new instance of a FlowDocumentPageViewer. /// public FlowDocumentPageViewer() : base() { this.LayoutUpdated += new EventHandler(HandleLayoutUpdated); } #endregion Constructors //-------------------------------------------------------------------- // // Public Methods // //------------------------------------------------------------------- #region Public Methods ////// Called when the Template's tree has been generated /// ///Whether Visuals were added to the tree. public override void OnApplyTemplate() { base.OnApplyTemplate(); // 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; } ////// Increases the current zoom. /// public void IncreaseZoom() { OnIncreaseZoomCommand(); } ////// Decreases the current zoom. /// public void DecreaseZoom() { OnDecreaseZoomCommand(); } ////// Invokes the Find Toolbar. This is analogous to the ApplicationCommands.Find. /// public void Find() { OnFindCommand(); } #endregion Public Methods //-------------------------------------------------------------------- // // Public Properties // //-------------------------------------------------------------------- #region Public Properties ////// Text Selection (readonly) /// public TextSelection Selection { get { ITextSelection textSelection = null; FlowDocument flowDocument = Document as FlowDocument; if (flowDocument != null) { textSelection = flowDocument.StructuralCache.TextContainer.TextSelection; } return textSelection as TextSelection; } } ////// The Zoom applied to all pages; this value is 100-based. /// public double Zoom { get { return (double) GetValue(ZoomProperty); } set { SetValue(ZoomProperty, value); } } ////// The maximum allowed value of the Zoom property. /// public double MaxZoom { get { return (double) GetValue(MaxZoomProperty); } set { SetValue(MaxZoomProperty, value); } } ////// The minimum allowed value of the Zoom property. /// public double MinZoom { get { return (double) GetValue(MinZoomProperty); } set { SetValue(MinZoomProperty, value); } } ////// The amount the Zoom property is incremented or decremented when /// the IncreaseZoom or DecreaseZoom command is executed. /// public double ZoomIncrement { get { return (double) GetValue(ZoomIncrementProperty); } set { SetValue(ZoomIncrementProperty, value); } } ////// Whether the viewer can increase the current zoom. /// public virtual bool CanIncreaseZoom { get { return (bool) GetValue(CanIncreaseZoomProperty); } } ////// Whether the viewer can decrease the current zoom. /// public virtual bool CanDecreaseZoom { get { return (bool) GetValue(CanDecreaseZoomProperty); } } #region Public Dynamic Properties ////// public static readonly DependencyProperty ZoomProperty = DependencyProperty.Register( "Zoom", typeof(double), typeof(FlowDocumentPageViewer), new FrameworkPropertyMetadata( 100d, new PropertyChangedCallback(ZoomChanged), new CoerceValueCallback(CoerceZoom)), new ValidateValueCallback(ZoomValidateValue)); ////// /// public static readonly DependencyProperty MaxZoomProperty = DependencyProperty.Register( "MaxZoom", typeof(double), typeof(FlowDocumentPageViewer), new FrameworkPropertyMetadata( 200d, new PropertyChangedCallback(MaxZoomChanged), new CoerceValueCallback(CoerceMaxZoom)), new ValidateValueCallback(ZoomValidateValue)); ////// /// public static readonly DependencyProperty MinZoomProperty = DependencyProperty.Register( "MinZoom", typeof(double), typeof(FlowDocumentPageViewer), new FrameworkPropertyMetadata( 80d, new PropertyChangedCallback(MinZoomChanged)), new ValidateValueCallback(ZoomValidateValue)); ////// /// public static readonly DependencyProperty ZoomIncrementProperty = DependencyProperty.Register( "ZoomIncrement", typeof(double), typeof(FlowDocumentPageViewer), new FrameworkPropertyMetadata(10d), new ValidateValueCallback(ZoomValidateValue)); ////// /// protected static readonly DependencyPropertyKey CanIncreaseZoomPropertyKey = DependencyProperty.RegisterReadOnly( "CanIncreaseZoom", typeof(bool), typeof(FlowDocumentPageViewer), new FrameworkPropertyMetadata(true)); ////// /// public static readonly DependencyProperty CanIncreaseZoomProperty = CanIncreaseZoomPropertyKey.DependencyProperty; ////// /// protected static readonly DependencyPropertyKey CanDecreaseZoomPropertyKey = DependencyProperty.RegisterReadOnly( "CanDecreaseZoom", typeof(bool), typeof(FlowDocumentPageViewer), new FrameworkPropertyMetadata(true)); ////// /// public static readonly DependencyProperty CanDecreaseZoomProperty = CanDecreaseZoomPropertyKey.DependencyProperty; #endregion Public Dynamic Properties #endregion Public Properties //------------------------------------------------------------------- // // Protected Methods // //-------------------------------------------------------------------- #region Protected Methods ////// /// Creates AutomationPeer ( protected override AutomationPeer OnCreateAutomationPeer() { return new FlowDocumentPageViewerAutomationPeer(this); } ///) /// /// 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) { // Esc -- Close FindToolBar if (e.Key == Key.Escape) { if (FindToolBar != null) { ToggleFindToolBar(false); e.Handled = true; } } // F3 -- Invoke Find if (e.Key == 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; } } // If not handled, do default handling. if (!e.Handled) { base.OnKeyDown(e); } } ////// An event reporting a mouse wheel rotation. /// protected override void OnMouseWheel(MouseWheelEventArgs e) { // [Mouse Wheel + Control] - zooming // [Mouse Wheel] - page navigation if (e.Delta != 0) { if ((Keyboard.Modifiers & ModifierKeys.Control) == ModifierKeys.Control) { if (e.Delta > 0) { IncreaseZoom(); } else { DecreaseZoom(); } } else { if (e.Delta > 0) { PreviousPage(); } else { NextPage(); } } e.Handled = false; } // If not handled, do default handling. if (!e.Handled) { base.OnMouseWheel(e); } } ////// Called when ContextMenuOpening is raised on this element. /// /// Event arguments protected override void OnContextMenuOpening(ContextMenuEventArgs e) { base.OnContextMenuOpening(e); DocumentViewerHelper.OnContextMenuOpening(Document as FlowDocument, this, e); } ////// Called when the PageViews collection is modified; this occurs when GetPageViewsCollection /// returns True or if the control's template is modified. /// protected override void OnPageViewsChanged() { // Change of DocumentPageView collection resets current ContentPosition. // This position is updated when layout process is done. _contentPosition = null; // Apply zoom value to new DocumentPageViews ApplyZoom(); base.OnPageViewsChanged(); } ////// Called when the Document property is changed. /// protected override void OnDocumentChanged() { // Document change resets current ContentPosition. _contentPosition = null; // _oldDocument is cached from previous document changed notification. if (_oldDocument != null) { DynamicDocumentPaginator dynamicDocumentPaginator = _oldDocument.DocumentPaginator as DynamicDocumentPaginator; if (dynamicDocumentPaginator != null) { dynamicDocumentPaginator.GetPageNumberCompleted -= new GetPageNumberCompletedEventHandler(HandleGetPageNumberCompleted); } FlowDocumentPaginator flowDocumentPaginator = _oldDocument.DocumentPaginator as FlowDocumentPaginator; if (flowDocumentPaginator != null) { flowDocumentPaginator.BreakRecordTableInvalidated -= new BreakRecordTableInvalidatedEventHandler(HandleAllBreakRecordsInvalidated); } } base.OnDocumentChanged(); _oldDocument = Document; // Validate the new document type if (Document != null && !(Document is FlowDocument)) { // Undo new document assignment. Document = null; // Throw exception. throw new NotSupportedException(SR.Get(SRID.FlowDocumentPageViewerOnlySupportsFlowDocument)); } if(Document != null) { DynamicDocumentPaginator dynamicDocumentPaginator = Document.DocumentPaginator as DynamicDocumentPaginator; if (dynamicDocumentPaginator != null) { dynamicDocumentPaginator.GetPageNumberCompleted += new GetPageNumberCompletedEventHandler(HandleGetPageNumberCompleted); } FlowDocumentPaginator flowDocumentPaginator = Document.DocumentPaginator as FlowDocumentPaginator; if (flowDocumentPaginator != null) { flowDocumentPaginator.BreakRecordTableInvalidated += new BreakRecordTableInvalidatedEventHandler(HandleAllBreakRecordsInvalidated); } } // Update the toolbar with our current document state. if (!CanShowFindToolBar) { // Disable FindToolBar, if the content does not support it. if (FindToolBar != null) { ToggleFindToolBar(false); } } // Go to the first page of new content. OnGoToPageCommand(1); } ////// Called when print has been completed. /// protected virtual void OnPrintCompleted() { ClearPrintingState(); } ////// Handler for the PreviousPage command. /// protected override void OnPreviousPageCommand() { if (this.CanGoToPreviousPage) { // Page navigation resets current ContentPosition. // This position is updated when layout process is done. _contentPosition = null; base.OnPreviousPageCommand(); } } ////// Handler for the NextPage command. /// protected override void OnNextPageCommand() { if (this.CanGoToNextPage) { // Page navigation resets current ContentPosition. // This position is updated when layout process is done. _contentPosition = null; base.OnNextPageCommand(); } } ////// Handler for the FirstPage command. /// protected override void OnFirstPageCommand() { if (this.CanGoToPreviousPage) { // Page navigation resets current ContentPosition. // This position is updated when layout process is done. _contentPosition = null; base.OnFirstPageCommand(); } } ////// Handler for the LastPage command. /// protected override void OnLastPageCommand() { if (this.CanGoToNextPage) { // Page navigation resets current ContentPosition. // This position is updated when layout process is done. _contentPosition = null; base.OnLastPageCommand(); } } ////// Handler for the GoToPage command. /// protected override void OnGoToPageCommand(int pageNumber) { if (CanGoToPage(pageNumber) && this.MasterPageNumber != pageNumber) { // Page navigation resets current ContentPosition. // This position is updated when layout process is done. _contentPosition = null; base.OnGoToPageCommand(pageNumber); } } ////// 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 override void OnPrintCommand() { #if !DONOTREFPRINTINGASMMETA XpsDocumentWriter docWriter; PrintDocumentImageableArea ia = null; FlowDocumentPaginator paginator; FlowDocument document = Document as FlowDocument; Thickness pagePadding; // Only one printing job is allowed. if (_printingState != null) { return; } // If the document is FlowDocument, do custom printing. Otherwise go through default path. if (document != null) { // Show print dialog. docWriter = PrintQueue.CreateXpsDocumentWriter(ref ia); if (docWriter != null && ia != null) { // Store the current state of the document in the PrintingState paginator = ((IDocumentPaginatorSource)document).DocumentPaginator as FlowDocumentPaginator; _printingState = new FlowDocumentPrintingState(); _printingState.XpsDocumentWriter = docWriter; _printingState.PageSize = paginator.PageSize; _printingState.PagePadding = document.PagePadding; _printingState.IsSelectionEnabled = IsSelectionEnabled; // Since _printingState value is used to determine CanExecute state, we must invalidate that state. CommandManager.InvalidateRequerySuggested(); // Register for XpsDocumentWriter events. docWriter.WritingCompleted += new WritingCompletedEventHandler(HandlePrintCompleted); docWriter.WritingCancelled += new WritingCancelledEventHandler(HandlePrintCancelled); // Add PreviewCanExecute handler to have a chance to disable UI Commands during printing. CommandManager.AddPreviewCanExecuteHandler(this, new CanExecuteRoutedEventHandler(PreviewCanExecuteRoutedEventHandler)); // Suspend layout on DocumentPageViews. ReadOnlyCollectionpageViews = PageViews; for (int index = 0; index < pageViews.Count; index++) { pageViews[index].SuspendLayout(); } // Disable TextSelection, if currently enabled. if (IsSelectionEnabled) { IsSelectionEnabled = false; } // Change the PageSize and PagePadding for the document to match the CanvasSize for the printer device. paginator.PageSize = new Size(ia.MediaSizeWidth, ia.MediaSizeHeight); pagePadding = document.ComputePageMargin(); document.PagePadding = new Thickness( Math.Max(ia.OriginWidth, pagePadding.Left), Math.Max(ia.OriginHeight, pagePadding.Top), Math.Max(ia.MediaSizeWidth - (ia.OriginWidth + ia.ExtentWidth), pagePadding.Right), Math.Max(ia.MediaSizeHeight - (ia.OriginHeight + ia.ExtentHeight), pagePadding.Bottom)); // Send DocumentPaginator to the printer. docWriter.WriteAsync(paginator); } } else { base.OnPrintCommand(); } #endif // DONOTREFPRINTINGASMMETA } /// /// Handler for the CancelPrint command. /// protected override void OnCancelPrintCommand() { #if !DONOTREFPRINTINGASMMETA if (_printingState != null) { _printingState.XpsDocumentWriter.CancelAsync(); } else { base.OnCancelPrintCommand(); } #endif // DONOTREFPRINTINGASMMETA } ////// Handler for the IncreaseZoom command. /// protected virtual void OnIncreaseZoomCommand() { // If can zoom in, increase zoom by the zoom increment value. if (this.CanIncreaseZoom) { Zoom = Math.Min(Zoom + ZoomIncrement, MaxZoom); } } ////// Handler for the DecreaseZoom command. /// protected virtual void OnDecreaseZoomCommand() { // If can zoom out, decrease zoom by the zoom increment value. if (this.CanDecreaseZoom) { Zoom = Math.Max(Zoom - ZoomIncrement, MinZoom); } } #endregion Protected Methods //------------------------------------------------------------------- // // Internal Methods // //------------------------------------------------------------------- #region Internal Methods ////// Allows FrameworkElement to augment the EventRoute. /// internal override bool BuildRouteCore(EventRoute route, RoutedEventArgs args) { // If FlowDocumentPageViewer is used as embedded viewer (in FlowDocumentReader), // it is not part of logical tree, so default logic in FE to re-add logical // tree from branched node does not work here. // But before FlowDocumentPageViewer is added to the event route, logical // ancestors up to Document need to be added to the route. Otherwise // content will not have a chance to react to events first. // This breaks navigation cursor management logic, because TextEditor attached // to FlowDocumentPageViewer handles those events first. DependencyObject document = this.Document as DependencyObject; if (document != null && LogicalTreeHelper.GetParent(document) != this) { DependencyObject branchNode = route.PeekBranchNode() as DependencyObject; if (branchNode != null && DocumentViewerHelper.IsLogicalDescendent(branchNode, document)) { // Add intermediate ContentElements to the route. FrameworkElement.AddIntermediateElementsToRoute( LogicalTreeHelper.GetParent(document), route, args, LogicalTreeHelper.GetParent(branchNode)); } } return base.BuildRouteCore(route, args); } ////// Brings specified point into view. /// /// Point in the viewer's coordinate system. ///Whether operation is pending or not. ////// It is guaranteed that Point is not over any existing pages. /// internal bool BringPointIntoView(Point point) { int index; Rect[] pageRects; Rect pageRect; ReadOnlyCollectionpageViews = this.PageViews; bool bringIntoViewPending = false; if (pageViews.Count > 0) { // Calculate rectangles for all pages. pageRects = new Rect[pageViews.Count]; for (index = 0; index < pageViews.Count; index++) { pageRect = new Rect(pageViews[index].RenderSize); pageRect = pageViews[index].TransformToAncestor(this).TransformBounds(pageRect); pageRects[index] = pageRect; } // Try to find exact hit for (index = 0; index < pageRects.Length; index++) { if (pageRects[index].Contains(point)) { break; } } if (index >= pageRects.Length) { // Union all rects. pageRect = pageRects[0]; for (index = 1; index < pageRects.Length; index++) { pageRect.Union(pageRects[index]); } // if (DoubleUtil.LessThan(point.X, pageRect.Left)) { if (this.CanGoToPreviousPage) { OnPreviousPageCommand(); bringIntoViewPending = true; } } else if (DoubleUtil.GreaterThan(point.X, pageRect.Right)) { if (this.CanGoToNextPage) { OnNextPageCommand(); bringIntoViewPending = true; } } else if (DoubleUtil.LessThan(point.Y, pageRect.Top)) { if (this.CanGoToPreviousPage) { OnPreviousPageCommand(); bringIntoViewPending = true; } } else if (DoubleUtil.GreaterThan(point.Y, pageRect.Bottom)) { if (this.CanGoToNextPage) { OnNextPageCommand(); bringIntoViewPending = true; } } } } return bringIntoViewPending; } /// /// Bring specified content position into view. /// internal object BringContentPositionIntoView(object arg) { PrivateBringContentPositionIntoView(arg, false); return null; } #endregion Internal Methods //------------------------------------------------------------------- // // Internal Properties // //-------------------------------------------------------------------- #region Internal Properties ////// ContentPosition representing currently viewed content. /// internal ContentPosition ContentPosition { get { return _contentPosition; } } ////// Whether FindToolBar can be enabled. /// internal bool CanShowFindToolBar { get { return (_findToolBarHost != null && this.Document != null && this.TextEditor != null); } } ////// Whether currently printing the content. /// internal bool IsPrinting { get { return (_printingState != null); } } #endregion Internal Properties //------------------------------------------------------------------- // // Private Methods // //-------------------------------------------------------------------- #region Private Methods ////// Handler for LayoutUpdated event raised by the LayoutSystem. /// private void HandleLayoutUpdated(object sender, EventArgs e) { DocumentPageView masterPageView; DynamicDocumentPaginator documentPaginator; // Ignore LayoutUpdated during printing. if (this.Document != null && _printingState == null) { documentPaginator = this.Document.DocumentPaginator as DynamicDocumentPaginator; if (documentPaginator != null) { // Update ContentPosition, if not cached. if (_contentPosition == null) { masterPageView = GetMasterPageView(); if (masterPageView != null && masterPageView.DocumentPage != null) { _contentPosition = documentPaginator.GetPagePosition(masterPageView.DocumentPage); } if (_contentPosition == ContentPosition.Missing) { _contentPosition = null; } } // Otherwise bring this position into view. else { PrivateBringContentPositionIntoView(_contentPosition, true); } } } } ////// Handler for GetPageNumberCompleted event raised by the Document. /// private void HandleGetPageNumberCompleted(object sender, GetPageNumberCompletedEventArgs e) { if (Document != null && sender == Document.DocumentPaginator && e != null) { if (!e.Cancelled && e.Error == null && e.UserState == _bringContentPositionIntoViewToken) { int newMasterPageNumber = e.PageNumber + 1; OnGoToPageCommand(newMasterPageNumber); } } } ////// Handler for BreakRecordTableInvalidated event raised by the Paginator. /// private void HandleAllBreakRecordsInvalidated(object sender, EventArgs e) { ReadOnlyCollectionpageViews = PageViews; for (int index = 0; index < pageViews.Count; index++) { pageViews[index].DuplicateVisual(); } } /// /// Handle the case when the position is no longer valid for the current document, conservatively returns true if /// is uknown. /// private bool IsValidContentPositionForDocument(IDocumentPaginatorSource document, ContentPosition contentPosition) { FlowDocument flowDocument = document as FlowDocument; TextPointer textPointer = contentPosition as TextPointer; if(flowDocument != null && textPointer != null) { return flowDocument.ContentStart.TextContainer == textPointer.TextContainer; } return true; } ////// Bring specified content position into view. (If async, cancel any previous async request to bring into view.) /// private void PrivateBringContentPositionIntoView(object arg, bool isAsyncRequest) { ContentPosition contentPosition = arg as ContentPosition; if (contentPosition != null && Document != null) { DynamicDocumentPaginator documentPaginator = this.Document.DocumentPaginator as DynamicDocumentPaginator; if (documentPaginator != null && IsValidContentPositionForDocument(Document, contentPosition)) { documentPaginator.CancelAsync(_bringContentPositionIntoViewToken); if(isAsyncRequest) { documentPaginator.GetPageNumberAsync(contentPosition, _bringContentPositionIntoViewToken); } else { int newMasterPageNumber = documentPaginator.GetPageNumber(contentPosition) + 1; OnGoToPageCommand(newMasterPageNumber); } _contentPosition = contentPosition; } } } ////// Called when WritingCompleted event raised by a DocumentWriter (during printing). /// /// Sender of the event. /// Event arguments. private void HandlePrintCompleted(object sender, WritingCompletedEventArgs e) { OnPrintCompleted(); } ////// Called when WritingCancelled event raised by a DocumentWriter (during printing). /// /// Sender of the event. /// Event arguments. private void HandlePrintCancelled(object sender, WritingCancelledEventArgs e) { ClearPrintingState(); } ////// Clears printing state. /// private void ClearPrintingState() { #if !DONOTREFPRINTINGASMMETA if (_printingState != null) { // Resume layout on DocumentPageViews. ReadOnlyCollectionpageViews = PageViews; for (int index = 0; index < pageViews.Count; index++) { pageViews[index].ResumeLayout(); } // Enable TextSelection, if it was previously enabled. if (_printingState.IsSelectionEnabled) { IsSelectionEnabled = true; } // Remove PreviewCanExecute handler (added when Print command was executed). CommandManager.RemovePreviewCanExecuteHandler(this, new CanExecuteRoutedEventHandler(PreviewCanExecuteRoutedEventHandler)); // Unregister for XpsDocumentWriter events. _printingState.XpsDocumentWriter.WritingCompleted -= new WritingCompletedEventHandler(HandlePrintCompleted); _printingState.XpsDocumentWriter.WritingCancelled -= new WritingCancelledEventHandler(HandlePrintCancelled); // Restore old page metrics on FlowDocument. ((FlowDocument)Document).PagePadding = _printingState.PagePadding; Document.DocumentPaginator.PageSize = _printingState.PageSize; _printingState = null; // Since _documentWriter value is used to determine CanExecute state, we must invalidate that state. CommandManager.InvalidateRequerySuggested(); } #endif // DONOTREFPRINTINGASMMETA } /// /// Apply zoom value to all existing DocumentPageViews. /// private void ApplyZoom() { int index; ReadOnlyCollectionpageViews; // Apply zoom value to all DocumentPageViews. pageViews = this.PageViews; for (index = 0; index < pageViews.Count; index++) { pageViews[index].SetPageZoom(Zoom / 100.0); } } /// /// Enables/disables the FindToolbar. /// /// Whether to enable/disable FindToolBar. private void ToggleFindToolBar(bool enable) { Invariant.Assert(enable == (FindToolBar == null)); DocumentViewerHelper.ToggleFindToolBar(_findToolBarHost, new EventHandler(OnFindInvoked), enable); } ////// 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; int newMasterPageNumber; FindToolBar findToolBar = FindToolBar; if (findToolBar != null && this.TextEditor != null) { // In order to show current text selection TextEditor requires Focus to be set on the UIScope. // If there embedded controls, it may happen that embedded control currently has focus and find // was invoked through hotkeys. To support this case we manually move focus to the appropriate element. Focus(); findResult = Find(findToolBar); // If we found something, bring it into the view. Otherwise alert the user. if ((findResult != null) && (!findResult.IsEmpty)) { if (findResult.Start is ContentPosition) { // Bring find result into view. Set also _contentPosition to the beginning of the // result, so it is visible during resizing. _contentPosition = (ContentPosition)findResult.Start; newMasterPageNumber = ((DynamicDocumentPaginator)this.Document.DocumentPaginator).GetPageNumber(_contentPosition) + 1; OnBringIntoView(this, Rect.Empty, newMasterPageNumber); } } else { DocumentViewerHelper.ShowFindUnsuccessfulMessage(findToolBar); } } } ////// The Zoom has changed and needs to be updated. /// private void ZoomChanged(double oldValue, double newValue) { if (!DoubleUtil.AreClose(oldValue, newValue)) { UpdateCanIncreaseZoom(); UpdateCanDecreaseZoom(); // Changes to Zoom may potentially cause content reflowing. // In such case Paginator will notify DocumentViewerBase // about content changes through PagesChanged event and viewer // will invalidate appropriate properties. // Hence there is no need to invalidate any properties on // DocumentViewerBase right now. ApplyZoom(); } } ////// Update CanIncreaseZoom property. /// private void UpdateCanIncreaseZoom() { SetValue(CanIncreaseZoomPropertyKey, BooleanBoxes.Box(DoubleUtil.GreaterThan(MaxZoom, Zoom))); } ////// Update CanDecreaseZoom property. /// private void UpdateCanDecreaseZoom() { SetValue(CanDecreaseZoomPropertyKey, BooleanBoxes.Box(DoubleUtil.LessThan(MinZoom, Zoom))); } ////// The MaxZoom has changed and needs to be updated. /// private void MaxZoomChanged(double oldValue, double newValue) { CoerceValue(ZoomProperty); UpdateCanIncreaseZoom(); } ////// The MinZoom has changed and needs to be updated. /// private void MinZoomChanged(double oldValue, double newValue) { CoerceValue(MaxZoomProperty); CoerceValue(ZoomProperty); UpdateCanIncreaseZoom(); UpdateCanDecreaseZoom(); } #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: ApplicationCommands.Find CommandHelpers.RegisterCommandHandler(typeof(FlowDocumentPageViewer), ApplicationCommands.Find, executedHandler, canExecuteHandler); // Command: NavigationCommands.IncreaseZoom CommandHelpers.RegisterCommandHandler(typeof(FlowDocumentPageViewer), NavigationCommands.IncreaseZoom, executedHandler, canExecuteHandler, new KeyGesture(Key.OemPlus, ModifierKeys.Control)); // Command: NavigationCommands.DecreaseZoom CommandHelpers.RegisterCommandHandler(typeof(FlowDocumentPageViewer), NavigationCommands.DecreaseZoom, executedHandler, canExecuteHandler, new KeyGesture(Key.OemMinus, ModifierKeys.Control)); // Register input bindings CommandManager.RegisterClassInputBinding(typeof(FlowDocumentPageViewer), new InputBinding(NavigationCommands.PreviousPage, new KeyGesture(Key.Left))); CommandManager.RegisterClassInputBinding(typeof(FlowDocumentPageViewer), new InputBinding(NavigationCommands.PreviousPage, new KeyGesture(Key.Up))); CommandManager.RegisterClassInputBinding(typeof(FlowDocumentPageViewer), new InputBinding(NavigationCommands.PreviousPage, new KeyGesture(Key.PageUp))); CommandManager.RegisterClassInputBinding(typeof(FlowDocumentPageViewer), new InputBinding(NavigationCommands.NextPage, new KeyGesture(Key.Right))); CommandManager.RegisterClassInputBinding(typeof(FlowDocumentPageViewer), new InputBinding(NavigationCommands.NextPage, new KeyGesture(Key.Down))); CommandManager.RegisterClassInputBinding(typeof(FlowDocumentPageViewer), new InputBinding(NavigationCommands.NextPage, new KeyGesture(Key.PageDown))); CommandManager.RegisterClassInputBinding(typeof(FlowDocumentPageViewer), new InputBinding(NavigationCommands.FirstPage, new KeyGesture(Key.Home))); CommandManager.RegisterClassInputBinding(typeof(FlowDocumentPageViewer), new InputBinding(NavigationCommands.FirstPage, new KeyGesture(Key.Home, ModifierKeys.Control))); CommandManager.RegisterClassInputBinding(typeof(FlowDocumentPageViewer), new InputBinding(NavigationCommands.LastPage, new KeyGesture(Key.End))); CommandManager.RegisterClassInputBinding(typeof(FlowDocumentPageViewer), new InputBinding(NavigationCommands.LastPage, new KeyGesture(Key.End, ModifierKeys.Control))); } ////// Central handler for CanExecuteRouted events fired by Commands directed at FlowDocumentPageViewer. /// /// The target of this Command, expected to be FlowDocumentPageViewer /// The event arguments for this event. private static void CanExecuteRoutedEventHandler(object target, CanExecuteRoutedEventArgs args) { FlowDocumentPageViewer fdpv = target as FlowDocumentPageViewer; Invariant.Assert(fdpv != null, "Target of QueryEnabledEvent must be FlowDocumentPageViewer."); Invariant.Assert(args != null, "args cannot be null."); // DocumentViewerBase is capable of execution of the majority of its commands. // Special rules: // a) Find command is enabled when Document is attached and printing is not in progress. if (args.Command == ApplicationCommands.Find) { args.CanExecute = fdpv.CanShowFindToolBar; } else { args.CanExecute = true; } } ////// Central handler for all ExecutedRouted events fired by Commands directed at FlowDocumentPageViewer. /// /// The target of this Command, expected to be FlowDocumentPageViewer. /// The event arguments associated with this event. private static void ExecutedRoutedEventHandler(object target, ExecutedRoutedEventArgs args) { FlowDocumentPageViewer fdpv = target as FlowDocumentPageViewer; Invariant.Assert(fdpv != null, "Target of ExecuteEvent must be FlowDocumentPageViewer."); Invariant.Assert(args != null, "args cannot be null."); // Now we execute the method corresponding to the Command that fired this event; // each Command has its own protected virtual method that performs the operation // corresponding to the Command. if (args.Command == NavigationCommands.IncreaseZoom) { fdpv.OnIncreaseZoomCommand(); } else if (args.Command == NavigationCommands.DecreaseZoom) { fdpv.OnDecreaseZoomCommand(); } else if (args.Command == ApplicationCommands.Find) { fdpv.OnFindCommand(); } else { Invariant.Assert(false, "Command not handled in ExecutedRoutedEventHandler."); } } ////// Disable commands on DocumentViewerBase when this printing is in progress. /// private void PreviewCanExecuteRoutedEventHandler(object target, CanExecuteRoutedEventArgs args) { FlowDocumentPageViewer fdpv = target as FlowDocumentPageViewer; Invariant.Assert(fdpv != null, "Target of PreviewCanExecuteRoutedEventHandler must be FlowDocumentPageViewer."); Invariant.Assert(args != null, "args cannot be null."); // Disable UI commands, if printing is in progress. if (fdpv._printingState != null) { if (args.Command != ApplicationCommands.CancelPrint) { args.CanExecute = false; args.Handled = true; } } } ////// Called when a key event occurs. /// private static void KeyDownHandler(object sender, KeyEventArgs e) { DocumentViewerHelper.KeyDownHelper(e, ((FlowDocumentPageViewer)sender)._findToolBarHost); } #endregion Commands #region Static Methods ////// Coerce the value for Zoom property. /// private static object CoerceZoom(DependencyObject d, object value) { Invariant.Assert(d != null && d is FlowDocumentPageViewer); double maxZoom, minZoom; FlowDocumentPageViewer v = (FlowDocumentPageViewer) d; double zoom = (double)value; maxZoom = v.MaxZoom; if (DoubleUtil.LessThan(maxZoom, zoom)) { return maxZoom; } minZoom = v.MinZoom; if (DoubleUtil.GreaterThan(minZoom, zoom)) { return minZoom; } return value; } ////// Coerce the value for MaxZoom property. /// private static object CoerceMaxZoom(DependencyObject d, object value) { Invariant.Assert(d != null && d is FlowDocumentPageViewer); FlowDocumentPageViewer v = (FlowDocumentPageViewer) d; double minZoom = v.MinZoom; if (DoubleUtil.LessThan((double)value, minZoom)) { return minZoom; } return value; } ////// The Zoom has changed and needs to be updated. /// private static void ZoomChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { Invariant.Assert(d != null && d is FlowDocumentPageViewer); ((FlowDocumentPageViewer)d).ZoomChanged((double) e.OldValue, (double) e.NewValue); } ////// The MaxZoom has changed and needs to be updated. /// private static void MaxZoomChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { Invariant.Assert(d != null && d is FlowDocumentPageViewer); ((FlowDocumentPageViewer)d).MaxZoomChanged((double) e.OldValue, (double) e.NewValue); } ////// The MinZoom has changed and needs to be updated. /// private static void MinZoomChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { Invariant.Assert(d != null && d is FlowDocumentPageViewer); ((FlowDocumentPageViewer)d).MinZoomChanged((double) e.OldValue, (double) e.NewValue); } ////// 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)); } #endregion Static Methods #endregion Private Methods //-------------------------------------------------------------------- // // Private Properties // //------------------------------------------------------------------- #region Private Properties ////// Returns FindToolBar, if enabled. /// private FindToolBar FindToolBar { get { return (_findToolBarHost != null) ? _findToolBarHost.Child as FindToolBar : null; } } #endregion Private Properties //-------------------------------------------------------------------- // // Private Fields // //------------------------------------------------------------------- #region Private Fields private Decorator _findToolBarHost; // Host for FindToolbar private ContentPosition _contentPosition; // Current position to be maintained during zooming and resizing. private FlowDocumentPrintingState _printingState; // Printing state private IDocumentPaginatorSource _oldDocument; // IDocumentPaginatorSource representing Document. Cached separately from DocumentViewerBase // due to lifetime issues. private object _bringContentPositionIntoViewToken = new object(); // Bring content position into view user state private const string _findToolBarHostTemplateName = "PART_FindToolBarHost"; //Name for the Find Toolbar host. #endregion Private Fields //------------------------------------------------------------------- // // IJournalState Members // //------------------------------------------------------------------- #region IJournalState Members [Serializable] private class JournalState : CustomJournalStateInternal { public JournalState(int contentPosition, LogicalDirection contentPositionDirection, double zoom) { ContentPosition = contentPosition; ContentPositionDirection = contentPositionDirection; Zoom = zoom; } public int ContentPosition; public LogicalDirection ContentPositionDirection; public double Zoom; } ////// CustomJournalStateInternal IJournalState.GetJournalState(JournalReason journalReason) { int cp = -1; LogicalDirection cpDirection = LogicalDirection.Forward; TextPointer contentPosition = ContentPosition as TextPointer; if (contentPosition != null) { cp = contentPosition.Offset; cpDirection = contentPosition.LogicalDirection; } return new JournalState(cp, cpDirection, Zoom); } ////// /// void IJournalState.RestoreJournalState(CustomJournalStateInternal state) { JournalState viewerState = state as JournalState; if (state != null) { Zoom = viewerState.Zoom; if (viewerState.ContentPosition != -1) { FlowDocument document = Document as FlowDocument; if (document != null) { TextContainer textContainer = document.StructuralCache.TextContainer; if (viewerState.ContentPosition <= textContainer.SymbolCount) { TextPointer contentPosition = textContainer.CreatePointerAtOffset(viewerState.ContentPosition, viewerState.ContentPositionDirection); // This need be called because the UI may not be ready when Contentposition is set. Dispatcher.BeginInvoke(DispatcherPriority.Input, new DispatcherOperationCallback(BringContentPositionIntoView), contentPosition); } } } } } #endregion IJournalState Members //-------------------------------------------------------------------- // // DTypeThemeStyleKey // //------------------------------------------------------------------- #region DTypeThemeStyleKey ////// /// Returns the DependencyObjectType for the registered ThemeStyleKey's default /// value. Controls will override this method to return approriate types /// internal override DependencyObjectType DTypeThemeStyleKey { get { return _dType; } } private static DependencyObjectType _dType; #endregion DTypeThemeStyleKey } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved.
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- WeakReference.cs
- UriGenerator.cs
- ApplicationDirectory.cs
- NativeMethods.cs
- _SSPIWrapper.cs
- Util.cs
- XmlHierarchyData.cs
- DataGridRow.cs
- NumericUpDownAcceleration.cs
- BypassElement.cs
- DataServiceStreamResponse.cs
- LinqDataSourceView.cs
- BitConverter.cs
- RepeaterItemEventArgs.cs
- Console.cs
- TrackingServices.cs
- MarkupCompilePass2.cs
- MenuItem.cs
- securitycriticaldataformultiplegetandset.cs
- RSAPKCS1KeyExchangeDeformatter.cs
- DefinitionUpdate.cs
- TypeRestriction.cs
- Stackframe.cs
- RequestUriProcessor.cs
- ProcessHostServerConfig.cs
- Util.cs
- SspiWrapper.cs
- InvokePattern.cs
- DataServiceHost.cs
- MailDefinition.cs
- FilterFactory.cs
- Internal.cs
- XmlRootAttribute.cs
- FacetValueContainer.cs
- StructuredType.cs
- TableCellCollection.cs
- OracleNumber.cs
- CanonicalXml.cs
- TextContainerChangedEventArgs.cs
- ControllableStoryboardAction.cs
- QueryReaderSettings.cs
- Mappings.cs
- DataTemplateSelector.cs
- ImageIndexConverter.cs
- IPPacketInformation.cs
- QueueProcessor.cs
- StyleXamlTreeBuilder.cs
- Internal.cs
- Int32Rect.cs
- Stream.cs
- DateTimeFormatInfoScanner.cs
- XComponentModel.cs
- figurelength.cs
- Publisher.cs
- Animatable.cs
- MDIControlStrip.cs
- DataConnectionHelper.cs
- AssertFilter.cs
- EntityTypeEmitter.cs
- EndpointDiscoveryMetadata.cs
- ListViewHitTestInfo.cs
- AspCompat.cs
- HttpModuleCollection.cs
- XmlNodeList.cs
- ToolStripTemplateNode.cs
- FamilyCollection.cs
- SmuggledIUnknown.cs
- HybridWebProxyFinder.cs
- XmlSchemaAttributeGroup.cs
- DataGridViewRowPostPaintEventArgs.cs
- StrokeDescriptor.cs
- PrinterUnitConvert.cs
- PasswordRecovery.cs
- ConfigurationErrorsException.cs
- ContainerSelectorBehavior.cs
- WebContext.cs
- XPathNodeHelper.cs
- SmtpReplyReaderFactory.cs
- RtfFormatStack.cs
- ButtonBase.cs
- HttpWebRequestElement.cs
- ReaderOutput.cs
- Condition.cs
- LocationSectionRecord.cs
- StorageEntityTypeMapping.cs
- DockingAttribute.cs
- DCSafeHandle.cs
- DelayedRegex.cs
- TextElementEditingBehaviorAttribute.cs
- SettingsPropertyValue.cs
- HelpFileFileNameEditor.cs
- DashStyles.cs
- DataGridViewCellMouseEventArgs.cs
- DependencySource.cs
- DispatcherOperation.cs
- ControlBuilderAttribute.cs
- ThreadExceptionDialog.cs
- PropertyOverridesTypeEditor.cs
- DateTimeFormat.cs
- TextRangeBase.cs