Code:
/ Dotnetfx_Win7_3.5.1 / Dotnetfx_Win7_3.5.1 / 3.5.1 / DEVDIV / depot / DevDiv / releases / Orcas / NetFXw7 / wpf / src / Framework / System / Windows / Controls / DocumentViewer.cs / 1 / DocumentViewer.cs
//---------------------------------------------------------------------------- // //// Copyright (C) Microsoft Corporation. All rights reserved. // // // // Description: Control for displaying paginated content. // // History: // 06/01/2002 - JerrySh - Created. // 07/09/2003 - JDersch - Initial port to WCP tree // 11/07/2003 - JDersch - VisualTree Styling overhaul // 09/21/2004 - JDersch - Cut Annotations, RM & DigSig and Browser-Hosted Toolband // 09/23/2004 - JeremyNS - Cut INavigator, IUriContext, SourceProperty // 10/21/2004 - JeremyNS - Overhauled, and renamed from PageViewer to DocumentViewer // 05/10/2005 - JDersch - Ported to DocumentViewerBase // //--------------------------------------------------------------------------- using MS.Internal; // For Invariant.Assert using MS.Internal.Commands; using MS.Internal.Documents; using MS.Internal.PresentationFramework; // For SecurityHelper using MS.Utility; using System; using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; // For DesignerSerializationVisibility using System.Globalization; using System.Reflection; using System.Windows; using System.Windows.Automation; using System.Windows.Automation.Peers; using System.Windows.Automation.Provider; using System.Windows.Controls; using System.Windows.Controls.Primitives; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Navigation; // For HyperLink navigation event. using System.Windows.Markup; using MS.Internal.Automation; // For TextAdaptor. using System.Security; namespace System.Windows.Controls { ////// DocumentViewer is a control that allows developers to create a custom reading /// experience in their applications for digital documents. /// ////// http://d2/DRX/default.aspx [TemplatePart(Name = "PART_FindToolBarHost", Type = typeof(ContentControl))] [TemplatePart(Name = "PART_ContentHost", Type = typeof(ScrollViewer))] public class DocumentViewer : DocumentViewerBase { //----------------------------------------------------- // // Constructors // //----------------------------------------------------- #region Constructors ////// Initializes class-wide settings. /// static DocumentViewer() { // Create our CommandBindings CreateCommandBindings(); // Register property metadata RegisterMetadata(); } ////// Instantiates a new instance of a DocumentViewer /// public DocumentViewer() : base() { //Perf Tracing - DocumentViewer Construction EventTrace.NormalTraceEvent(EventTraceGuidId.DRXINSTANTIATEDGUID, MS.Utility.EventType.Info); SetUp(); } #endregion Constructors //------------------------------------------------------ // // Public Methods // //----------------------------------------------------- #region Public Methods #region Command convenience methods ////// Tells DocumentViewer to display a "thumbnail view" of pages. This is analogous /// to the ViewThumbnailsCommand. /// public void ViewThumbnails() { OnViewThumbnailsCommand(); } ////// Tells DocumentViewer to fit a single page to the width of the current viewport. /// This is analogous to the FitToWidthCommand. /// public void FitToWidth() { OnFitToWidthCommand(); } ////// Tells DocumentViewer to fit a single page to the height of the current viewport. /// This is analogous to the FitToHeightCommand. /// public void FitToHeight() { OnFitToHeightCommand(); } ////// Tells DocumentViewer to fit the current MaxPagesAcross count to the current /// viewport. This is analogous to the FitToMaxPagesAcrossCommand. /// public void FitToMaxPagesAcross() { OnFitToMaxPagesAcrossCommand(); } ////// Tells DocumentViewer to fit the specified number of pages across to the current viewport /// and sets MaxPagesAcross to the passed in value. This is analogous to the /// FitMaxPagesAcrossCommand. /// /// public void FitToMaxPagesAcross(int pagesAcross) { if (ValidateMaxPagesAcross(pagesAcross)) { if (_documentScrollInfo != null) { _documentScrollInfo.FitColumns(pagesAcross); } } else { throw new ArgumentOutOfRangeException("pagesAcross"); } } ////// Tells DocumentViewer to invoke the Find Dialog. This is analogous to the /// FindCommand. /// public void Find() { OnFindCommand(); } ////// Tells DocumentViewer to scroll up by one viewport. This is analogous to the /// ScrollPageUpCommand. /// public void ScrollPageUp() { OnScrollPageUpCommand(); } ////// Tells DocumentViewer to scroll down by one viewport. This is analogous to the /// ScrollPageDownCommand. /// public void ScrollPageDown() { OnScrollPageDownCommand(); } ////// Tells DocumentViewer to scroll left by one viewport. This is analogous to the /// ScrollPageLeftCommand. /// public void ScrollPageLeft() { OnScrollPageLeftCommand(); } ////// Tells DocumentViewer to scroll right by one viewport. This is analogous to the /// ScrollPageRightCommand. /// public void ScrollPageRight() { OnScrollPageRightCommand(); } ////// Tells DocumentViewer to scroll up by one line (16px). This is analogous to the /// MoveUpCommand. /// public void MoveUp() { OnMoveUpCommand(); } ////// Tells DocumentViewer to scroll down by one line (16px). This is analogous to the /// MoveDownCommand. /// public void MoveDown() { OnMoveDownCommand(); } ////// Tells DocumentViewer to scroll left by one line (16px). This is analogous to the /// MoveLeftCommand. /// public void MoveLeft() { OnMoveLeftCommand(); } ////// Tells DocumentViewer to scroll right by one line (16px). This is analogous to the /// MoveRightCommand. /// public void MoveRight() { OnMoveRightCommand(); } ////// Tells DocumentViewer to increase Zoom by a predefined, nonlinear value. This is /// analogous to the IncreaseZoomCommand. /// public void IncreaseZoom() { OnIncreaseZoomCommand(); } ////// Tells DocumentViewer to decrease Zoom by a predefined, nonlinear value. This is /// analogous to the DecreaseZoomCommand. /// public void DecreaseZoom() { OnDecreaseZoomCommand(); } #endregion Command convenience methods ////// Called when the Template's tree has been generated /// ////// This method is commonly used to check the status of the visual /// tree prior to rendering, so that elements of the tree can be /// customized before they are shown. /// If a style is changed that affects the visual tree, the /// ApplyTemplate method will expand the new visual tree and return /// true. Otherwise, it will return false. /// When overriding this method, be sure to call the ApplyTemplate /// method of the base class. /// ////// True if the Visual Tree has been created /// ///There must be a ScrollViewer in /// DocumentViewer's visual tree which has Name PART_ContentHost. public override void OnApplyTemplate() { base.OnApplyTemplate(); // Walk the visual tree, locating those elements marked with the special // properties such as "I'm the Content area!" FindContentHost(); // Create the Find toolbar and add it to our Visual Tree when appropriate. InstantiateFindToolBar(); //Perf Tracing - DocumentViewer Visuals Created EventTrace.NormalTraceEvent(EventTraceGuidId.DRXSTYLECREATEDGUID, MS.Utility.EventType.Info); // If unset, we will set the ContextMenu property to null -- this will prevent the TextEditor // from overriding our ContextMenu with its own. The TextEditor checks the UIScope (DocumentViewer) // not the RenderScope (DocumentGrid) for previously-set Context Menus, and if it finds one (or if // it finds that ContextMenu has explicitly been set to null, it will not override it. // Since DocumentViewer doesn't have a ContextMenu -- the ContextMenu is set on DocumentGrid which the // TextEditor won't find, we set ContextMenu to null here. // Yes, this seems, on the surface, to be a bit redundant -- but there is a difference between an // "unset null" and an "explicitly set" null to the Property engine that the TextEditor looks for. // We check that the ContextMenu is null because we don't want to override any user-specified ContextMenus. if (this.ContextMenu == null) { this.ContextMenu = null; } } #endregion Public Methods //------------------------------------------------------ // // Public Properties // //------------------------------------------------------ #region Public Properties #region Commands ////// This command will invoke ViewThumbnails method, causing as many pages /// as feasible to be displayed in the current viewport. /// public static RoutedUICommand ViewThumbnailsCommand { get { return _viewThumbnailsCommand; } } ////// This command will invoke the FitToWidth method, /// setting the layout to 1 page across, and zooming so that one page is displayed /// at the width of the current viewport. /// public static RoutedUICommand FitToWidthCommand { get { return _fitToWidthCommand; } } ////// This command will invoke the FitToWidth method, /// setting the layout to 1 page across, and zooming so that one page is displayed /// at the height of the current viewport. /// public static RoutedUICommand FitToHeightCommand { get { return _fitToHeightCommand; } } ////// This command will invoke the FitToMaxPagesAcross method, /// effectively setting MaxPagesAcross /// to the value of the parameter and fitting those pages into view. /// public static RoutedUICommand FitToMaxPagesAcrossCommand { get { return _fitToMaxPagesAcrossCommand; } } #endregion Commands #region Dependency Properties #region HorizontalOffset ////// Reflects the current Horizontal position in the document in pixel units given /// the current page layout. /// public static readonly DependencyProperty HorizontalOffsetProperty = DependencyProperty.Register( "HorizontalOffset", typeof(double), typeof(DocumentViewer), new FrameworkPropertyMetadata( _horizontalOffsetDefault, //default value FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, //MetaData flags new PropertyChangedCallback(OnHorizontalOffsetChanged)), //changed callback new ValidateValueCallback(ValidateOffset)); //validate callback ////// Reflects the current Horizontal position in the document in pixel units given /// the current page layout. /// public double HorizontalOffset { get { return (double) GetValue(HorizontalOffsetProperty); } set { SetValue(HorizontalOffsetProperty, value); } } #endregion HorizontalOffset #region VerticalOffset ////// Reflects the current Vertical position in the document in pixel units given /// the current page layout. /// public static readonly DependencyProperty VerticalOffsetProperty = DependencyProperty.Register( "VerticalOffset", typeof(double), typeof(DocumentViewer), new FrameworkPropertyMetadata( _verticalOffsetDefault, //default value FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, //MetaData flags new PropertyChangedCallback(OnVerticalOffsetChanged)), //changed callback new ValidateValueCallback(ValidateOffset)); //validate callback ////// Reflects the current Vertical position in the document in pixel units given /// the current page layout. /// public double VerticalOffset { get { return (double) GetValue(VerticalOffsetProperty); } set { SetValue(VerticalOffsetProperty, value); } } #endregion VerticalOffset #region ExtentWidth ////// Reflects the current width of the document layout. /// private static readonly DependencyPropertyKey ExtentWidthPropertyKey = DependencyProperty.RegisterReadOnly( "ExtentWidth", typeof(double), typeof(DocumentViewer), new FrameworkPropertyMetadata( _extentWidthDefault, new PropertyChangedCallback(OnExtentWidthChanged))); ////// Reflects the current width of the document layout. /// public static readonly DependencyProperty ExtentWidthProperty = ExtentWidthPropertyKey.DependencyProperty; ////// Reflects the current width of the document layout. /// public double ExtentWidth { get { return (double) GetValue(ExtentWidthProperty); } } #endregion ExtentWidth #region ExtentHeight ////// Reflects the current height of the document layout. /// private static readonly DependencyPropertyKey ExtentHeightPropertyKey = DependencyProperty.RegisterReadOnly( "ExtentHeight", typeof(double), typeof(DocumentViewer), new FrameworkPropertyMetadata( _extentHeightDefault, new PropertyChangedCallback(OnExtentHeightChanged))); ////// Reflects the current height of the document layout. /// public static readonly DependencyProperty ExtentHeightProperty = ExtentHeightPropertyKey.DependencyProperty; ////// Reflects the current height of the document layout. /// public double ExtentHeight { get { return (double) GetValue(ExtentHeightProperty); } } #endregion ExtentHeight #region ViewportWidth ////// Reflects the current width of the DocumentViewer's content area. /// private static readonly DependencyPropertyKey ViewportWidthPropertyKey = DependencyProperty.RegisterReadOnly( "ViewportWidth", typeof(double), typeof(DocumentViewer), new FrameworkPropertyMetadata( _viewportWidthDefault, new PropertyChangedCallback(OnViewportWidthChanged))); ////// Reflects the current width of the DocumentViewer's content area. /// public static readonly DependencyProperty ViewportWidthProperty = ViewportWidthPropertyKey.DependencyProperty; ////// Reflects the current width of the DocumentViewer's content area. /// public double ViewportWidth { get { return (double) GetValue(ViewportWidthProperty); } } #endregion ViewportWidth #region ViewportHeight ////// Reflects the current height of the DocumentViewer's content area. /// private static readonly DependencyPropertyKey ViewportHeightPropertyKey = DependencyProperty.RegisterReadOnly( "ViewportHeight", typeof(double), typeof(DocumentViewer), new FrameworkPropertyMetadata( _viewportHeightDefault, new PropertyChangedCallback(OnViewportHeightChanged))); ////// Reflects the current height of the DocumentViewer's content area. /// public static readonly DependencyProperty ViewportHeightProperty = ViewportHeightPropertyKey.DependencyProperty; ////// Reflects the current height of the DocumentViewer's content area. /// public double ViewportHeight { get { return (double) GetValue(ViewportHeightProperty); } } #endregion ViewportHeight #region ShowPageBorders ////// Reflects whether a "Drop Shadow" border should be shown around the pages being displayed. /// public static readonly DependencyProperty ShowPageBordersProperty = DependencyProperty.Register( "ShowPageBorders", typeof(bool), typeof(DocumentViewer), new FrameworkPropertyMetadata( _showPageBordersDefault, //default value FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, //MetaData flags new PropertyChangedCallback(OnShowPageBordersChanged))); //changed callback ////// Reflects whether a "Drop Shadow" border should be shown around the pages being displayed. /// public bool ShowPageBorders { get { return (bool) GetValue(ShowPageBordersProperty); } set { SetValue(ShowPageBordersProperty, value); } } #endregion ShowPageBorders #region Zoom ////// Reflects the effective Zoom percentage based on the last layout related /// property set or command issued. /// If this was the last property set, or the Zoom command was last issued, /// then this will just be the last Zoom value set. /// When another layout related property (ie MaxPagesAcross, etc) was set /// or a command (ie FitToMaxPagesAcross, FitToHeight, etc) was issued, then /// this value will be the resulting Zoom value from that layout adjustment. /// /// Must be greater than 5.0 and less than 5000.0. Invalid values will throw. /// public static readonly DependencyProperty ZoomProperty = DependencyProperty.Register( "Zoom", typeof(double), typeof(DocumentViewer), new FrameworkPropertyMetadata( _zoomPercentageDefault, //default value FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, //MetaData flags new PropertyChangedCallback(OnZoomChanged), //changed callback new CoerceValueCallback(CoerceZoom))); // coercion callback ////// Reflects the effective Zoom percentage based on the last layout related /// property set or command issued. /// If this was the last property set, or the Zoom command was last issued, /// then this will just be the last Zoom value set. /// When another layout related property (ie MaxPagesAcross, etc) was set /// or a command (ie FitToMaxPagesAcross, FitToHeight, etc) was issued, then /// this value will be the resulting Zoom value from that layout adjustment. /// /// Must be greater than 5.0 and less than 5000.0. /// public double Zoom { get { return (double) GetValue(ZoomProperty); } set { SetValue(ZoomProperty, value); } } #endregion Zoom #region MaxPagesAcross ////// Reflects the number of Columns of pages displayed, based on the last /// value set through this property, or a layout related command /// (ie FitToMaxPagesAcross, ViewThumbnails, etc..) /// public static readonly DependencyProperty MaxPagesAcrossProperty = DependencyProperty.Register( "MaxPagesAcross", typeof(int), typeof(DocumentViewer), new FrameworkPropertyMetadata( _maxPagesAcrossDefault, //default value FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, //MetaData flags new PropertyChangedCallback(OnMaxPagesAcrossChanged)), //changed callback new ValidateValueCallback(ValidateMaxPagesAcross)); //validation callback ////// Reflects the number of Columns of pages displayed, based on the last /// value set through this property, or a layout related command /// (ie FitToMaxPagesAcross, ViewThumbnails, etc..) /// Valid values are from 1 to 32, inclusive. /// public int MaxPagesAcross { get { return (int) GetValue(MaxPagesAcrossProperty); } set { SetValue(MaxPagesAcrossProperty, value); } } #endregion MaxPagesAcross #region VerticalPageSpacing ////// Reflects the vertical gap between Pages when laid out, in pixel units. /// public static readonly DependencyProperty VerticalPageSpacingProperty = DependencyProperty.Register( "VerticalPageSpacing", typeof(double), typeof(DocumentViewer), new FrameworkPropertyMetadata( _verticalPageSpacingDefault, //default value new PropertyChangedCallback(OnVerticalPageSpacingChanged)), //changed callback new ValidateValueCallback(ValidatePageSpacing)); //validation callback ////// Reflects the vertical gap between Pages when laid out, in pixel units. /// public double VerticalPageSpacing { get { return (double) GetValue(VerticalPageSpacingProperty); } set { SetValue(VerticalPageSpacingProperty, value); } } #endregion VerticalPageSpacing #region HorizontalPageSpacing ////// Reflects the horizontal gap between Pages when laid out, in pixel units. /// public static readonly DependencyProperty HorizontalPageSpacingProperty = DependencyProperty.Register( "HorizontalPageSpacing", typeof(double), typeof(DocumentViewer), new FrameworkPropertyMetadata( _horizontalPageSpacingDefault, //default value new PropertyChangedCallback(OnHorizontalPageSpacingChanged)), //changed callback new ValidateValueCallback(ValidatePageSpacing)); //validation callback ////// Reflects the horizontal gap between Pages when laid out, in pixel units. /// public double HorizontalPageSpacing { get { return (double) GetValue(HorizontalPageSpacingProperty); } set { SetValue(HorizontalPageSpacingProperty, value); } } #endregion HorizontalPageSpacing #region CanMoveUp ////// Reflects whether the DocumentViewer is at the top of the current document. /// private static readonly DependencyPropertyKey CanMoveUpPropertyKey = DependencyProperty.RegisterReadOnly( "CanMoveUp", typeof(bool), typeof(DocumentViewer), new FrameworkPropertyMetadata(_canMoveUpDefault)); ////// Reflects whether the DocumentViewer is at the top of the current document. /// public static readonly DependencyProperty CanMoveUpProperty = CanMoveUpPropertyKey.DependencyProperty; ////// Reflects whether the DocumentViewer is at the top of the current document. /// public bool CanMoveUp { get { return (bool) GetValue(CanMoveUpProperty); } } #endregion CanMoveUp #region CanMoveDown ////// Reflects whether the DocumentViewer is at the bottom of the current document. /// private static readonly DependencyPropertyKey CanMoveDownPropertyKey = DependencyProperty.RegisterReadOnly( "CanMoveDown", typeof(bool), typeof(DocumentViewer), new FrameworkPropertyMetadata(_canMoveDownDefault)); ////// Reflects whether the DocumentViewer is at the bottom of the current document. /// public static readonly DependencyProperty CanMoveDownProperty = CanMoveDownPropertyKey.DependencyProperty; ////// Reflects whether the DocumentViewer is at the bottom of the current document. /// public bool CanMoveDown { get { return (bool) GetValue(CanMoveDownProperty); } } #endregion CanMoveDown #region CanMoveLeft ////// Reflects whether the DocumentViewer is at the leftmost extent of the current document. /// private static readonly DependencyPropertyKey CanMoveLeftPropertyKey = DependencyProperty.RegisterReadOnly( "CanMoveLeft", typeof(bool), typeof(DocumentViewer), new FrameworkPropertyMetadata(_canMoveLeftDefault)); ////// Reflects whether the DocumentViewer is at the leftmost extent of the current document. /// public static readonly DependencyProperty CanMoveLeftProperty = CanMoveLeftPropertyKey.DependencyProperty; ////// Reflects whether the DocumentViewer is at the leftmost extent of the current document. /// public bool CanMoveLeft { get { return (bool) GetValue(CanMoveLeftProperty); } } #endregion CanMoveLeft #region CanMoveRight ////// Reflects whether the DocumentViewer is at the rightmost extent of the current document. /// private static readonly DependencyPropertyKey CanMoveRightPropertyKey = DependencyProperty.RegisterReadOnly( "CanMoveRight", typeof(bool), typeof(DocumentViewer), new FrameworkPropertyMetadata(_canMoveRightDefault)); ////// Reflects whether the DocumentViewer is at the rightmost extent of the current document. /// public static readonly DependencyProperty CanMoveRightProperty = CanMoveRightPropertyKey.DependencyProperty; ////// Reflects whether the DocumentViewer is at the rightmost extent of the current document. /// public bool CanMoveRight { get { return (bool) GetValue(CanMoveRightProperty); } } #endregion CanMoveRight #region CanIncreaseZoom ////// Reflects whether the DocumentViewer can zoom in any further /// (ie not at the highest "zoom level") of the current document. /// private static readonly DependencyPropertyKey CanIncreaseZoomPropertyKey = DependencyProperty.RegisterReadOnly( "CanIncreaseZoom", typeof(bool), typeof(DocumentViewer), new FrameworkPropertyMetadata(_canIncreaseZoomDefault)); ////// Reflects whether the DocumentViewer can zoom in any further /// (ie not at the highest "zoom level") of the current document. /// public static readonly DependencyProperty CanIncreaseZoomProperty = CanIncreaseZoomPropertyKey.DependencyProperty; ////// Reflects whether the DocumentViewer can zoom in any further /// (ie not at the highest "zoom level") of the current document. /// public bool CanIncreaseZoom { get { return (bool) GetValue(CanIncreaseZoomProperty); } } #endregion CanIncreaseZoom #region CanDecreaseZoom ////// Reflects whether the DocumentViewer can zoom out any further /// (ie not at the lowest "zoom level") of the current document. /// private static readonly DependencyPropertyKey CanDecreaseZoomPropertyKey = DependencyProperty.RegisterReadOnly( "CanDecreaseZoom", typeof(bool), typeof(DocumentViewer), new FrameworkPropertyMetadata(_canDecreaseZoomDefault)); ////// Reflects whether the DocumentViewer can zoom out any further /// (ie not at the lowest "zoom level") of the current document. /// public static readonly DependencyProperty CanDecreaseZoomProperty = CanDecreaseZoomPropertyKey.DependencyProperty; ////// Reflects whether the DocumentViewer can zoom out any further /// (ie not at the lowest "zoom level") of the current document. /// public bool CanDecreaseZoom { get { return (bool) GetValue(CanDecreaseZoomProperty); } } #endregion CanDecreaseZoom #endregion Dependency Properties #endregion Public Properties //----------------------------------------------------- // // Public Operators // //------------------------------------------------------ //----------------------------------------------------- // // Public Events // //----------------------------------------------------- //----------------------------------------------------- // // Protected Methods // //------------------------------------------------------ #region Protected Methods ////// Creates AutomationPeer ( protected override AutomationPeer OnCreateAutomationPeer() { return new DocumentViewerAutomationPeer(this); } ///) /// /// Attaches DocumentGrid to our document when it changes. /// ////// Critical: set_DocumentLoaded is defined in a non-APTCA assembly. /// TreatAsSafe: call to set_DocumentLoaded does not entail any risk. /// [SecurityCritical, SecurityTreatAsSafe] protected override void OnDocumentChanged() { // Validate the new document type if (!(Document is FixedDocument) && !(Document is FixedDocumentSequence) && !(Document == null)) { throw new NotSupportedException(SR.Get(SRID.DocumentViewerOnlySupportsFixedDocumentSequence)); } //Call the base so that TextEditors are attached. base.OnDocumentChanged(); //Assign the content to DocumentGrid. AttachContent(); // Update the toolbar with our current document state. if (_findToolbar != null) { _findToolbar.DocumentLoaded = (Document != null) ? true : false; } // We do not automatically go to the first page on the _first_ content // assignment, for two reasons: // 1) If this is the first assignment, then we're already there by default. // 2) The user may have specified vertical or horizontal offsets in markup or // otherwise () and we need to honor // those settings. if (!_firstDocumentAssignment) { // Go to the first page of new content. OnGoToPageCommand(1); } _firstDocumentAssignment = false; } /// /// Called when a BringIntoView event is bubbled up from the Document. /// Base implementation will move the master page to the page /// on which the element occurs. /// /// The object to make visible. /// The rectangular region in the object's coordinate space which should be made visible. /// protected override void OnBringIntoView(DependencyObject element, Rect rect, int pageNumber) { // DVBase will give us a 1-indexed page number, we convert to 0-indexed. int zeroIndexed = pageNumber - 1; if (zeroIndexed >= 0 && zeroIndexed < PageCount) { _documentScrollInfo.MakeVisible(element, rect, zeroIndexed); } } ////// Handler for the PreviousPage command. /// protected override void OnPreviousPageCommand() { //Scroll to the previous row. if (_documentScrollInfo != null) { _documentScrollInfo.ScrollToPreviousRow(); } } ////// Handler for the NextPage command. /// protected override void OnNextPageCommand() { //Scroll to the previous row. if (_documentScrollInfo != null) { _documentScrollInfo.ScrollToNextRow(); } } ////// Handler for the FirstPage command. /// protected override void OnFirstPageCommand() { //Scroll to the top of the document. if (_documentScrollInfo != null) { _documentScrollInfo.MakePageVisible( 0 ); } } ////// Handler for the LastPage command. /// protected override void OnLastPageCommand() { //Scroll to the bottom of the document. if (_documentScrollInfo != null) { _documentScrollInfo.MakePageVisible( PageCount - 1 ); } } ////// Handler for the GoToPage command. /// protected override void OnGoToPageCommand(int pageNumber) { // Check if we can go to the specified page. // and navigate there. if (CanGoToPage(pageNumber)) { //Scroll to the specified page in the document. if (_documentScrollInfo != null) { // CanGoToPage should have guaranteed that this assert is always true. Invariant.Assert(pageNumber > 0, "PageNumber must be positive."); _documentScrollInfo.MakePageVisible(pageNumber - 1); } } } ////// Handler for the ViewThumbnails Command /// protected virtual void OnViewThumbnailsCommand() { if (_documentScrollInfo != null) { _documentScrollInfo.ViewThumbnails(); } } ////// Handler for the FitToWidth Command /// protected virtual void OnFitToWidthCommand() { if (_documentScrollInfo != null) { _documentScrollInfo.FitToPageWidth(); } } ////// Handler for the FitToHeight Command /// protected virtual void OnFitToHeightCommand() { if (_documentScrollInfo != null) { _documentScrollInfo.FitToPageHeight(); } } ////// Handler for the FitToMaxPagesAcross Command /// protected virtual void OnFitToMaxPagesAcrossCommand() { if (_documentScrollInfo != null) { _documentScrollInfo.FitColumns(MaxPagesAcross); } } ////// HAndler for the FitMaxPagesAcross Command /// /// protected virtual void OnFitToMaxPagesAcrossCommand(int pagesAcross) { if (ValidateMaxPagesAcross(pagesAcross)) { if (_documentScrollInfo != null) { _documentScrollInfo.FitColumns(pagesAcross); } } else { throw new ArgumentOutOfRangeException("pagesAcross"); } } ////// Handler for the Find Command /// protected virtual void OnFindCommand() { GoToFind(); } ////// This is the method that responds to the KeyDown event. /// /// protected override void OnKeyDown(KeyEventArgs e) { // Look for Find specific key inputs and process them. // If the key is processed, this event will be marked handled. e = ProcessFindKeys(e); base.OnKeyDown(e); } ////// Handler for the ScrollPageUp Command /// protected virtual void OnScrollPageUpCommand() { if (_documentScrollInfo != null) { _documentScrollInfo.PageUp(); } } ////// Handler for the ScrollPageDown Command /// protected virtual void OnScrollPageDownCommand() { if (_documentScrollInfo != null) { _documentScrollInfo.PageDown(); } } ////// Handler for the ScrollPageLeft Command /// protected virtual void OnScrollPageLeftCommand() { if (_documentScrollInfo != null) { _documentScrollInfo.PageLeft(); } } ////// Handler for the ScrollPageRight Command /// protected virtual void OnScrollPageRightCommand() { if (_documentScrollInfo != null) { _documentScrollInfo.PageRight(); } } ////// Handler for the MoveUp Command /// protected virtual void OnMoveUpCommand() { if (_documentScrollInfo != null) { _documentScrollInfo.LineUp(); } } ////// Handler for the MoveDown Command /// protected virtual void OnMoveDownCommand() { if (_documentScrollInfo != null) { _documentScrollInfo.LineDown(); } } ////// Handler for the MoveLeft Command /// protected virtual void OnMoveLeftCommand() { if (_documentScrollInfo != null) { _documentScrollInfo.LineLeft(); } } ////// Handler for the MoveRight Command /// protected virtual void OnMoveRightCommand() { if (_documentScrollInfo != null) { _documentScrollInfo.LineRight(); } } ////// Handler for the IncreaseZoom Command /// protected virtual void OnIncreaseZoomCommand() { // Check if possible to zoom in if (CanIncreaseZoom) { // Update the zoom level index to the appropriate place. double oldZoom = Zoom; FindZoomLevelIndex(); // As long as more zoomLevel's exist, increase zoom. if (_zoomLevelIndex > 0) { _zoomLevelIndex--; } // Set the zoom percentage, with _updatingInternalZoomLevel set to true to // avoid resetting the zoom level index. _updatingInternalZoomLevel = true; Zoom = DocumentViewer._zoomLevelCollection[_zoomLevelIndex]; _updatingInternalZoomLevel = false; } } ////// Handler for the DecreaseZoom Command /// protected virtual void OnDecreaseZoomCommand() { // Check if possible to zoom out. if (CanDecreaseZoom) { // Update the zoom level index to the appropriate place. double oldZoom = Zoom; FindZoomLevelIndex(); // If the current zoom value exists in the zoomLevelCollection, and can // still be zoomed out, then zoom out another level. if ((oldZoom == DocumentViewer._zoomLevelCollection[_zoomLevelIndex]) && (_zoomLevelIndex < DocumentViewer._zoomLevelCollection.Length - 1)) { _zoomLevelIndex++; } // Set the zoom percentage, with _updatingInternalZoomLevel set to true to // avoid resetting the zoom level index. _updatingInternalZoomLevel = true; Zoom = _zoomLevelCollection[_zoomLevelIndex]; _updatingInternalZoomLevel = false; } } ////// Overrides the base implementation and returns the current collection of /// DocumentPageViews being displayed in our IDSI. /// /// ///protected override ReadOnlyCollection GetPageViewsCollection(out bool changed) { ReadOnlyCollection pageViews = null; //Save off the current value of our PageView changed flag so we can //return it to indicate if the collection has actually changed. changed = _pageViewCollectionChanged; //Reset the flag so that if this is called again before InvalidatePageViews is called //it'll reflect the unchanged-ness of the collection. _pageViewCollectionChanged = false; if (_documentScrollInfo != null && _documentScrollInfo.PageViews != null) { //Return the current collection. pageViews = _documentScrollInfo.PageViews; } else { //Return an empty collection (null is not valid). pageViews = new ReadOnlyCollection (new List (0)); } return pageViews; } /// /// Overrides the OnMouseLeftButtonDown method so that we can take focus when clicked. /// /// The MouseButtonEventArgs associated with this mouse event. protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e) { base.OnMouseLeftButtonDown(e); // If no other controls in our Template have handled the event, we'll // take focus here. if (!e.Handled) { Focus(); e.Handled = true; } } ////// OnPreviewMouseWheel Zooms in/out on the document when the /// mouse wheel is scrolled and the Ctrl key is depressed. /// /// Event Arguments protected override void OnPreviewMouseWheel(MouseWheelEventArgs e) { if (e.Handled) { return; } //Get the state of the Ctrl key -- if it's pressed, we'll Zoom. //Otherwise we do nothing and let others handle this event. if (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl)) { e.Handled = true; //Zoom based on the direction of the wheel. if (e.Delta < 0) { DecreaseZoom(); } else { IncreaseZoom(); } } } #endregion Protected Methods #region Internal Methods ////// Called when our IDocumentScrollInfo has new layout information to share with us. /// internal void InvalidateDocumentScrollInfo() { // We need to see if any IDocumentScrollInfo properties that DocumentViewer // either exposes or makes use of have changed. If so we invalidate properties // or take actions here. // Any properties that are read only need to have the cache set and be invalidated // Settable DP's can be set directly (and should be, for validation) //Set our internal change flag. //DP Invalidation callbacks can check for this flag to see if a change originated //from our IDocumentScrollInfo object or not and take the appropriate action. //(Usually, if the IDSI caused the change to a DP, the invalidated callback won't need to //update the associated property on the IDSI.) _internalIDSIChange = true; SetValue(ExtentWidthPropertyKey, _documentScrollInfo.ExtentWidth); SetValue(ExtentHeightPropertyKey, _documentScrollInfo.ExtentHeight); SetValue(ViewportWidthPropertyKey, _documentScrollInfo.ViewportWidth); SetValue(ViewportHeightPropertyKey, _documentScrollInfo.ViewportHeight); if (HorizontalOffset != _documentScrollInfo.HorizontalOffset) { HorizontalOffset = _documentScrollInfo.HorizontalOffset; } if (VerticalOffset != _documentScrollInfo.VerticalOffset) { VerticalOffset = _documentScrollInfo.VerticalOffset; } // IDSI is 0-indexed SetValue(MasterPageNumberPropertyKey, _documentScrollInfo.FirstVisiblePageNumber + 1); // Convert IDocumentScrollInfo.Scale into 100-based percentage value for comparison. double scrollZoom = ScaleToZoom(_documentScrollInfo.Scale); if (Zoom != scrollZoom) { Zoom = scrollZoom; } if (MaxPagesAcross != _documentScrollInfo.MaxPagesAcross) { MaxPagesAcross = _documentScrollInfo.MaxPagesAcross; } //Reset our internal change flag. _internalIDSIChange = false; } ////// Merely calls the base's InvalidatePageViews (which is protected). /// Used by our IDSI to keep the DPV collection in [....]. /// internal void InvalidatePageViewsInternal() { //Our PageView collection has changed, set the flag. _pageViewCollectionChanged = true; InvalidatePageViews(); } ////// BringPointIntoView is called by the base if a selection goes outside of the bounds /// of the current TextView. If this happens it is necessary to scroll our content /// in an attempt to make that selection point visible, thus moving the scope of the TextView /// and allowing selection to continue. /// /// The point to be brought into view. ///Whether operation is pending or not. internal bool BringPointIntoView(Point point) { FrameworkElement grid = _documentScrollInfo as FrameworkElement; if (grid != null) { //Calculate the bounds of the DocumentGrid relative to the bounds of DocumentViewer Transform tr = this.TransformToDescendant(grid) as Transform; Rect gridRect = Rect.Transform(new Rect(grid.RenderSize), tr.Value); double verticalOffset = VerticalOffset; double horizontalOffset = HorizontalOffset; //Scroll the point into view Vertically. if (point.Y > gridRect.Y + gridRect.Height) { verticalOffset += (point.Y - (gridRect.Y + gridRect.Height)); } else if (point.Y < gridRect.Y) { verticalOffset -= (gridRect.Y - point.Y); } //Scroll the point into view Horizontally. if (point.X < gridRect.X) { horizontalOffset -= (gridRect.X - point.X); } else if (point.X > gridRect.X + gridRect.Width) { horizontalOffset += (point.X - (gridRect.X + gridRect.Width)); } VerticalOffset = Math.Max(verticalOffset, 0.0); HorizontalOffset = Math.Max(horizontalOffset, 0.0); } return false; } #endregion Internal Methods #region Internal Properties ////// Internally exposes our TextEditor's Selection, for use /// by Annotations code. /// internal ITextSelection TextSelection { get { if (TextEditor != null) { return TextEditor.Selection; } else { return null; } } } ////// Internally exposes our IDocumentScrollInfo, for use /// by Annotations code. /// internal IDocumentScrollInfo DocumentScrollInfo { get { return _documentScrollInfo; } } ////// Internally exposes out ScrollViewer, for use in DocumentViewerAutomationPeer. /// internal ScrollViewer ScrollViewer { get { return _scrollViewer; } } #endregion InternalProperties //----------------------------------------------------- // // Private Methods // //------------------------------------------------------ #region Private Methods #region Commands ////// Set up our Command bindings /// ////// Set up our RoutedUICommand bindings /// ////// Critical - creates a command binding. /// TAS - registering our own internal commands is considered safe. /// [SecurityCritical , SecurityTreatAsSafe ] private static void CreateCommandBindings() { // Create our generic ExecutedRoutedEventHandler. ExecutedRoutedEventHandler executeHandler = new ExecutedRoutedEventHandler(ExecutedRoutedEventHandler); // Create our generic QueryEnabledStatusHandler CanExecuteRoutedEventHandler queryEnabledHandler = new CanExecuteRoutedEventHandler(QueryEnabledHandler); // // Command: ViewThumbnails // Tells DocumentViewer to display thumbnails. _viewThumbnailsCommand = new RoutedUICommand(SR.Get(SRID.DocumentViewerViewThumbnailsCommandText), "ViewThumbnailsCommand", typeof(DocumentViewer), null); CommandHelpers.RegisterCommandHandler( typeof(DocumentViewer), _viewThumbnailsCommand, executeHandler, queryEnabledHandler); //no key gesture // // Command: FitToWidth // Tells DocumentViewer to zoom to the document width. _fitToWidthCommand = new RoutedUICommand( SR.Get(SRID.DocumentViewerViewFitToWidthCommandText), "FitToWidthCommand", typeof(DocumentViewer), null); CommandHelpers.RegisterCommandHandler(typeof(DocumentViewer), _fitToWidthCommand, executeHandler, queryEnabledHandler, new KeyGesture(Key.D2, ModifierKeys.Control)); // // Command: FitToHeight // Tells DocumentViewer to zoom to the document height. _fitToHeightCommand = new RoutedUICommand( SR.Get(SRID.DocumentViewerViewFitToHeightCommandText), "FitToHeightCommand", typeof(DocumentViewer), null); CommandHelpers.RegisterCommandHandler(typeof(DocumentViewer), _fitToHeightCommand, executeHandler, queryEnabledHandler); //no key gesture // // Command: MaxPagesAcross // Sets the MaxPagesAcross to the value provided. _fitToMaxPagesAcrossCommand = new RoutedUICommand( SR.Get(SRID.DocumentViewerViewFitToMaxPagesAcrossCommandText), "FitToMaxPagesAcrossCommand", typeof(DocumentViewer), null); CommandHelpers.RegisterCommandHandler(typeof(DocumentViewer), _fitToMaxPagesAcrossCommand, executeHandler, queryEnabledHandler); //no key gesture #region Library Commands // Command: ApplicationCommands.Find - Ctrl+F // Invokes DocumentViewer's Find dialog. CommandHelpers.RegisterCommandHandler(typeof(DocumentViewer), ApplicationCommands.Find, executeHandler, queryEnabledHandler); // // Command: ComponentCommands.ScrollPageUp - PageUp // Causes DocumentViewer to scroll a Viewport up. CommandHelpers.RegisterCommandHandler(typeof(DocumentViewer), ComponentCommands.ScrollPageUp, executeHandler, queryEnabledHandler, Key.PageUp); // // Command: ComponentCommands.ScrollPageDown - PageDown // Causes DocumentViewer to scroll a Viewport down. CommandHelpers.RegisterCommandHandler(typeof(DocumentViewer), ComponentCommands.ScrollPageDown, executeHandler, queryEnabledHandler, Key.PageDown); // // Command: ComponentCommands.ScrollPageLeft // Causes DocumentViewer to scroll a Viewport to the left. CommandHelpers.RegisterCommandHandler(typeof(DocumentViewer), ComponentCommands.ScrollPageLeft, executeHandler, queryEnabledHandler); //no key gesture // // Command: ComponentCommands.ScrollPageRight // Causes DocumentViewer to scroll a Viewport to the right. CommandHelpers.RegisterCommandHandler(typeof(DocumentViewer), ComponentCommands.ScrollPageRight, executeHandler, queryEnabledHandler); //no key gesture // // Command: ComponentCommands.MoveUp - Up // Causes DocumentViewer to scroll the Viewport up by 16px. CommandHelpers.RegisterCommandHandler(typeof(DocumentViewer), ComponentCommands.MoveUp, executeHandler, queryEnabledHandler, Key.Up); // // Command: ComponentCommands.MoveDown - Down // Causes DocumentViewer to scroll the Viewport down by 16px. CommandHelpers.RegisterCommandHandler(typeof(DocumentViewer), ComponentCommands.MoveDown, executeHandler, queryEnabledHandler, Key.Down); // // Command: ComponentCommands.MoveLeft - Left // Causes DocumentViewer to scroll a Viewport left by 16px. CommandHelpers.RegisterCommandHandler(typeof(DocumentViewer), ComponentCommands.MoveLeft, executeHandler, queryEnabledHandler, Key.Left); // // Command: ComponentCommands.MoveRight - Right // Causes DocumentViewer to scroll a Viewport right by 16px. CommandHelpers.RegisterCommandHandler(typeof(DocumentViewer), ComponentCommands.MoveRight, executeHandler, queryEnabledHandler, Key.Right); // // Command: NavigationCommands.Zoom // Sets DocumentViewer's Zoom to the specified level. CommandHelpers.RegisterCommandHandler(typeof(DocumentViewer), NavigationCommands.Zoom, executeHandler, queryEnabledHandler); //no key gesture // // Command: NavigationCommands.IncreaseZoom // Causes DocumentViewer to zoom in on the content. CommandHelpers.RegisterCommandHandler(typeof(DocumentViewer), NavigationCommands.IncreaseZoom, executeHandler, queryEnabledHandler, // Ctrl+Numpad '+' new KeyGesture(Key.Add, ModifierKeys.Control), // Ctrl+Numpad '+' (In case shift is held down) new KeyGesture(Key.Add, ModifierKeys.Shift | ModifierKeys.Control), // Ctrl+'+' new KeyGesture(Key.OemPlus, ModifierKeys.Control), // Ctrl+'+' (In case shift is held down) new KeyGesture(Key.OemPlus, ModifierKeys.Shift | ModifierKeys.Control)); // // Command: NavigationCommands.DecreaseZoom // Causes DocumentViewer to zoom out of the content. CommandHelpers.RegisterCommandHandler(typeof(DocumentViewer), NavigationCommands.DecreaseZoom, executeHandler, queryEnabledHandler, // Ctrl+Numpad '-' new KeyGesture(Key.Subtract, ModifierKeys.Control), // Ctrl+Numpad '-' (In case shift is held down) new KeyGesture(Key.Subtract, ModifierKeys.Shift | ModifierKeys.Control), // Ctrl+'-' new KeyGesture(Key.OemMinus, ModifierKeys.Control), // Ctrl+'-' (In case shift is held down) new KeyGesture(Key.OemMinus, ModifierKeys.Shift | ModifierKeys.Control)); // Command: NavigationCommands.PreviousPage CommandHelpers.RegisterCommandHandler(typeof(DocumentViewer), NavigationCommands.PreviousPage, executeHandler, queryEnabledHandler, new KeyGesture(Key.PageUp, ModifierKeys.Control)); // Command: NavigationCommands.NextPage CommandHelpers.RegisterCommandHandler(typeof(DocumentViewer), NavigationCommands.NextPage, executeHandler, queryEnabledHandler, new KeyGesture(Key.PageDown, ModifierKeys.Control)); // Command: NavigationCommands.FirstPage CommandHelpers.RegisterCommandHandler(typeof(DocumentViewer), NavigationCommands.FirstPage, executeHandler, queryEnabledHandler, new KeyGesture(Key.Home, ModifierKeys.Control)); // Command: NavigationCommands.FirstPage CommandHelpers.RegisterCommandHandler(typeof(DocumentViewer), NavigationCommands.LastPage, executeHandler, queryEnabledHandler, new KeyGesture(Key.End, ModifierKeys.Control)); #endregion Library Commands //Register input bindings for keyboard shortcuts that require //Command Parameters: //Zoom 100%: Requires a CommandParameter of 100.0 with the Zoom Command. //Bound to Ctrl+1. InputBinding zoom100InputBinding = new InputBinding(NavigationCommands.Zoom, new KeyGesture(Key.D1, ModifierKeys.Control)); zoom100InputBinding.CommandParameter = 100.0; CommandManager.RegisterClassInputBinding(typeof(DocumentViewer), zoom100InputBinding); //Whole Page: Requires a CommandParameter of 1 with the FitToMaxPagesAcross Command. //Bound to Ctrl+3. InputBinding wholePageInputBinding = new InputBinding(DocumentViewer.FitToMaxPagesAcrossCommand, new KeyGesture(Key.D3, ModifierKeys.Control)); wholePageInputBinding.CommandParameter = 1; CommandManager.RegisterClassInputBinding(typeof(DocumentViewer), wholePageInputBinding); //Two Pages: Requires a CommandParameter of 2 with the FitToMaxPagesAcross Command. //Bound to Ctrl+4. InputBinding twoPagesInputBinding = new InputBinding(DocumentViewer.FitToMaxPagesAcrossCommand, new KeyGesture(Key.D4, ModifierKeys.Control)); twoPagesInputBinding.CommandParameter = 2; CommandManager.RegisterClassInputBinding(typeof(DocumentViewer), twoPagesInputBinding); } ////// Central handler for QueryEnabled events fired by Commands directed at DocumentViewer. /// /// The target of this Command, expected to be DocumentViewer /// The event arguments for this event. [SecurityCritical, SecurityTreatAsSafe] private static void QueryEnabledHandler(object target, CanExecuteRoutedEventArgs args) { DocumentViewer dv = target as DocumentViewer; Invariant.Assert(dv != null, "Target of QueryEnabledEvent must be DocumentViewer."); Invariant.Assert(args != null, "args cannot be null."); // If the target is not a DocumentViewer we silently return (but note that // we have Asserted this above.) if (dv == null) { return; } // Mark this event as handled so that the CanExecute handler on the base // doesn't override our settings. args.Handled = true; // Now we set the IsEnabled flag based on the Command that fired this event // and the current state of DocumentViewer. if (args.Command == ViewThumbnailsCommand || args.Command == FitToWidthCommand || args.Command == FitToHeightCommand || args.Command == FitToMaxPagesAcrossCommand || args.Command == NavigationCommands.Zoom) { // Fit and Zoom operations are always enabled. args.CanExecute = true; } else if (args.Command == ApplicationCommands.Find) { //Find can only operate if we have a TextEditor. args.CanExecute = dv.TextEditor != null; } else if (args.Command == ComponentCommands.ScrollPageUp || args.Command == ComponentCommands.MoveUp) { // Enabling the Move/Scroll Up Commands is tied to the // state of the CanMoveUp property. args.CanExecute = dv.CanMoveUp; } else if (args.Command == ComponentCommands.ScrollPageDown || args.Command == ComponentCommands.MoveDown) { // Enabling the Move/Scroll Down Commands is tied to the // state of the CanMoveDown property. args.CanExecute = dv.CanMoveDown; } else if (args.Command == ComponentCommands.ScrollPageLeft || args.Command == ComponentCommands.MoveLeft) { // Enabling the Move/Scroll Left Commands is tied to the // state of the CanMoveLeft property. args.CanExecute = dv.CanMoveLeft; } else if (args.Command == ComponentCommands.ScrollPageRight || args.Command == ComponentCommands.MoveRight) { // Enabling the Move/Scroll Right Commands is tied to the // state of the CanMoveRight property. args.CanExecute = dv.CanMoveRight; } else if (args.Command == NavigationCommands.IncreaseZoom) { // Zooming in is only allowed if DocumentViewer has a valid Document assigned // and can increase zoom. args.CanExecute = dv.CanIncreaseZoom; } else if (args.Command == NavigationCommands.DecreaseZoom) { // Zooming out is only allowed if DocumentViewer has a valid Document assigned // and can decrease zoom. args.CanExecute = dv.CanDecreaseZoom; } else if (args.Command == NavigationCommands.PreviousPage || args.Command == NavigationCommands.FirstPage) { // Enabling the PreviousPage and FirstPage Commands is tied // to the state of the CanGoToPreviousPage property. args.CanExecute = dv.CanGoToPreviousPage; } else if (args.Command == NavigationCommands.NextPage || args.Command == NavigationCommands.LastPage) { // Enabling the NextPage and LastPage Commands is tied // to the state of the CanGoToNextPage property. args.CanExecute = dv.CanGoToNextPage; } else if (args.Command == NavigationCommands.GoToPage) { // This command is always enabled as long as there is a document loaded. args.CanExecute = (dv.Document != null); } else { args.Handled = false; // If we get here then we missed a Command above. // We assert to indicate the failure. Invariant.Assert(false, "Command not handled in QueryEnabledHandler."); } } ////// Critical - Sets the critical Handled property on the RoutedEventArgs /// TreatAsSafe - We are marking the event as handled only for the Commands that /// DocumentViewer explicitly handles -- this cannot be used for spoofing. /// ////// Central handler for all ExecuteEvents fired by Commands directed at DocumentViewer. /// /// The target of this Command, expected to be DocumentViewer. /// The event arguments associated with this event. private static void ExecutedRoutedEventHandler(object target, ExecutedRoutedEventArgs args) { DocumentViewer dv = target as DocumentViewer; Invariant.Assert(dv != null, "Target of ExecuteEvent must be DocumentViewer."); Invariant.Assert(args != null, "args cannot be null."); // If the target is not a DocumentViewer we silently return (but note that // we have Asserted this above.) if (dv == null) { return; } // 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 == ViewThumbnailsCommand) { dv.OnViewThumbnailsCommand(); } else if (args.Command == FitToWidthCommand) { dv.OnFitToWidthCommand(); } else if (args.Command == FitToHeightCommand) { dv.OnFitToHeightCommand(); } else if (args.Command == FitToMaxPagesAcrossCommand) { DoFitToMaxPagesAcross(dv, args.Parameter); } else if (args.Command == ApplicationCommands.Find) { dv.OnFindCommand(); } else if (args.Command == ComponentCommands.ScrollPageUp) { dv.OnScrollPageUpCommand(); } else if (args.Command == ComponentCommands.ScrollPageDown) { dv.OnScrollPageDownCommand(); } else if (args.Command == ComponentCommands.ScrollPageLeft) { dv.OnScrollPageLeftCommand(); } else if (args.Command == ComponentCommands.ScrollPageRight) { dv.OnScrollPageRightCommand(); } else if (args.Command == ComponentCommands.MoveUp) { dv.OnMoveUpCommand(); } else if (args.Command == ComponentCommands.MoveDown) { dv.OnMoveDownCommand(); } else if (args.Command == ComponentCommands.MoveLeft) { dv.OnMoveLeftCommand(); } else if (args.Command == ComponentCommands.MoveRight) { dv.OnMoveRightCommand(); } else if (args.Command == NavigationCommands.Zoom) { DoZoom(dv, args.Parameter); } else if (args.Command == NavigationCommands.DecreaseZoom) { dv.DecreaseZoom(); } else if (args.Command == NavigationCommands.IncreaseZoom) { dv.IncreaseZoom(); } else if (args.Command == NavigationCommands.PreviousPage) { dv.PreviousPage(); } else if (args.Command == NavigationCommands.NextPage) { dv.NextPage(); } else if (args.Command == NavigationCommands.FirstPage) { dv.FirstPage(); } else if (args.Command == NavigationCommands.LastPage) { dv.LastPage(); } else { Invariant.Assert(false, "Command not handled in ExecutedRoutedEventHandler."); } } ////// Helper for the FitToMaxPagesAcross Command, called from ExecutedRoutedEventHandler. /// Verifies that the data passed into ExecutedRoutedEventHandler is valid for a column count /// and sets the MaxPagesAcross property appropriately. /// /// the DocumentViewer that received the command /// the data associated with this command private static void DoFitToMaxPagesAcross(DocumentViewer dv, object data) { // Check that args is valid if (data != null) { int columnValue = 0; bool isValidArg = true; // If data is an int, then cast if (data is int) { columnValue = (int)data; } // If args.Data is a string, then parse else if (data is string) { try { columnValue = System.Convert.ToInt32((string)data, CultureInfo.CurrentCulture); } // Catch only the expected parse exceptions catch (ArgumentNullException) { isValidArg = false; } catch (FormatException) { isValidArg = false; } catch (OverflowException) { isValidArg = false; } } // Argument wasn't a valid int, throw an exception. if (!isValidArg) { throw new ArgumentException(SR.Get(SRID.DocumentViewerArgumentMustBeInteger), "data"); } dv.OnFitToMaxPagesAcrossCommand(columnValue); } else { throw new ArgumentNullException("data"); } } ////// Helper for the Zoom Command, called from ExecutedRoutedEventHandler. /// Verifies that the data passed into ExecutedRoutedEventHandler is valid for a zoom factor /// and sets the Zoom property appropriately. /// /// The DocumentViewer that recieved the command /// the data associated with this command private static void DoZoom(DocumentViewer dv, object data) { // Check that args is valid if (data != null) { // If a ZoomConverter doesn't exist, create one. if (dv._zoomPercentageConverter == null) { dv._zoomPercentageConverter = new ZoomPercentageConverter(); } // Use ZoomConverter to convert argument to zoom value. // We use InvariantCulture because the Command arguments are typically // defined in XAML or code, which is culture invariant. object zoomValue = dv._zoomPercentageConverter.ConvertBack(data, typeof(double), null, CultureInfo.InvariantCulture); // Argument wasn't a valid percent, throw an exception. if (zoomValue == DependencyProperty.UnsetValue) { throw new ArgumentException(SR.Get(SRID.DocumentViewerArgumentMustBePercentage), "data"); } dv.Zoom = (double)zoomValue; } else { throw new ArgumentNullException("data"); } } #endregion Commands ////// Register our properties' metadata so that our DependencyProperties function. /// private static void RegisterMetadata() { DefaultStyleKeyProperty.OverrideMetadata(typeof(DocumentViewer), new FrameworkPropertyMetadata(typeof(DocumentViewer))); _dType = DependencyObjectType.FromSystemTypeInternal(typeof(DocumentViewer)); } ////// Initializes our DocumentScrollInfo. /// private void SetUp() { // Enable selection. IsSelectionEnabled = true; // Set the TextBox.AcceptsReturn flag -- this will disable the "select everything on focus" // behavior of the TextEditor. // We reset the TextBox.AcceptsTab property to keep the TextEditor from eating Tab. SetValue(TextBox.AcceptsTabProperty, false); // Construct the DocumentGrid. CreateIDocumentScrollInfo(); } ////// CreateIDocumentScrollInfo instantiates our IDocumentScrollInfo control /// and sets/resets default properties. /// private void CreateIDocumentScrollInfo() { if (_documentScrollInfo == null) { // Construct IDocumentScrollInfo (DocumentGrid). _documentScrollInfo = new DocumentGrid(); _documentScrollInfo.DocumentViewerOwner = this; //If IDocumentScrollInfo is a FrameworkElement we can give it a //Name for automation. FrameworkElement fe = _documentScrollInfo as FrameworkElement; if (fe != null) { fe.Name = "DocumentGrid"; fe.Focusable = false; //We don't allow Tabbing to the IDocumentScrollInfo -- //The ScrollViewer parent is what is tabbed to. fe.SetValue(KeyboardNavigation.IsTabStopProperty, false); TextEditorRenderScope = fe; } } //Assign our content to the IDSI. AttachContent(); //Give the IDocumentScrollInfo object default values for important properties. _documentScrollInfo.VerticalPageSpacing = VerticalPageSpacing; _documentScrollInfo.HorizontalPageSpacing = HorizontalPageSpacing; } ////// Assigns our current Document to our IDSI and gives it a reference to our TextEditor. /// private void AttachContent() { _documentScrollInfo.Content = (Document != null) ? Document.DocumentPaginator as DynamicDocumentPaginator : null; IsSelectionEnabled = true; } ////// FindContentHost does 2 things: /// - It finds "marked" elements (elements with ContentHost attached properties) /// in the current Visual Tree. /// - It takes these elements and populates them with the proper UI (for Content) /// ///There must be a ScrollViewer in /// DocumentViewer's visual tree which has the Name PART_ContentHost. private void FindContentHost() { // Find the "special" element in the tree marked as the // ContentHost. This element must exist or we throw. ScrollViewer contentHost = this.Template.FindName(_contentHostName, this) as ScrollViewer; // Make sure contentHost exists. This wouldn't be much of a DocumentViewer if it didn't, // since we need someplace to throw our IDocumentScrollInfo so we can display documents. // Throw an exception if it doesn't exist. if (contentHost == null) { throw new NotSupportedException(SR.Get(SRID.DocumentViewerStyleMustIncludeContentHost)); } _scrollViewer = contentHost; _scrollViewer.Focusable = false; Invariant.Assert(_documentScrollInfo != null, "IDocumentScrollInfo cannot be null."); //Make the IDSI the child of the ScrollViewer. _scrollViewer.Content = _documentScrollInfo; _scrollViewer.ScrollInfo = _documentScrollInfo; // Set IDocumentScrollInfo's content if its content is invalid. if (_documentScrollInfo.Content != Document) { AttachContent(); } } #region Find ////// Instantiates the Find Toolbar and adds it to our Visual tree where appropriate. /// ////// Critical: FindToolBar..ctor is defined in a non-APTCA assembly. /// TreatAsSafe: call to FindToolBar..ctor does not entail any risk. /// [SecurityCritical, SecurityTreatAsSafe] private void InstantiateFindToolBar() { //First, find the correct place to insert toolbar. // Location is defined by named element, FindToolbarHost. ContentControl findHost = this.Template.FindName(_findToolBarHostName, this) as ContentControl; // Only create and hook up the toolbar, if we found a place to put it. if (findHost != null) { if( _findToolbar == null ) { // create the new object _findToolbar = new FindToolBar(); // add the event handlers _findToolbar.FindClicked += new EventHandler(OnFindInvoked); //set initial DocumentLoaded state. _findToolbar.DocumentLoaded = (Document != null) ? true : false; } // Now insert the toolbar, if it isn't already parented elsewhere. // (It will have been disconnected from DocumentViewer on a Theme or // Template change.) if (!_findToolbar.IsAncestorOf(this)) { ((IAddChild)findHost).AddChild(_findToolbar); } } } ////// 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 ////// Critical: get_SearchUp is defined in a non-APTCA assembly. /// TreatAsSafe: call to get_SearchUp does not entail any risk. /// [SecurityCritical, SecurityTreatAsSafe] private void OnFindInvoked(object sender, EventArgs e) { EventTrace.NormalTraceEvent(EventTraceGuidId.DRXFINDGUID, MS.Utility.EventType.StartEvent); if (_findToolbar != null && TextEditor != null) { ITextRange findResult = Find(_findToolbar); // If we found something, select it. if ((findResult != null) && (!findResult.IsEmpty)) { //Give ourselves focus, this ensures that the selection //will be made visible after it's made. this.Focus(); if (_documentScrollInfo != null) { _documentScrollInfo.MakeSelectionVisible(); } //Put the focus back on the Find Toolbar's TextBox to search again. _findToolbar.GoToTextBox(); } else { // No, we did not find anything. Alert the user. // build our message string. string messageString = _findToolbar.SearchUp ? SR.Get(SRID.DocumentViewerSearchUpCompleteLabel) : SR.Get(SRID.DocumentViewerSearchDownCompleteLabel); messageString = String.Format( CultureInfo.CurrentCulture, messageString, _findToolbar.SearchText); Window wnd = null; if (Application.Current != null && Application.Current.CheckAccess()) { wnd = Application.Current.MainWindow; } SecurityHelper.ShowMessageBoxHelper( wnd, messageString, SR.Get(SRID.DocumentViewerSearchCompleteTitle), MessageBoxButton.OK, MessageBoxImage.Asterisk); } } EventTrace.NormalTraceEvent(EventTraceGuidId.DRXFINDGUID, MS.Utility.EventType.EndEvent); } ////// This is just a private convenience method for handling the Find command in a /// localized place. /// ////// Critical: GoToTextBox is defined in a non-APTCA assembly. /// TreatAsSafe: call to GoToTextBox does not entail any risk. /// [SecurityCritical, SecurityTreatAsSafe] private void GoToFind() { if (_findToolbar != null) { _findToolbar.GoToTextBox(); } } ////// This is just a private convenience method to handle those keyboard /// shortcuts related to the Find Command. /// localized place. /// ////// Critical: get_SearchUp is defined in a non-APTCA assembly. /// TreatAsSafe: call to get_SearchUp does not entail any risk. /// [SecurityCritical, SecurityTreatAsSafe] private KeyEventArgs ProcessFindKeys(KeyEventArgs e) { if (_findToolbar == null || Document == null) { // Short-circuit. Find isn't enabled, // just exit. return e; } // F3 -- Invoke Find if (e.Key == Key.F3) { e.Handled = true; //If the Shift key is also pressed, then search up. _findToolbar.SearchUp = ((e.KeyboardDevice.Modifiers & ModifierKeys.Shift) == ModifierKeys.Shift); OnFindInvoked(this, EventArgs.Empty); } return e; } #endregion Find ////// Find the location in the zoomLevelCollection such that it is the closest /// zoomLevel equal to or lower than the current zoom. /// private void FindZoomLevelIndex() { // Ensure the list of zoom levels is created. if (_zoomLevelCollection != null) { // If the index is not in a valid location, update it to the list start. if ((_zoomLevelIndex < 0) || (_zoomLevelIndex >= _zoomLevelCollection.Length)) { _zoomLevelIndex = 0; _zoomLevelIndexValid = false; } // Check if the current index is in the correct location in the list. if (!_zoomLevelIndexValid) { // Since the index is not in the correct location in the list // (ie the Zoom was set by another means), then // search the list of possible zooms for the correct location. double currentZoom = Zoom; // Currently this search is done using a linear method which is // fine given the small size of the list. If we increase the list // size, then a simple binary search could increaes performance. // Search the list of zoom's from highest to lowest until the // appropriate "floor" level (level equal to, or // lower than the current zoom) is found. int loopIndex; for (loopIndex = 0; loopIndex < _zoomLevelCollection.Length - 1; loopIndex++) { if (currentZoom >= _zoomLevelCollection[loopIndex]) { // Closest equal or lower match found break; } } // Assign the current zoom level, and mark that our index is valid // (for future Increase / Decrease zoom calls). _zoomLevelIndex = loopIndex; _zoomLevelIndexValid = true; } } } ////// Determines if the parameter represents a valid double (that is a value other /// than NaN, PositiveInfinity, or NegativeInfinity). /// /// The double value to be checked ///True if the double value is valid, false otherwise. private static bool DoubleValue_Validate(object value) { // bool ok; // Ensure value is double if (value is double) { double checkValue = (double)value; // Check if double is within an assumed range if ((double.IsNaN(checkValue)) || (double.IsInfinity(checkValue))) { ok = false; } else { ok = true; } } else { ok = false; } return ok; } ////// Converts an IDocumentScrollInfo's Scale value to a Zoom /// /// A valid IDocumentScrollInfo.Scale value. ///A Zoom value private static double ScaleToZoom(double scale) { return scale * 100.0; } ////// Converts a Zoom value to an IDocumentScrollInfo.Scale value. /// /// A valid Zoom value. ///An IDocumentScrollInfo.Scale value. private static double ZoomToScale(double zoom) { return zoom / 100.0; } #region DependencyProperties #region HorizontalOffset ////// Validate the value passed in as a possible offset (either vertical or horizontal) /// /// A double representing the requested offset ///True if the offset is valid, false otherwise. private static bool ValidateOffset(object value) { return DoubleValue_Validate(value) && ((double)value >= 0.0); } ////// The HorizontalOffset has changed, and needs to be updated. /// private static void OnHorizontalOffsetChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { DocumentViewer dv = (DocumentViewer)d; double newOffset = (double) e.NewValue; // If the HorizontalOffset has changed and it isn't due to a change that originated // from our IDocumentScrollInfo object, then set the new offset value on the IDocumentScrollInfo. if (!dv._internalIDSIChange && (dv._documentScrollInfo != null)) { dv._documentScrollInfo.SetHorizontalOffset(newOffset); } dv.SetValue(CanMoveLeftPropertyKey, newOffset > 0.0); dv.SetValue(CanMoveRightPropertyKey, newOffset < (dv.ExtentWidth - dv.ViewportWidth)); } #endregion HorizontalOffset #region VerticalOffset ////// The VerticalOffset has changed, and needs to be updated. /// private static void OnVerticalOffsetChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { DocumentViewer dv = (DocumentViewer)d; double newOffset = (double) e.NewValue; // If the VerticalOffset has changed and it isn't due to a change that originated // from our IDocumentScrollInfo object, then set the new offset value on the IDocumentScrollInfo. if ( !dv._internalIDSIChange && (dv._documentScrollInfo != null)) { dv._documentScrollInfo.SetVerticalOffset(newOffset); } dv.SetValue(CanMoveUpPropertyKey, newOffset > 0.0); dv.SetValue(CanMoveDownPropertyKey, newOffset < (dv.ExtentHeight - dv.ViewportHeight)); } #endregion VerticalOffset #region ExtentWidth private static void OnExtentWidthChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { DocumentViewer dv = (DocumentViewer)d; dv.SetValue(CanMoveRightPropertyKey, dv.HorizontalOffset < ((double) e.NewValue - dv.ViewportWidth)); } #endregion ExtentWidth #region ExtentHeight private static void OnExtentHeightChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { DocumentViewer dv = (DocumentViewer)d; dv.SetValue(CanMoveDownPropertyKey, dv.VerticalOffset < ((double) e.NewValue - dv.ViewportHeight)); } #endregion ExtentHeight #region ViewportWidth private static void OnViewportWidthChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { DocumentViewer dv = (DocumentViewer)d; double newWidth = (double) e.NewValue; dv.SetValue(CanMoveRightPropertyKey, dv.HorizontalOffset < (dv.ExtentWidth - (double) e.NewValue)); } #endregion ViewportWidth #region ViewportHeight private static void OnViewportHeightChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { DocumentViewer dv = (DocumentViewer)d; double newHeight = (double) e.NewValue; dv.SetValue(CanMoveDownPropertyKey, dv.VerticalOffset < (dv.ExtentHeight - newHeight)); } #endregion ViewportHeight #region ShowPageBorders ////// ShowPageBorders has changed, and needs to be updated. /// private static void OnShowPageBordersChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { DocumentViewer dv = (DocumentViewer) d; // If the ShowPageBorders has changed, then set the new value on the IDocumentScrollInfo. if (dv._documentScrollInfo != null) { dv._documentScrollInfo.ShowPageBorders = (bool) e.NewValue; } } #endregion ShowPageBorders #region Zoom private static object CoerceZoom(DependencyObject d, object value) { double checkValue = (double) value; if (checkValue < DocumentViewerConstants.MinimumZoom) { return DocumentViewerConstants.MinimumZoom; } if (checkValue > DocumentViewerConstants.MaximumZoom) { return DocumentViewerConstants.MaximumZoom; } return value; } ////// The Zoom has changed, and needs to be updated. /// private static void OnZoomChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { DocumentViewer dv = (DocumentViewer)d; // If the ZoomPercentage has changed, then update the IDocumentScrollInfo. if (dv._documentScrollInfo != null) { double newZoom = (double) e.NewValue; if (!dv._internalIDSIChange) { //Perf Tracing - Mark Zoom Change Start if (EventTrace.IsEnabled(EventTrace.Flags.performance, EventTrace.Level.normal)) { EventTrace.EventProvider.TraceEvent(EventTrace.GuidFromId(EventTraceGuidId.DRXZOOMGUID), MS.Utility.EventType.Info, (int) newZoom); } // Set the new zoom scale on IDocumentScrollInfo dv._documentScrollInfo.SetScale(DocumentViewer.ZoomToScale(newZoom)); } dv.SetValue(CanIncreaseZoomPropertyKey, newZoom < DocumentViewerConstants.MaximumZoom); dv.SetValue(CanDecreaseZoomPropertyKey, newZoom > DocumentViewerConstants.MinimumZoom); // If the zoom was not set by Increase / DecreaseZoom commands, // then invalidate the zoom level index. if (!dv._updatingInternalZoomLevel) { dv._zoomLevelIndexValid = false; } } } #endregion ZoomPercentage #region MaxPagesAcross ////// Validate the value passed in as a possible MaxPagesAcross /// /// An int MaxPagesAcross value ///True if the value is valid, false otherwise. private static bool ValidateMaxPagesAcross(object value) { int checkValue = (int)value; return checkValue > 0 && checkValue <= DocumentViewerConstants.MaximumMaxPagesAcross; } ////// The MaxPagesAcross has changed, and needs to be updated. /// private static void OnMaxPagesAcrossChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { DocumentViewer dv = (DocumentViewer)d; //regardless of whether the value of MaxPagesAcross has actually changed. //Setting this property will cause content to reflow or rescale to fit and we //want this to happen even if the same number of columns will be visible. //As an example, if we're at 500% showing 1 page, setting MaxPagesAcross to 1 will //cause the Zoom to change to show precisely one column. if (!dv._internalIDSIChange) { dv._documentScrollInfo.SetColumns((int) e.NewValue); } } #endregion GridColumnCount #region VerticalPageSpacing ////// Validate the value passed in as a possible PageSpacing, either vertical or horizontal /// /// A value representing the requested page spacing ///True if the offset is valid, false otherwise. private static bool ValidatePageSpacing(object value) { return DoubleValue_Validate(value) && ((double)value >= 0.0); } ////// The VerticalPageSpacing has changed, and needs to be updated. /// private static void OnVerticalPageSpacingChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { DocumentViewer dv = (DocumentViewer)d; // If the VerticalPageSpacing has changed, then set the new value on IDocumentScrollInfo. if (dv._documentScrollInfo != null) { dv._documentScrollInfo.VerticalPageSpacing = (double) e.NewValue; } } #endregion VerticalPageSpacing #region HorizontalPageSpacing ////// The HorizontalPageSpacing has changed, and needs to be updated. /// private static void OnHorizontalPageSpacingChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { DocumentViewer dv = (DocumentViewer)d; // If the HorizontalPageSpacing has changed, then set the new value on IDocumentScrollInfo. if (dv._documentScrollInfo != null) { dv._documentScrollInfo.HorizontalPageSpacing = (double) e.NewValue; } } #endregion HorizontalPageSpacing #endregion Dependency Properties #endregion Private Methods //------------------------------------------------------ // // Private Fields // //----------------------------------------------------- #region Private Fields // UI Elements private IDocumentScrollInfo _documentScrollInfo; private ScrollViewer _scrollViewer; private ZoomPercentageConverter _zoomPercentageConverter; //Find ToolBar private FindToolBar _findToolbar; // The FindToolbar UI // Default values for DPs private const double _horizontalOffsetDefault = 0.0; private const double _verticalOffsetDefault = 0.0; private const double _extentWidthDefault = 0.0; private const double _extentHeightDefault = 0.0; private const double _viewportWidthDefault = 0.0; private const double _viewportHeightDefault = 0.0; private const bool _showPageBordersDefault = true; private const double _zoomPercentageDefault = 100.0; private const int _maxPagesAcrossDefault = 1; private const double _verticalPageSpacingDefault = 10.0; private const double _horizontalPageSpacingDefault = 10.0; private const bool _canMoveUpDefault = false; private const bool _canMoveDownDefault = false; private const bool _canMoveLeftDefault = false; private const bool _canMoveRightDefault = false; private const bool _canIncreaseZoomDefault = true; private const bool _canDecreaseZoomDefault = true; // private const bool _isToolbarMaximizedDefault = true; // Our Commands, instantiated on a pay-for-play basis private static RoutedUICommand _viewThumbnailsCommand; private static RoutedUICommand _fitToWidthCommand; private static RoutedUICommand _fitToHeightCommand; private static RoutedUICommand _fitToMaxPagesAcrossCommand; // This list is assumed to be in decreasing order. private static double[] _zoomLevelCollection = {5000.0, 4000.0, 3200.0, 2400.0, 2000.0, 1600.0, 1200.0, 800.0, 400.0, 300.0, 200.0, 175.0, 150.0, 125.0, 100.0, 75.0, 66.0, 50.0, 33.0, 25.0, 10.0, 5.0}; private int _zoomLevelIndex; // = 0 private bool _zoomLevelIndexValid; // = false private bool _updatingInternalZoomLevel; // = false private bool _internalIDSIChange; // = false private bool _pageViewCollectionChanged; // = false private bool _firstDocumentAssignment = true; private const string _findToolBarHostName = "PART_FindToolBarHost"; private const string _contentHostName = "PART_ContentHost"; #endregion #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. // // // // Description: Control for displaying paginated content. // // History: // 06/01/2002 - JerrySh - Created. // 07/09/2003 - JDersch - Initial port to WCP tree // 11/07/2003 - JDersch - VisualTree Styling overhaul // 09/21/2004 - JDersch - Cut Annotations, RM & DigSig and Browser-Hosted Toolband // 09/23/2004 - JeremyNS - Cut INavigator, IUriContext, SourceProperty // 10/21/2004 - JeremyNS - Overhauled, and renamed from PageViewer to DocumentViewer // 05/10/2005 - JDersch - Ported to DocumentViewerBase // //--------------------------------------------------------------------------- using MS.Internal; // For Invariant.Assert using MS.Internal.Commands; using MS.Internal.Documents; using MS.Internal.PresentationFramework; // For SecurityHelper using MS.Utility; using System; using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; // For DesignerSerializationVisibility using System.Globalization; using System.Reflection; using System.Windows; using System.Windows.Automation; using System.Windows.Automation.Peers; using System.Windows.Automation.Provider; using System.Windows.Controls; using System.Windows.Controls.Primitives; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Navigation; // For HyperLink navigation event. using System.Windows.Markup; using MS.Internal.Automation; // For TextAdaptor. using System.Security; namespace System.Windows.Controls { ////// DocumentViewer is a control that allows developers to create a custom reading /// experience in their applications for digital documents. /// ////// http://d2/DRX/default.aspx [TemplatePart(Name = "PART_FindToolBarHost", Type = typeof(ContentControl))] [TemplatePart(Name = "PART_ContentHost", Type = typeof(ScrollViewer))] public class DocumentViewer : DocumentViewerBase { //----------------------------------------------------- // // Constructors // //----------------------------------------------------- #region Constructors ////// Initializes class-wide settings. /// static DocumentViewer() { // Create our CommandBindings CreateCommandBindings(); // Register property metadata RegisterMetadata(); } ////// Instantiates a new instance of a DocumentViewer /// public DocumentViewer() : base() { //Perf Tracing - DocumentViewer Construction EventTrace.NormalTraceEvent(EventTraceGuidId.DRXINSTANTIATEDGUID, MS.Utility.EventType.Info); SetUp(); } #endregion Constructors //------------------------------------------------------ // // Public Methods // //----------------------------------------------------- #region Public Methods #region Command convenience methods ////// Tells DocumentViewer to display a "thumbnail view" of pages. This is analogous /// to the ViewThumbnailsCommand. /// public void ViewThumbnails() { OnViewThumbnailsCommand(); } ////// Tells DocumentViewer to fit a single page to the width of the current viewport. /// This is analogous to the FitToWidthCommand. /// public void FitToWidth() { OnFitToWidthCommand(); } ////// Tells DocumentViewer to fit a single page to the height of the current viewport. /// This is analogous to the FitToHeightCommand. /// public void FitToHeight() { OnFitToHeightCommand(); } ////// Tells DocumentViewer to fit the current MaxPagesAcross count to the current /// viewport. This is analogous to the FitToMaxPagesAcrossCommand. /// public void FitToMaxPagesAcross() { OnFitToMaxPagesAcrossCommand(); } ////// Tells DocumentViewer to fit the specified number of pages across to the current viewport /// and sets MaxPagesAcross to the passed in value. This is analogous to the /// FitMaxPagesAcrossCommand. /// /// public void FitToMaxPagesAcross(int pagesAcross) { if (ValidateMaxPagesAcross(pagesAcross)) { if (_documentScrollInfo != null) { _documentScrollInfo.FitColumns(pagesAcross); } } else { throw new ArgumentOutOfRangeException("pagesAcross"); } } ////// Tells DocumentViewer to invoke the Find Dialog. This is analogous to the /// FindCommand. /// public void Find() { OnFindCommand(); } ////// Tells DocumentViewer to scroll up by one viewport. This is analogous to the /// ScrollPageUpCommand. /// public void ScrollPageUp() { OnScrollPageUpCommand(); } ////// Tells DocumentViewer to scroll down by one viewport. This is analogous to the /// ScrollPageDownCommand. /// public void ScrollPageDown() { OnScrollPageDownCommand(); } ////// Tells DocumentViewer to scroll left by one viewport. This is analogous to the /// ScrollPageLeftCommand. /// public void ScrollPageLeft() { OnScrollPageLeftCommand(); } ////// Tells DocumentViewer to scroll right by one viewport. This is analogous to the /// ScrollPageRightCommand. /// public void ScrollPageRight() { OnScrollPageRightCommand(); } ////// Tells DocumentViewer to scroll up by one line (16px). This is analogous to the /// MoveUpCommand. /// public void MoveUp() { OnMoveUpCommand(); } ////// Tells DocumentViewer to scroll down by one line (16px). This is analogous to the /// MoveDownCommand. /// public void MoveDown() { OnMoveDownCommand(); } ////// Tells DocumentViewer to scroll left by one line (16px). This is analogous to the /// MoveLeftCommand. /// public void MoveLeft() { OnMoveLeftCommand(); } ////// Tells DocumentViewer to scroll right by one line (16px). This is analogous to the /// MoveRightCommand. /// public void MoveRight() { OnMoveRightCommand(); } ////// Tells DocumentViewer to increase Zoom by a predefined, nonlinear value. This is /// analogous to the IncreaseZoomCommand. /// public void IncreaseZoom() { OnIncreaseZoomCommand(); } ////// Tells DocumentViewer to decrease Zoom by a predefined, nonlinear value. This is /// analogous to the DecreaseZoomCommand. /// public void DecreaseZoom() { OnDecreaseZoomCommand(); } #endregion Command convenience methods ////// Called when the Template's tree has been generated /// ////// This method is commonly used to check the status of the visual /// tree prior to rendering, so that elements of the tree can be /// customized before they are shown. /// If a style is changed that affects the visual tree, the /// ApplyTemplate method will expand the new visual tree and return /// true. Otherwise, it will return false. /// When overriding this method, be sure to call the ApplyTemplate /// method of the base class. /// ////// True if the Visual Tree has been created /// ///There must be a ScrollViewer in /// DocumentViewer's visual tree which has Name PART_ContentHost. public override void OnApplyTemplate() { base.OnApplyTemplate(); // Walk the visual tree, locating those elements marked with the special // properties such as "I'm the Content area!" FindContentHost(); // Create the Find toolbar and add it to our Visual Tree when appropriate. InstantiateFindToolBar(); //Perf Tracing - DocumentViewer Visuals Created EventTrace.NormalTraceEvent(EventTraceGuidId.DRXSTYLECREATEDGUID, MS.Utility.EventType.Info); // If unset, we will set the ContextMenu property to null -- this will prevent the TextEditor // from overriding our ContextMenu with its own. The TextEditor checks the UIScope (DocumentViewer) // not the RenderScope (DocumentGrid) for previously-set Context Menus, and if it finds one (or if // it finds that ContextMenu has explicitly been set to null, it will not override it. // Since DocumentViewer doesn't have a ContextMenu -- the ContextMenu is set on DocumentGrid which the // TextEditor won't find, we set ContextMenu to null here. // Yes, this seems, on the surface, to be a bit redundant -- but there is a difference between an // "unset null" and an "explicitly set" null to the Property engine that the TextEditor looks for. // We check that the ContextMenu is null because we don't want to override any user-specified ContextMenus. if (this.ContextMenu == null) { this.ContextMenu = null; } } #endregion Public Methods //------------------------------------------------------ // // Public Properties // //------------------------------------------------------ #region Public Properties #region Commands ////// This command will invoke ViewThumbnails method, causing as many pages /// as feasible to be displayed in the current viewport. /// public static RoutedUICommand ViewThumbnailsCommand { get { return _viewThumbnailsCommand; } } ////// This command will invoke the FitToWidth method, /// setting the layout to 1 page across, and zooming so that one page is displayed /// at the width of the current viewport. /// public static RoutedUICommand FitToWidthCommand { get { return _fitToWidthCommand; } } ////// This command will invoke the FitToWidth method, /// setting the layout to 1 page across, and zooming so that one page is displayed /// at the height of the current viewport. /// public static RoutedUICommand FitToHeightCommand { get { return _fitToHeightCommand; } } ////// This command will invoke the FitToMaxPagesAcross method, /// effectively setting MaxPagesAcross /// to the value of the parameter and fitting those pages into view. /// public static RoutedUICommand FitToMaxPagesAcrossCommand { get { return _fitToMaxPagesAcrossCommand; } } #endregion Commands #region Dependency Properties #region HorizontalOffset ////// Reflects the current Horizontal position in the document in pixel units given /// the current page layout. /// public static readonly DependencyProperty HorizontalOffsetProperty = DependencyProperty.Register( "HorizontalOffset", typeof(double), typeof(DocumentViewer), new FrameworkPropertyMetadata( _horizontalOffsetDefault, //default value FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, //MetaData flags new PropertyChangedCallback(OnHorizontalOffsetChanged)), //changed callback new ValidateValueCallback(ValidateOffset)); //validate callback ////// Reflects the current Horizontal position in the document in pixel units given /// the current page layout. /// public double HorizontalOffset { get { return (double) GetValue(HorizontalOffsetProperty); } set { SetValue(HorizontalOffsetProperty, value); } } #endregion HorizontalOffset #region VerticalOffset ////// Reflects the current Vertical position in the document in pixel units given /// the current page layout. /// public static readonly DependencyProperty VerticalOffsetProperty = DependencyProperty.Register( "VerticalOffset", typeof(double), typeof(DocumentViewer), new FrameworkPropertyMetadata( _verticalOffsetDefault, //default value FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, //MetaData flags new PropertyChangedCallback(OnVerticalOffsetChanged)), //changed callback new ValidateValueCallback(ValidateOffset)); //validate callback ////// Reflects the current Vertical position in the document in pixel units given /// the current page layout. /// public double VerticalOffset { get { return (double) GetValue(VerticalOffsetProperty); } set { SetValue(VerticalOffsetProperty, value); } } #endregion VerticalOffset #region ExtentWidth ////// Reflects the current width of the document layout. /// private static readonly DependencyPropertyKey ExtentWidthPropertyKey = DependencyProperty.RegisterReadOnly( "ExtentWidth", typeof(double), typeof(DocumentViewer), new FrameworkPropertyMetadata( _extentWidthDefault, new PropertyChangedCallback(OnExtentWidthChanged))); ////// Reflects the current width of the document layout. /// public static readonly DependencyProperty ExtentWidthProperty = ExtentWidthPropertyKey.DependencyProperty; ////// Reflects the current width of the document layout. /// public double ExtentWidth { get { return (double) GetValue(ExtentWidthProperty); } } #endregion ExtentWidth #region ExtentHeight ////// Reflects the current height of the document layout. /// private static readonly DependencyPropertyKey ExtentHeightPropertyKey = DependencyProperty.RegisterReadOnly( "ExtentHeight", typeof(double), typeof(DocumentViewer), new FrameworkPropertyMetadata( _extentHeightDefault, new PropertyChangedCallback(OnExtentHeightChanged))); ////// Reflects the current height of the document layout. /// public static readonly DependencyProperty ExtentHeightProperty = ExtentHeightPropertyKey.DependencyProperty; ////// Reflects the current height of the document layout. /// public double ExtentHeight { get { return (double) GetValue(ExtentHeightProperty); } } #endregion ExtentHeight #region ViewportWidth ////// Reflects the current width of the DocumentViewer's content area. /// private static readonly DependencyPropertyKey ViewportWidthPropertyKey = DependencyProperty.RegisterReadOnly( "ViewportWidth", typeof(double), typeof(DocumentViewer), new FrameworkPropertyMetadata( _viewportWidthDefault, new PropertyChangedCallback(OnViewportWidthChanged))); ////// Reflects the current width of the DocumentViewer's content area. /// public static readonly DependencyProperty ViewportWidthProperty = ViewportWidthPropertyKey.DependencyProperty; ////// Reflects the current width of the DocumentViewer's content area. /// public double ViewportWidth { get { return (double) GetValue(ViewportWidthProperty); } } #endregion ViewportWidth #region ViewportHeight ////// Reflects the current height of the DocumentViewer's content area. /// private static readonly DependencyPropertyKey ViewportHeightPropertyKey = DependencyProperty.RegisterReadOnly( "ViewportHeight", typeof(double), typeof(DocumentViewer), new FrameworkPropertyMetadata( _viewportHeightDefault, new PropertyChangedCallback(OnViewportHeightChanged))); ////// Reflects the current height of the DocumentViewer's content area. /// public static readonly DependencyProperty ViewportHeightProperty = ViewportHeightPropertyKey.DependencyProperty; ////// Reflects the current height of the DocumentViewer's content area. /// public double ViewportHeight { get { return (double) GetValue(ViewportHeightProperty); } } #endregion ViewportHeight #region ShowPageBorders ////// Reflects whether a "Drop Shadow" border should be shown around the pages being displayed. /// public static readonly DependencyProperty ShowPageBordersProperty = DependencyProperty.Register( "ShowPageBorders", typeof(bool), typeof(DocumentViewer), new FrameworkPropertyMetadata( _showPageBordersDefault, //default value FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, //MetaData flags new PropertyChangedCallback(OnShowPageBordersChanged))); //changed callback ////// Reflects whether a "Drop Shadow" border should be shown around the pages being displayed. /// public bool ShowPageBorders { get { return (bool) GetValue(ShowPageBordersProperty); } set { SetValue(ShowPageBordersProperty, value); } } #endregion ShowPageBorders #region Zoom ////// Reflects the effective Zoom percentage based on the last layout related /// property set or command issued. /// If this was the last property set, or the Zoom command was last issued, /// then this will just be the last Zoom value set. /// When another layout related property (ie MaxPagesAcross, etc) was set /// or a command (ie FitToMaxPagesAcross, FitToHeight, etc) was issued, then /// this value will be the resulting Zoom value from that layout adjustment. /// /// Must be greater than 5.0 and less than 5000.0. Invalid values will throw. /// public static readonly DependencyProperty ZoomProperty = DependencyProperty.Register( "Zoom", typeof(double), typeof(DocumentViewer), new FrameworkPropertyMetadata( _zoomPercentageDefault, //default value FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, //MetaData flags new PropertyChangedCallback(OnZoomChanged), //changed callback new CoerceValueCallback(CoerceZoom))); // coercion callback ////// Reflects the effective Zoom percentage based on the last layout related /// property set or command issued. /// If this was the last property set, or the Zoom command was last issued, /// then this will just be the last Zoom value set. /// When another layout related property (ie MaxPagesAcross, etc) was set /// or a command (ie FitToMaxPagesAcross, FitToHeight, etc) was issued, then /// this value will be the resulting Zoom value from that layout adjustment. /// /// Must be greater than 5.0 and less than 5000.0. /// public double Zoom { get { return (double) GetValue(ZoomProperty); } set { SetValue(ZoomProperty, value); } } #endregion Zoom #region MaxPagesAcross ////// Reflects the number of Columns of pages displayed, based on the last /// value set through this property, or a layout related command /// (ie FitToMaxPagesAcross, ViewThumbnails, etc..) /// public static readonly DependencyProperty MaxPagesAcrossProperty = DependencyProperty.Register( "MaxPagesAcross", typeof(int), typeof(DocumentViewer), new FrameworkPropertyMetadata( _maxPagesAcrossDefault, //default value FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, //MetaData flags new PropertyChangedCallback(OnMaxPagesAcrossChanged)), //changed callback new ValidateValueCallback(ValidateMaxPagesAcross)); //validation callback ////// Reflects the number of Columns of pages displayed, based on the last /// value set through this property, or a layout related command /// (ie FitToMaxPagesAcross, ViewThumbnails, etc..) /// Valid values are from 1 to 32, inclusive. /// public int MaxPagesAcross { get { return (int) GetValue(MaxPagesAcrossProperty); } set { SetValue(MaxPagesAcrossProperty, value); } } #endregion MaxPagesAcross #region VerticalPageSpacing ////// Reflects the vertical gap between Pages when laid out, in pixel units. /// public static readonly DependencyProperty VerticalPageSpacingProperty = DependencyProperty.Register( "VerticalPageSpacing", typeof(double), typeof(DocumentViewer), new FrameworkPropertyMetadata( _verticalPageSpacingDefault, //default value new PropertyChangedCallback(OnVerticalPageSpacingChanged)), //changed callback new ValidateValueCallback(ValidatePageSpacing)); //validation callback ////// Reflects the vertical gap between Pages when laid out, in pixel units. /// public double VerticalPageSpacing { get { return (double) GetValue(VerticalPageSpacingProperty); } set { SetValue(VerticalPageSpacingProperty, value); } } #endregion VerticalPageSpacing #region HorizontalPageSpacing ////// Reflects the horizontal gap between Pages when laid out, in pixel units. /// public static readonly DependencyProperty HorizontalPageSpacingProperty = DependencyProperty.Register( "HorizontalPageSpacing", typeof(double), typeof(DocumentViewer), new FrameworkPropertyMetadata( _horizontalPageSpacingDefault, //default value new PropertyChangedCallback(OnHorizontalPageSpacingChanged)), //changed callback new ValidateValueCallback(ValidatePageSpacing)); //validation callback ////// Reflects the horizontal gap between Pages when laid out, in pixel units. /// public double HorizontalPageSpacing { get { return (double) GetValue(HorizontalPageSpacingProperty); } set { SetValue(HorizontalPageSpacingProperty, value); } } #endregion HorizontalPageSpacing #region CanMoveUp ////// Reflects whether the DocumentViewer is at the top of the current document. /// private static readonly DependencyPropertyKey CanMoveUpPropertyKey = DependencyProperty.RegisterReadOnly( "CanMoveUp", typeof(bool), typeof(DocumentViewer), new FrameworkPropertyMetadata(_canMoveUpDefault)); ////// Reflects whether the DocumentViewer is at the top of the current document. /// public static readonly DependencyProperty CanMoveUpProperty = CanMoveUpPropertyKey.DependencyProperty; ////// Reflects whether the DocumentViewer is at the top of the current document. /// public bool CanMoveUp { get { return (bool) GetValue(CanMoveUpProperty); } } #endregion CanMoveUp #region CanMoveDown ////// Reflects whether the DocumentViewer is at the bottom of the current document. /// private static readonly DependencyPropertyKey CanMoveDownPropertyKey = DependencyProperty.RegisterReadOnly( "CanMoveDown", typeof(bool), typeof(DocumentViewer), new FrameworkPropertyMetadata(_canMoveDownDefault)); ////// Reflects whether the DocumentViewer is at the bottom of the current document. /// public static readonly DependencyProperty CanMoveDownProperty = CanMoveDownPropertyKey.DependencyProperty; ////// Reflects whether the DocumentViewer is at the bottom of the current document. /// public bool CanMoveDown { get { return (bool) GetValue(CanMoveDownProperty); } } #endregion CanMoveDown #region CanMoveLeft ////// Reflects whether the DocumentViewer is at the leftmost extent of the current document. /// private static readonly DependencyPropertyKey CanMoveLeftPropertyKey = DependencyProperty.RegisterReadOnly( "CanMoveLeft", typeof(bool), typeof(DocumentViewer), new FrameworkPropertyMetadata(_canMoveLeftDefault)); ////// Reflects whether the DocumentViewer is at the leftmost extent of the current document. /// public static readonly DependencyProperty CanMoveLeftProperty = CanMoveLeftPropertyKey.DependencyProperty; ////// Reflects whether the DocumentViewer is at the leftmost extent of the current document. /// public bool CanMoveLeft { get { return (bool) GetValue(CanMoveLeftProperty); } } #endregion CanMoveLeft #region CanMoveRight ////// Reflects whether the DocumentViewer is at the rightmost extent of the current document. /// private static readonly DependencyPropertyKey CanMoveRightPropertyKey = DependencyProperty.RegisterReadOnly( "CanMoveRight", typeof(bool), typeof(DocumentViewer), new FrameworkPropertyMetadata(_canMoveRightDefault)); ////// Reflects whether the DocumentViewer is at the rightmost extent of the current document. /// public static readonly DependencyProperty CanMoveRightProperty = CanMoveRightPropertyKey.DependencyProperty; ////// Reflects whether the DocumentViewer is at the rightmost extent of the current document. /// public bool CanMoveRight { get { return (bool) GetValue(CanMoveRightProperty); } } #endregion CanMoveRight #region CanIncreaseZoom ////// Reflects whether the DocumentViewer can zoom in any further /// (ie not at the highest "zoom level") of the current document. /// private static readonly DependencyPropertyKey CanIncreaseZoomPropertyKey = DependencyProperty.RegisterReadOnly( "CanIncreaseZoom", typeof(bool), typeof(DocumentViewer), new FrameworkPropertyMetadata(_canIncreaseZoomDefault)); ////// Reflects whether the DocumentViewer can zoom in any further /// (ie not at the highest "zoom level") of the current document. /// public static readonly DependencyProperty CanIncreaseZoomProperty = CanIncreaseZoomPropertyKey.DependencyProperty; ////// Reflects whether the DocumentViewer can zoom in any further /// (ie not at the highest "zoom level") of the current document. /// public bool CanIncreaseZoom { get { return (bool) GetValue(CanIncreaseZoomProperty); } } #endregion CanIncreaseZoom #region CanDecreaseZoom ////// Reflects whether the DocumentViewer can zoom out any further /// (ie not at the lowest "zoom level") of the current document. /// private static readonly DependencyPropertyKey CanDecreaseZoomPropertyKey = DependencyProperty.RegisterReadOnly( "CanDecreaseZoom", typeof(bool), typeof(DocumentViewer), new FrameworkPropertyMetadata(_canDecreaseZoomDefault)); ////// Reflects whether the DocumentViewer can zoom out any further /// (ie not at the lowest "zoom level") of the current document. /// public static readonly DependencyProperty CanDecreaseZoomProperty = CanDecreaseZoomPropertyKey.DependencyProperty; ////// Reflects whether the DocumentViewer can zoom out any further /// (ie not at the lowest "zoom level") of the current document. /// public bool CanDecreaseZoom { get { return (bool) GetValue(CanDecreaseZoomProperty); } } #endregion CanDecreaseZoom #endregion Dependency Properties #endregion Public Properties //----------------------------------------------------- // // Public Operators // //------------------------------------------------------ //----------------------------------------------------- // // Public Events // //----------------------------------------------------- //----------------------------------------------------- // // Protected Methods // //------------------------------------------------------ #region Protected Methods ////// Creates AutomationPeer ( protected override AutomationPeer OnCreateAutomationPeer() { return new DocumentViewerAutomationPeer(this); } ///) /// /// Attaches DocumentGrid to our document when it changes. /// ////// Critical: set_DocumentLoaded is defined in a non-APTCA assembly. /// TreatAsSafe: call to set_DocumentLoaded does not entail any risk. /// [SecurityCritical, SecurityTreatAsSafe] protected override void OnDocumentChanged() { // Validate the new document type if (!(Document is FixedDocument) && !(Document is FixedDocumentSequence) && !(Document == null)) { throw new NotSupportedException(SR.Get(SRID.DocumentViewerOnlySupportsFixedDocumentSequence)); } //Call the base so that TextEditors are attached. base.OnDocumentChanged(); //Assign the content to DocumentGrid. AttachContent(); // Update the toolbar with our current document state. if (_findToolbar != null) { _findToolbar.DocumentLoaded = (Document != null) ? true : false; } // We do not automatically go to the first page on the _first_ content // assignment, for two reasons: // 1) If this is the first assignment, then we're already there by default. // 2) The user may have specified vertical or horizontal offsets in markup or // otherwise () and we need to honor // those settings. if (!_firstDocumentAssignment) { // Go to the first page of new content. OnGoToPageCommand(1); } _firstDocumentAssignment = false; } /// /// Called when a BringIntoView event is bubbled up from the Document. /// Base implementation will move the master page to the page /// on which the element occurs. /// /// The object to make visible. /// The rectangular region in the object's coordinate space which should be made visible. /// protected override void OnBringIntoView(DependencyObject element, Rect rect, int pageNumber) { // DVBase will give us a 1-indexed page number, we convert to 0-indexed. int zeroIndexed = pageNumber - 1; if (zeroIndexed >= 0 && zeroIndexed < PageCount) { _documentScrollInfo.MakeVisible(element, rect, zeroIndexed); } } ////// Handler for the PreviousPage command. /// protected override void OnPreviousPageCommand() { //Scroll to the previous row. if (_documentScrollInfo != null) { _documentScrollInfo.ScrollToPreviousRow(); } } ////// Handler for the NextPage command. /// protected override void OnNextPageCommand() { //Scroll to the previous row. if (_documentScrollInfo != null) { _documentScrollInfo.ScrollToNextRow(); } } ////// Handler for the FirstPage command. /// protected override void OnFirstPageCommand() { //Scroll to the top of the document. if (_documentScrollInfo != null) { _documentScrollInfo.MakePageVisible( 0 ); } } ////// Handler for the LastPage command. /// protected override void OnLastPageCommand() { //Scroll to the bottom of the document. if (_documentScrollInfo != null) { _documentScrollInfo.MakePageVisible( PageCount - 1 ); } } ////// Handler for the GoToPage command. /// protected override void OnGoToPageCommand(int pageNumber) { // Check if we can go to the specified page. // and navigate there. if (CanGoToPage(pageNumber)) { //Scroll to the specified page in the document. if (_documentScrollInfo != null) { // CanGoToPage should have guaranteed that this assert is always true. Invariant.Assert(pageNumber > 0, "PageNumber must be positive."); _documentScrollInfo.MakePageVisible(pageNumber - 1); } } } ////// Handler for the ViewThumbnails Command /// protected virtual void OnViewThumbnailsCommand() { if (_documentScrollInfo != null) { _documentScrollInfo.ViewThumbnails(); } } ////// Handler for the FitToWidth Command /// protected virtual void OnFitToWidthCommand() { if (_documentScrollInfo != null) { _documentScrollInfo.FitToPageWidth(); } } ////// Handler for the FitToHeight Command /// protected virtual void OnFitToHeightCommand() { if (_documentScrollInfo != null) { _documentScrollInfo.FitToPageHeight(); } } ////// Handler for the FitToMaxPagesAcross Command /// protected virtual void OnFitToMaxPagesAcrossCommand() { if (_documentScrollInfo != null) { _documentScrollInfo.FitColumns(MaxPagesAcross); } } ////// HAndler for the FitMaxPagesAcross Command /// /// protected virtual void OnFitToMaxPagesAcrossCommand(int pagesAcross) { if (ValidateMaxPagesAcross(pagesAcross)) { if (_documentScrollInfo != null) { _documentScrollInfo.FitColumns(pagesAcross); } } else { throw new ArgumentOutOfRangeException("pagesAcross"); } } ////// Handler for the Find Command /// protected virtual void OnFindCommand() { GoToFind(); } ////// This is the method that responds to the KeyDown event. /// /// protected override void OnKeyDown(KeyEventArgs e) { // Look for Find specific key inputs and process them. // If the key is processed, this event will be marked handled. e = ProcessFindKeys(e); base.OnKeyDown(e); } ////// Handler for the ScrollPageUp Command /// protected virtual void OnScrollPageUpCommand() { if (_documentScrollInfo != null) { _documentScrollInfo.PageUp(); } } ////// Handler for the ScrollPageDown Command /// protected virtual void OnScrollPageDownCommand() { if (_documentScrollInfo != null) { _documentScrollInfo.PageDown(); } } ////// Handler for the ScrollPageLeft Command /// protected virtual void OnScrollPageLeftCommand() { if (_documentScrollInfo != null) { _documentScrollInfo.PageLeft(); } } ////// Handler for the ScrollPageRight Command /// protected virtual void OnScrollPageRightCommand() { if (_documentScrollInfo != null) { _documentScrollInfo.PageRight(); } } ////// Handler for the MoveUp Command /// protected virtual void OnMoveUpCommand() { if (_documentScrollInfo != null) { _documentScrollInfo.LineUp(); } } ////// Handler for the MoveDown Command /// protected virtual void OnMoveDownCommand() { if (_documentScrollInfo != null) { _documentScrollInfo.LineDown(); } } ////// Handler for the MoveLeft Command /// protected virtual void OnMoveLeftCommand() { if (_documentScrollInfo != null) { _documentScrollInfo.LineLeft(); } } ////// Handler for the MoveRight Command /// protected virtual void OnMoveRightCommand() { if (_documentScrollInfo != null) { _documentScrollInfo.LineRight(); } } ////// Handler for the IncreaseZoom Command /// protected virtual void OnIncreaseZoomCommand() { // Check if possible to zoom in if (CanIncreaseZoom) { // Update the zoom level index to the appropriate place. double oldZoom = Zoom; FindZoomLevelIndex(); // As long as more zoomLevel's exist, increase zoom. if (_zoomLevelIndex > 0) { _zoomLevelIndex--; } // Set the zoom percentage, with _updatingInternalZoomLevel set to true to // avoid resetting the zoom level index. _updatingInternalZoomLevel = true; Zoom = DocumentViewer._zoomLevelCollection[_zoomLevelIndex]; _updatingInternalZoomLevel = false; } } ////// Handler for the DecreaseZoom Command /// protected virtual void OnDecreaseZoomCommand() { // Check if possible to zoom out. if (CanDecreaseZoom) { // Update the zoom level index to the appropriate place. double oldZoom = Zoom; FindZoomLevelIndex(); // If the current zoom value exists in the zoomLevelCollection, and can // still be zoomed out, then zoom out another level. if ((oldZoom == DocumentViewer._zoomLevelCollection[_zoomLevelIndex]) && (_zoomLevelIndex < DocumentViewer._zoomLevelCollection.Length - 1)) { _zoomLevelIndex++; } // Set the zoom percentage, with _updatingInternalZoomLevel set to true to // avoid resetting the zoom level index. _updatingInternalZoomLevel = true; Zoom = _zoomLevelCollection[_zoomLevelIndex]; _updatingInternalZoomLevel = false; } } ////// Overrides the base implementation and returns the current collection of /// DocumentPageViews being displayed in our IDSI. /// /// ///protected override ReadOnlyCollection GetPageViewsCollection(out bool changed) { ReadOnlyCollection pageViews = null; //Save off the current value of our PageView changed flag so we can //return it to indicate if the collection has actually changed. changed = _pageViewCollectionChanged; //Reset the flag so that if this is called again before InvalidatePageViews is called //it'll reflect the unchanged-ness of the collection. _pageViewCollectionChanged = false; if (_documentScrollInfo != null && _documentScrollInfo.PageViews != null) { //Return the current collection. pageViews = _documentScrollInfo.PageViews; } else { //Return an empty collection (null is not valid). pageViews = new ReadOnlyCollection (new List (0)); } return pageViews; } /// /// Overrides the OnMouseLeftButtonDown method so that we can take focus when clicked. /// /// The MouseButtonEventArgs associated with this mouse event. protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e) { base.OnMouseLeftButtonDown(e); // If no other controls in our Template have handled the event, we'll // take focus here. if (!e.Handled) { Focus(); e.Handled = true; } } ////// OnPreviewMouseWheel Zooms in/out on the document when the /// mouse wheel is scrolled and the Ctrl key is depressed. /// /// Event Arguments protected override void OnPreviewMouseWheel(MouseWheelEventArgs e) { if (e.Handled) { return; } //Get the state of the Ctrl key -- if it's pressed, we'll Zoom. //Otherwise we do nothing and let others handle this event. if (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl)) { e.Handled = true; //Zoom based on the direction of the wheel. if (e.Delta < 0) { DecreaseZoom(); } else { IncreaseZoom(); } } } #endregion Protected Methods #region Internal Methods ////// Called when our IDocumentScrollInfo has new layout information to share with us. /// internal void InvalidateDocumentScrollInfo() { // We need to see if any IDocumentScrollInfo properties that DocumentViewer // either exposes or makes use of have changed. If so we invalidate properties // or take actions here. // Any properties that are read only need to have the cache set and be invalidated // Settable DP's can be set directly (and should be, for validation) //Set our internal change flag. //DP Invalidation callbacks can check for this flag to see if a change originated //from our IDocumentScrollInfo object or not and take the appropriate action. //(Usually, if the IDSI caused the change to a DP, the invalidated callback won't need to //update the associated property on the IDSI.) _internalIDSIChange = true; SetValue(ExtentWidthPropertyKey, _documentScrollInfo.ExtentWidth); SetValue(ExtentHeightPropertyKey, _documentScrollInfo.ExtentHeight); SetValue(ViewportWidthPropertyKey, _documentScrollInfo.ViewportWidth); SetValue(ViewportHeightPropertyKey, _documentScrollInfo.ViewportHeight); if (HorizontalOffset != _documentScrollInfo.HorizontalOffset) { HorizontalOffset = _documentScrollInfo.HorizontalOffset; } if (VerticalOffset != _documentScrollInfo.VerticalOffset) { VerticalOffset = _documentScrollInfo.VerticalOffset; } // IDSI is 0-indexed SetValue(MasterPageNumberPropertyKey, _documentScrollInfo.FirstVisiblePageNumber + 1); // Convert IDocumentScrollInfo.Scale into 100-based percentage value for comparison. double scrollZoom = ScaleToZoom(_documentScrollInfo.Scale); if (Zoom != scrollZoom) { Zoom = scrollZoom; } if (MaxPagesAcross != _documentScrollInfo.MaxPagesAcross) { MaxPagesAcross = _documentScrollInfo.MaxPagesAcross; } //Reset our internal change flag. _internalIDSIChange = false; } ////// Merely calls the base's InvalidatePageViews (which is protected). /// Used by our IDSI to keep the DPV collection in [....]. /// internal void InvalidatePageViewsInternal() { //Our PageView collection has changed, set the flag. _pageViewCollectionChanged = true; InvalidatePageViews(); } ////// BringPointIntoView is called by the base if a selection goes outside of the bounds /// of the current TextView. If this happens it is necessary to scroll our content /// in an attempt to make that selection point visible, thus moving the scope of the TextView /// and allowing selection to continue. /// /// The point to be brought into view. ///Whether operation is pending or not. internal bool BringPointIntoView(Point point) { FrameworkElement grid = _documentScrollInfo as FrameworkElement; if (grid != null) { //Calculate the bounds of the DocumentGrid relative to the bounds of DocumentViewer Transform tr = this.TransformToDescendant(grid) as Transform; Rect gridRect = Rect.Transform(new Rect(grid.RenderSize), tr.Value); double verticalOffset = VerticalOffset; double horizontalOffset = HorizontalOffset; //Scroll the point into view Vertically. if (point.Y > gridRect.Y + gridRect.Height) { verticalOffset += (point.Y - (gridRect.Y + gridRect.Height)); } else if (point.Y < gridRect.Y) { verticalOffset -= (gridRect.Y - point.Y); } //Scroll the point into view Horizontally. if (point.X < gridRect.X) { horizontalOffset -= (gridRect.X - point.X); } else if (point.X > gridRect.X + gridRect.Width) { horizontalOffset += (point.X - (gridRect.X + gridRect.Width)); } VerticalOffset = Math.Max(verticalOffset, 0.0); HorizontalOffset = Math.Max(horizontalOffset, 0.0); } return false; } #endregion Internal Methods #region Internal Properties ////// Internally exposes our TextEditor's Selection, for use /// by Annotations code. /// internal ITextSelection TextSelection { get { if (TextEditor != null) { return TextEditor.Selection; } else { return null; } } } ////// Internally exposes our IDocumentScrollInfo, for use /// by Annotations code. /// internal IDocumentScrollInfo DocumentScrollInfo { get { return _documentScrollInfo; } } ////// Internally exposes out ScrollViewer, for use in DocumentViewerAutomationPeer. /// internal ScrollViewer ScrollViewer { get { return _scrollViewer; } } #endregion InternalProperties //----------------------------------------------------- // // Private Methods // //------------------------------------------------------ #region Private Methods #region Commands ////// Set up our Command bindings /// ////// Set up our RoutedUICommand bindings /// ////// Critical - creates a command binding. /// TAS - registering our own internal commands is considered safe. /// [SecurityCritical , SecurityTreatAsSafe ] private static void CreateCommandBindings() { // Create our generic ExecutedRoutedEventHandler. ExecutedRoutedEventHandler executeHandler = new ExecutedRoutedEventHandler(ExecutedRoutedEventHandler); // Create our generic QueryEnabledStatusHandler CanExecuteRoutedEventHandler queryEnabledHandler = new CanExecuteRoutedEventHandler(QueryEnabledHandler); // // Command: ViewThumbnails // Tells DocumentViewer to display thumbnails. _viewThumbnailsCommand = new RoutedUICommand(SR.Get(SRID.DocumentViewerViewThumbnailsCommandText), "ViewThumbnailsCommand", typeof(DocumentViewer), null); CommandHelpers.RegisterCommandHandler( typeof(DocumentViewer), _viewThumbnailsCommand, executeHandler, queryEnabledHandler); //no key gesture // // Command: FitToWidth // Tells DocumentViewer to zoom to the document width. _fitToWidthCommand = new RoutedUICommand( SR.Get(SRID.DocumentViewerViewFitToWidthCommandText), "FitToWidthCommand", typeof(DocumentViewer), null); CommandHelpers.RegisterCommandHandler(typeof(DocumentViewer), _fitToWidthCommand, executeHandler, queryEnabledHandler, new KeyGesture(Key.D2, ModifierKeys.Control)); // // Command: FitToHeight // Tells DocumentViewer to zoom to the document height. _fitToHeightCommand = new RoutedUICommand( SR.Get(SRID.DocumentViewerViewFitToHeightCommandText), "FitToHeightCommand", typeof(DocumentViewer), null); CommandHelpers.RegisterCommandHandler(typeof(DocumentViewer), _fitToHeightCommand, executeHandler, queryEnabledHandler); //no key gesture // // Command: MaxPagesAcross // Sets the MaxPagesAcross to the value provided. _fitToMaxPagesAcrossCommand = new RoutedUICommand( SR.Get(SRID.DocumentViewerViewFitToMaxPagesAcrossCommandText), "FitToMaxPagesAcrossCommand", typeof(DocumentViewer), null); CommandHelpers.RegisterCommandHandler(typeof(DocumentViewer), _fitToMaxPagesAcrossCommand, executeHandler, queryEnabledHandler); //no key gesture #region Library Commands // Command: ApplicationCommands.Find - Ctrl+F // Invokes DocumentViewer's Find dialog. CommandHelpers.RegisterCommandHandler(typeof(DocumentViewer), ApplicationCommands.Find, executeHandler, queryEnabledHandler); // // Command: ComponentCommands.ScrollPageUp - PageUp // Causes DocumentViewer to scroll a Viewport up. CommandHelpers.RegisterCommandHandler(typeof(DocumentViewer), ComponentCommands.ScrollPageUp, executeHandler, queryEnabledHandler, Key.PageUp); // // Command: ComponentCommands.ScrollPageDown - PageDown // Causes DocumentViewer to scroll a Viewport down. CommandHelpers.RegisterCommandHandler(typeof(DocumentViewer), ComponentCommands.ScrollPageDown, executeHandler, queryEnabledHandler, Key.PageDown); // // Command: ComponentCommands.ScrollPageLeft // Causes DocumentViewer to scroll a Viewport to the left. CommandHelpers.RegisterCommandHandler(typeof(DocumentViewer), ComponentCommands.ScrollPageLeft, executeHandler, queryEnabledHandler); //no key gesture // // Command: ComponentCommands.ScrollPageRight // Causes DocumentViewer to scroll a Viewport to the right. CommandHelpers.RegisterCommandHandler(typeof(DocumentViewer), ComponentCommands.ScrollPageRight, executeHandler, queryEnabledHandler); //no key gesture // // Command: ComponentCommands.MoveUp - Up // Causes DocumentViewer to scroll the Viewport up by 16px. CommandHelpers.RegisterCommandHandler(typeof(DocumentViewer), ComponentCommands.MoveUp, executeHandler, queryEnabledHandler, Key.Up); // // Command: ComponentCommands.MoveDown - Down // Causes DocumentViewer to scroll the Viewport down by 16px. CommandHelpers.RegisterCommandHandler(typeof(DocumentViewer), ComponentCommands.MoveDown, executeHandler, queryEnabledHandler, Key.Down); // // Command: ComponentCommands.MoveLeft - Left // Causes DocumentViewer to scroll a Viewport left by 16px. CommandHelpers.RegisterCommandHandler(typeof(DocumentViewer), ComponentCommands.MoveLeft, executeHandler, queryEnabledHandler, Key.Left); // // Command: ComponentCommands.MoveRight - Right // Causes DocumentViewer to scroll a Viewport right by 16px. CommandHelpers.RegisterCommandHandler(typeof(DocumentViewer), ComponentCommands.MoveRight, executeHandler, queryEnabledHandler, Key.Right); // // Command: NavigationCommands.Zoom // Sets DocumentViewer's Zoom to the specified level. CommandHelpers.RegisterCommandHandler(typeof(DocumentViewer), NavigationCommands.Zoom, executeHandler, queryEnabledHandler); //no key gesture // // Command: NavigationCommands.IncreaseZoom // Causes DocumentViewer to zoom in on the content. CommandHelpers.RegisterCommandHandler(typeof(DocumentViewer), NavigationCommands.IncreaseZoom, executeHandler, queryEnabledHandler, // Ctrl+Numpad '+' new KeyGesture(Key.Add, ModifierKeys.Control), // Ctrl+Numpad '+' (In case shift is held down) new KeyGesture(Key.Add, ModifierKeys.Shift | ModifierKeys.Control), // Ctrl+'+' new KeyGesture(Key.OemPlus, ModifierKeys.Control), // Ctrl+'+' (In case shift is held down) new KeyGesture(Key.OemPlus, ModifierKeys.Shift | ModifierKeys.Control)); // // Command: NavigationCommands.DecreaseZoom // Causes DocumentViewer to zoom out of the content. CommandHelpers.RegisterCommandHandler(typeof(DocumentViewer), NavigationCommands.DecreaseZoom, executeHandler, queryEnabledHandler, // Ctrl+Numpad '-' new KeyGesture(Key.Subtract, ModifierKeys.Control), // Ctrl+Numpad '-' (In case shift is held down) new KeyGesture(Key.Subtract, ModifierKeys.Shift | ModifierKeys.Control), // Ctrl+'-' new KeyGesture(Key.OemMinus, ModifierKeys.Control), // Ctrl+'-' (In case shift is held down) new KeyGesture(Key.OemMinus, ModifierKeys.Shift | ModifierKeys.Control)); // Command: NavigationCommands.PreviousPage CommandHelpers.RegisterCommandHandler(typeof(DocumentViewer), NavigationCommands.PreviousPage, executeHandler, queryEnabledHandler, new KeyGesture(Key.PageUp, ModifierKeys.Control)); // Command: NavigationCommands.NextPage CommandHelpers.RegisterCommandHandler(typeof(DocumentViewer), NavigationCommands.NextPage, executeHandler, queryEnabledHandler, new KeyGesture(Key.PageDown, ModifierKeys.Control)); // Command: NavigationCommands.FirstPage CommandHelpers.RegisterCommandHandler(typeof(DocumentViewer), NavigationCommands.FirstPage, executeHandler, queryEnabledHandler, new KeyGesture(Key.Home, ModifierKeys.Control)); // Command: NavigationCommands.FirstPage CommandHelpers.RegisterCommandHandler(typeof(DocumentViewer), NavigationCommands.LastPage, executeHandler, queryEnabledHandler, new KeyGesture(Key.End, ModifierKeys.Control)); #endregion Library Commands //Register input bindings for keyboard shortcuts that require //Command Parameters: //Zoom 100%: Requires a CommandParameter of 100.0 with the Zoom Command. //Bound to Ctrl+1. InputBinding zoom100InputBinding = new InputBinding(NavigationCommands.Zoom, new KeyGesture(Key.D1, ModifierKeys.Control)); zoom100InputBinding.CommandParameter = 100.0; CommandManager.RegisterClassInputBinding(typeof(DocumentViewer), zoom100InputBinding); //Whole Page: Requires a CommandParameter of 1 with the FitToMaxPagesAcross Command. //Bound to Ctrl+3. InputBinding wholePageInputBinding = new InputBinding(DocumentViewer.FitToMaxPagesAcrossCommand, new KeyGesture(Key.D3, ModifierKeys.Control)); wholePageInputBinding.CommandParameter = 1; CommandManager.RegisterClassInputBinding(typeof(DocumentViewer), wholePageInputBinding); //Two Pages: Requires a CommandParameter of 2 with the FitToMaxPagesAcross Command. //Bound to Ctrl+4. InputBinding twoPagesInputBinding = new InputBinding(DocumentViewer.FitToMaxPagesAcrossCommand, new KeyGesture(Key.D4, ModifierKeys.Control)); twoPagesInputBinding.CommandParameter = 2; CommandManager.RegisterClassInputBinding(typeof(DocumentViewer), twoPagesInputBinding); } ////// Central handler for QueryEnabled events fired by Commands directed at DocumentViewer. /// /// The target of this Command, expected to be DocumentViewer /// The event arguments for this event. [SecurityCritical, SecurityTreatAsSafe] private static void QueryEnabledHandler(object target, CanExecuteRoutedEventArgs args) { DocumentViewer dv = target as DocumentViewer; Invariant.Assert(dv != null, "Target of QueryEnabledEvent must be DocumentViewer."); Invariant.Assert(args != null, "args cannot be null."); // If the target is not a DocumentViewer we silently return (but note that // we have Asserted this above.) if (dv == null) { return; } // Mark this event as handled so that the CanExecute handler on the base // doesn't override our settings. args.Handled = true; // Now we set the IsEnabled flag based on the Command that fired this event // and the current state of DocumentViewer. if (args.Command == ViewThumbnailsCommand || args.Command == FitToWidthCommand || args.Command == FitToHeightCommand || args.Command == FitToMaxPagesAcrossCommand || args.Command == NavigationCommands.Zoom) { // Fit and Zoom operations are always enabled. args.CanExecute = true; } else if (args.Command == ApplicationCommands.Find) { //Find can only operate if we have a TextEditor. args.CanExecute = dv.TextEditor != null; } else if (args.Command == ComponentCommands.ScrollPageUp || args.Command == ComponentCommands.MoveUp) { // Enabling the Move/Scroll Up Commands is tied to the // state of the CanMoveUp property. args.CanExecute = dv.CanMoveUp; } else if (args.Command == ComponentCommands.ScrollPageDown || args.Command == ComponentCommands.MoveDown) { // Enabling the Move/Scroll Down Commands is tied to the // state of the CanMoveDown property. args.CanExecute = dv.CanMoveDown; } else if (args.Command == ComponentCommands.ScrollPageLeft || args.Command == ComponentCommands.MoveLeft) { // Enabling the Move/Scroll Left Commands is tied to the // state of the CanMoveLeft property. args.CanExecute = dv.CanMoveLeft; } else if (args.Command == ComponentCommands.ScrollPageRight || args.Command == ComponentCommands.MoveRight) { // Enabling the Move/Scroll Right Commands is tied to the // state of the CanMoveRight property. args.CanExecute = dv.CanMoveRight; } else if (args.Command == NavigationCommands.IncreaseZoom) { // Zooming in is only allowed if DocumentViewer has a valid Document assigned // and can increase zoom. args.CanExecute = dv.CanIncreaseZoom; } else if (args.Command == NavigationCommands.DecreaseZoom) { // Zooming out is only allowed if DocumentViewer has a valid Document assigned // and can decrease zoom. args.CanExecute = dv.CanDecreaseZoom; } else if (args.Command == NavigationCommands.PreviousPage || args.Command == NavigationCommands.FirstPage) { // Enabling the PreviousPage and FirstPage Commands is tied // to the state of the CanGoToPreviousPage property. args.CanExecute = dv.CanGoToPreviousPage; } else if (args.Command == NavigationCommands.NextPage || args.Command == NavigationCommands.LastPage) { // Enabling the NextPage and LastPage Commands is tied // to the state of the CanGoToNextPage property. args.CanExecute = dv.CanGoToNextPage; } else if (args.Command == NavigationCommands.GoToPage) { // This command is always enabled as long as there is a document loaded. args.CanExecute = (dv.Document != null); } else { args.Handled = false; // If we get here then we missed a Command above. // We assert to indicate the failure. Invariant.Assert(false, "Command not handled in QueryEnabledHandler."); } } ////// Critical - Sets the critical Handled property on the RoutedEventArgs /// TreatAsSafe - We are marking the event as handled only for the Commands that /// DocumentViewer explicitly handles -- this cannot be used for spoofing. /// ////// Central handler for all ExecuteEvents fired by Commands directed at DocumentViewer. /// /// The target of this Command, expected to be DocumentViewer. /// The event arguments associated with this event. private static void ExecutedRoutedEventHandler(object target, ExecutedRoutedEventArgs args) { DocumentViewer dv = target as DocumentViewer; Invariant.Assert(dv != null, "Target of ExecuteEvent must be DocumentViewer."); Invariant.Assert(args != null, "args cannot be null."); // If the target is not a DocumentViewer we silently return (but note that // we have Asserted this above.) if (dv == null) { return; } // 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 == ViewThumbnailsCommand) { dv.OnViewThumbnailsCommand(); } else if (args.Command == FitToWidthCommand) { dv.OnFitToWidthCommand(); } else if (args.Command == FitToHeightCommand) { dv.OnFitToHeightCommand(); } else if (args.Command == FitToMaxPagesAcrossCommand) { DoFitToMaxPagesAcross(dv, args.Parameter); } else if (args.Command == ApplicationCommands.Find) { dv.OnFindCommand(); } else if (args.Command == ComponentCommands.ScrollPageUp) { dv.OnScrollPageUpCommand(); } else if (args.Command == ComponentCommands.ScrollPageDown) { dv.OnScrollPageDownCommand(); } else if (args.Command == ComponentCommands.ScrollPageLeft) { dv.OnScrollPageLeftCommand(); } else if (args.Command == ComponentCommands.ScrollPageRight) { dv.OnScrollPageRightCommand(); } else if (args.Command == ComponentCommands.MoveUp) { dv.OnMoveUpCommand(); } else if (args.Command == ComponentCommands.MoveDown) { dv.OnMoveDownCommand(); } else if (args.Command == ComponentCommands.MoveLeft) { dv.OnMoveLeftCommand(); } else if (args.Command == ComponentCommands.MoveRight) { dv.OnMoveRightCommand(); } else if (args.Command == NavigationCommands.Zoom) { DoZoom(dv, args.Parameter); } else if (args.Command == NavigationCommands.DecreaseZoom) { dv.DecreaseZoom(); } else if (args.Command == NavigationCommands.IncreaseZoom) { dv.IncreaseZoom(); } else if (args.Command == NavigationCommands.PreviousPage) { dv.PreviousPage(); } else if (args.Command == NavigationCommands.NextPage) { dv.NextPage(); } else if (args.Command == NavigationCommands.FirstPage) { dv.FirstPage(); } else if (args.Command == NavigationCommands.LastPage) { dv.LastPage(); } else { Invariant.Assert(false, "Command not handled in ExecutedRoutedEventHandler."); } } ////// Helper for the FitToMaxPagesAcross Command, called from ExecutedRoutedEventHandler. /// Verifies that the data passed into ExecutedRoutedEventHandler is valid for a column count /// and sets the MaxPagesAcross property appropriately. /// /// the DocumentViewer that received the command /// the data associated with this command private static void DoFitToMaxPagesAcross(DocumentViewer dv, object data) { // Check that args is valid if (data != null) { int columnValue = 0; bool isValidArg = true; // If data is an int, then cast if (data is int) { columnValue = (int)data; } // If args.Data is a string, then parse else if (data is string) { try { columnValue = System.Convert.ToInt32((string)data, CultureInfo.CurrentCulture); } // Catch only the expected parse exceptions catch (ArgumentNullException) { isValidArg = false; } catch (FormatException) { isValidArg = false; } catch (OverflowException) { isValidArg = false; } } // Argument wasn't a valid int, throw an exception. if (!isValidArg) { throw new ArgumentException(SR.Get(SRID.DocumentViewerArgumentMustBeInteger), "data"); } dv.OnFitToMaxPagesAcrossCommand(columnValue); } else { throw new ArgumentNullException("data"); } } ////// Helper for the Zoom Command, called from ExecutedRoutedEventHandler. /// Verifies that the data passed into ExecutedRoutedEventHandler is valid for a zoom factor /// and sets the Zoom property appropriately. /// /// The DocumentViewer that recieved the command /// the data associated with this command private static void DoZoom(DocumentViewer dv, object data) { // Check that args is valid if (data != null) { // If a ZoomConverter doesn't exist, create one. if (dv._zoomPercentageConverter == null) { dv._zoomPercentageConverter = new ZoomPercentageConverter(); } // Use ZoomConverter to convert argument to zoom value. // We use InvariantCulture because the Command arguments are typically // defined in XAML or code, which is culture invariant. object zoomValue = dv._zoomPercentageConverter.ConvertBack(data, typeof(double), null, CultureInfo.InvariantCulture); // Argument wasn't a valid percent, throw an exception. if (zoomValue == DependencyProperty.UnsetValue) { throw new ArgumentException(SR.Get(SRID.DocumentViewerArgumentMustBePercentage), "data"); } dv.Zoom = (double)zoomValue; } else { throw new ArgumentNullException("data"); } } #endregion Commands ////// Register our properties' metadata so that our DependencyProperties function. /// private static void RegisterMetadata() { DefaultStyleKeyProperty.OverrideMetadata(typeof(DocumentViewer), new FrameworkPropertyMetadata(typeof(DocumentViewer))); _dType = DependencyObjectType.FromSystemTypeInternal(typeof(DocumentViewer)); } ////// Initializes our DocumentScrollInfo. /// private void SetUp() { // Enable selection. IsSelectionEnabled = true; // Set the TextBox.AcceptsReturn flag -- this will disable the "select everything on focus" // behavior of the TextEditor. // We reset the TextBox.AcceptsTab property to keep the TextEditor from eating Tab. SetValue(TextBox.AcceptsTabProperty, false); // Construct the DocumentGrid. CreateIDocumentScrollInfo(); } ////// CreateIDocumentScrollInfo instantiates our IDocumentScrollInfo control /// and sets/resets default properties. /// private void CreateIDocumentScrollInfo() { if (_documentScrollInfo == null) { // Construct IDocumentScrollInfo (DocumentGrid). _documentScrollInfo = new DocumentGrid(); _documentScrollInfo.DocumentViewerOwner = this; //If IDocumentScrollInfo is a FrameworkElement we can give it a //Name for automation. FrameworkElement fe = _documentScrollInfo as FrameworkElement; if (fe != null) { fe.Name = "DocumentGrid"; fe.Focusable = false; //We don't allow Tabbing to the IDocumentScrollInfo -- //The ScrollViewer parent is what is tabbed to. fe.SetValue(KeyboardNavigation.IsTabStopProperty, false); TextEditorRenderScope = fe; } } //Assign our content to the IDSI. AttachContent(); //Give the IDocumentScrollInfo object default values for important properties. _documentScrollInfo.VerticalPageSpacing = VerticalPageSpacing; _documentScrollInfo.HorizontalPageSpacing = HorizontalPageSpacing; } ////// Assigns our current Document to our IDSI and gives it a reference to our TextEditor. /// private void AttachContent() { _documentScrollInfo.Content = (Document != null) ? Document.DocumentPaginator as DynamicDocumentPaginator : null; IsSelectionEnabled = true; } ////// FindContentHost does 2 things: /// - It finds "marked" elements (elements with ContentHost attached properties) /// in the current Visual Tree. /// - It takes these elements and populates them with the proper UI (for Content) /// ///There must be a ScrollViewer in /// DocumentViewer's visual tree which has the Name PART_ContentHost. private void FindContentHost() { // Find the "special" element in the tree marked as the // ContentHost. This element must exist or we throw. ScrollViewer contentHost = this.Template.FindName(_contentHostName, this) as ScrollViewer; // Make sure contentHost exists. This wouldn't be much of a DocumentViewer if it didn't, // since we need someplace to throw our IDocumentScrollInfo so we can display documents. // Throw an exception if it doesn't exist. if (contentHost == null) { throw new NotSupportedException(SR.Get(SRID.DocumentViewerStyleMustIncludeContentHost)); } _scrollViewer = contentHost; _scrollViewer.Focusable = false; Invariant.Assert(_documentScrollInfo != null, "IDocumentScrollInfo cannot be null."); //Make the IDSI the child of the ScrollViewer. _scrollViewer.Content = _documentScrollInfo; _scrollViewer.ScrollInfo = _documentScrollInfo; // Set IDocumentScrollInfo's content if its content is invalid. if (_documentScrollInfo.Content != Document) { AttachContent(); } } #region Find ////// Instantiates the Find Toolbar and adds it to our Visual tree where appropriate. /// ////// Critical: FindToolBar..ctor is defined in a non-APTCA assembly. /// TreatAsSafe: call to FindToolBar..ctor does not entail any risk. /// [SecurityCritical, SecurityTreatAsSafe] private void InstantiateFindToolBar() { //First, find the correct place to insert toolbar. // Location is defined by named element, FindToolbarHost. ContentControl findHost = this.Template.FindName(_findToolBarHostName, this) as ContentControl; // Only create and hook up the toolbar, if we found a place to put it. if (findHost != null) { if( _findToolbar == null ) { // create the new object _findToolbar = new FindToolBar(); // add the event handlers _findToolbar.FindClicked += new EventHandler(OnFindInvoked); //set initial DocumentLoaded state. _findToolbar.DocumentLoaded = (Document != null) ? true : false; } // Now insert the toolbar, if it isn't already parented elsewhere. // (It will have been disconnected from DocumentViewer on a Theme or // Template change.) if (!_findToolbar.IsAncestorOf(this)) { ((IAddChild)findHost).AddChild(_findToolbar); } } } ////// 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 ////// Critical: get_SearchUp is defined in a non-APTCA assembly. /// TreatAsSafe: call to get_SearchUp does not entail any risk. /// [SecurityCritical, SecurityTreatAsSafe] private void OnFindInvoked(object sender, EventArgs e) { EventTrace.NormalTraceEvent(EventTraceGuidId.DRXFINDGUID, MS.Utility.EventType.StartEvent); if (_findToolbar != null && TextEditor != null) { ITextRange findResult = Find(_findToolbar); // If we found something, select it. if ((findResult != null) && (!findResult.IsEmpty)) { //Give ourselves focus, this ensures that the selection //will be made visible after it's made. this.Focus(); if (_documentScrollInfo != null) { _documentScrollInfo.MakeSelectionVisible(); } //Put the focus back on the Find Toolbar's TextBox to search again. _findToolbar.GoToTextBox(); } else { // No, we did not find anything. Alert the user. // build our message string. string messageString = _findToolbar.SearchUp ? SR.Get(SRID.DocumentViewerSearchUpCompleteLabel) : SR.Get(SRID.DocumentViewerSearchDownCompleteLabel); messageString = String.Format( CultureInfo.CurrentCulture, messageString, _findToolbar.SearchText); Window wnd = null; if (Application.Current != null && Application.Current.CheckAccess()) { wnd = Application.Current.MainWindow; } SecurityHelper.ShowMessageBoxHelper( wnd, messageString, SR.Get(SRID.DocumentViewerSearchCompleteTitle), MessageBoxButton.OK, MessageBoxImage.Asterisk); } } EventTrace.NormalTraceEvent(EventTraceGuidId.DRXFINDGUID, MS.Utility.EventType.EndEvent); } ////// This is just a private convenience method for handling the Find command in a /// localized place. /// ////// Critical: GoToTextBox is defined in a non-APTCA assembly. /// TreatAsSafe: call to GoToTextBox does not entail any risk. /// [SecurityCritical, SecurityTreatAsSafe] private void GoToFind() { if (_findToolbar != null) { _findToolbar.GoToTextBox(); } } ////// This is just a private convenience method to handle those keyboard /// shortcuts related to the Find Command. /// localized place. /// ////// Critical: get_SearchUp is defined in a non-APTCA assembly. /// TreatAsSafe: call to get_SearchUp does not entail any risk. /// [SecurityCritical, SecurityTreatAsSafe] private KeyEventArgs ProcessFindKeys(KeyEventArgs e) { if (_findToolbar == null || Document == null) { // Short-circuit. Find isn't enabled, // just exit. return e; } // F3 -- Invoke Find if (e.Key == Key.F3) { e.Handled = true; //If the Shift key is also pressed, then search up. _findToolbar.SearchUp = ((e.KeyboardDevice.Modifiers & ModifierKeys.Shift) == ModifierKeys.Shift); OnFindInvoked(this, EventArgs.Empty); } return e; } #endregion Find ////// Find the location in the zoomLevelCollection such that it is the closest /// zoomLevel equal to or lower than the current zoom. /// private void FindZoomLevelIndex() { // Ensure the list of zoom levels is created. if (_zoomLevelCollection != null) { // If the index is not in a valid location, update it to the list start. if ((_zoomLevelIndex < 0) || (_zoomLevelIndex >= _zoomLevelCollection.Length)) { _zoomLevelIndex = 0; _zoomLevelIndexValid = false; } // Check if the current index is in the correct location in the list. if (!_zoomLevelIndexValid) { // Since the index is not in the correct location in the list // (ie the Zoom was set by another means), then // search the list of possible zooms for the correct location. double currentZoom = Zoom; // Currently this search is done using a linear method which is // fine given the small size of the list. If we increase the list // size, then a simple binary search could increaes performance. // Search the list of zoom's from highest to lowest until the // appropriate "floor" level (level equal to, or // lower than the current zoom) is found. int loopIndex; for (loopIndex = 0; loopIndex < _zoomLevelCollection.Length - 1; loopIndex++) { if (currentZoom >= _zoomLevelCollection[loopIndex]) { // Closest equal or lower match found break; } } // Assign the current zoom level, and mark that our index is valid // (for future Increase / Decrease zoom calls). _zoomLevelIndex = loopIndex; _zoomLevelIndexValid = true; } } } ////// Determines if the parameter represents a valid double (that is a value other /// than NaN, PositiveInfinity, or NegativeInfinity). /// /// The double value to be checked ///True if the double value is valid, false otherwise. private static bool DoubleValue_Validate(object value) { // bool ok; // Ensure value is double if (value is double) { double checkValue = (double)value; // Check if double is within an assumed range if ((double.IsNaN(checkValue)) || (double.IsInfinity(checkValue))) { ok = false; } else { ok = true; } } else { ok = false; } return ok; } ////// Converts an IDocumentScrollInfo's Scale value to a Zoom /// /// A valid IDocumentScrollInfo.Scale value. ///A Zoom value private static double ScaleToZoom(double scale) { return scale * 100.0; } ////// Converts a Zoom value to an IDocumentScrollInfo.Scale value. /// /// A valid Zoom value. ///An IDocumentScrollInfo.Scale value. private static double ZoomToScale(double zoom) { return zoom / 100.0; } #region DependencyProperties #region HorizontalOffset ////// Validate the value passed in as a possible offset (either vertical or horizontal) /// /// A double representing the requested offset ///True if the offset is valid, false otherwise. private static bool ValidateOffset(object value) { return DoubleValue_Validate(value) && ((double)value >= 0.0); } ////// The HorizontalOffset has changed, and needs to be updated. /// private static void OnHorizontalOffsetChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { DocumentViewer dv = (DocumentViewer)d; double newOffset = (double) e.NewValue; // If the HorizontalOffset has changed and it isn't due to a change that originated // from our IDocumentScrollInfo object, then set the new offset value on the IDocumentScrollInfo. if (!dv._internalIDSIChange && (dv._documentScrollInfo != null)) { dv._documentScrollInfo.SetHorizontalOffset(newOffset); } dv.SetValue(CanMoveLeftPropertyKey, newOffset > 0.0); dv.SetValue(CanMoveRightPropertyKey, newOffset < (dv.ExtentWidth - dv.ViewportWidth)); } #endregion HorizontalOffset #region VerticalOffset ////// The VerticalOffset has changed, and needs to be updated. /// private static void OnVerticalOffsetChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { DocumentViewer dv = (DocumentViewer)d; double newOffset = (double) e.NewValue; // If the VerticalOffset has changed and it isn't due to a change that originated // from our IDocumentScrollInfo object, then set the new offset value on the IDocumentScrollInfo. if ( !dv._internalIDSIChange && (dv._documentScrollInfo != null)) { dv._documentScrollInfo.SetVerticalOffset(newOffset); } dv.SetValue(CanMoveUpPropertyKey, newOffset > 0.0); dv.SetValue(CanMoveDownPropertyKey, newOffset < (dv.ExtentHeight - dv.ViewportHeight)); } #endregion VerticalOffset #region ExtentWidth private static void OnExtentWidthChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { DocumentViewer dv = (DocumentViewer)d; dv.SetValue(CanMoveRightPropertyKey, dv.HorizontalOffset < ((double) e.NewValue - dv.ViewportWidth)); } #endregion ExtentWidth #region ExtentHeight private static void OnExtentHeightChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { DocumentViewer dv = (DocumentViewer)d; dv.SetValue(CanMoveDownPropertyKey, dv.VerticalOffset < ((double) e.NewValue - dv.ViewportHeight)); } #endregion ExtentHeight #region ViewportWidth private static void OnViewportWidthChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { DocumentViewer dv = (DocumentViewer)d; double newWidth = (double) e.NewValue; dv.SetValue(CanMoveRightPropertyKey, dv.HorizontalOffset < (dv.ExtentWidth - (double) e.NewValue)); } #endregion ViewportWidth #region ViewportHeight private static void OnViewportHeightChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { DocumentViewer dv = (DocumentViewer)d; double newHeight = (double) e.NewValue; dv.SetValue(CanMoveDownPropertyKey, dv.VerticalOffset < (dv.ExtentHeight - newHeight)); } #endregion ViewportHeight #region ShowPageBorders ////// ShowPageBorders has changed, and needs to be updated. /// private static void OnShowPageBordersChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { DocumentViewer dv = (DocumentViewer) d; // If the ShowPageBorders has changed, then set the new value on the IDocumentScrollInfo. if (dv._documentScrollInfo != null) { dv._documentScrollInfo.ShowPageBorders = (bool) e.NewValue; } } #endregion ShowPageBorders #region Zoom private static object CoerceZoom(DependencyObject d, object value) { double checkValue = (double) value; if (checkValue < DocumentViewerConstants.MinimumZoom) { return DocumentViewerConstants.MinimumZoom; } if (checkValue > DocumentViewerConstants.MaximumZoom) { return DocumentViewerConstants.MaximumZoom; } return value; } ////// The Zoom has changed, and needs to be updated. /// private static void OnZoomChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { DocumentViewer dv = (DocumentViewer)d; // If the ZoomPercentage has changed, then update the IDocumentScrollInfo. if (dv._documentScrollInfo != null) { double newZoom = (double) e.NewValue; if (!dv._internalIDSIChange) { //Perf Tracing - Mark Zoom Change Start if (EventTrace.IsEnabled(EventTrace.Flags.performance, EventTrace.Level.normal)) { EventTrace.EventProvider.TraceEvent(EventTrace.GuidFromId(EventTraceGuidId.DRXZOOMGUID), MS.Utility.EventType.Info, (int) newZoom); } // Set the new zoom scale on IDocumentScrollInfo dv._documentScrollInfo.SetScale(DocumentViewer.ZoomToScale(newZoom)); } dv.SetValue(CanIncreaseZoomPropertyKey, newZoom < DocumentViewerConstants.MaximumZoom); dv.SetValue(CanDecreaseZoomPropertyKey, newZoom > DocumentViewerConstants.MinimumZoom); // If the zoom was not set by Increase / DecreaseZoom commands, // then invalidate the zoom level index. if (!dv._updatingInternalZoomLevel) { dv._zoomLevelIndexValid = false; } } } #endregion ZoomPercentage #region MaxPagesAcross ////// Validate the value passed in as a possible MaxPagesAcross /// /// An int MaxPagesAcross value ///True if the value is valid, false otherwise. private static bool ValidateMaxPagesAcross(object value) { int checkValue = (int)value; return checkValue > 0 && checkValue <= DocumentViewerConstants.MaximumMaxPagesAcross; } ////// The MaxPagesAcross has changed, and needs to be updated. /// private static void OnMaxPagesAcrossChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { DocumentViewer dv = (DocumentViewer)d; //regardless of whether the value of MaxPagesAcross has actually changed. //Setting this property will cause content to reflow or rescale to fit and we //want this to happen even if the same number of columns will be visible. //As an example, if we're at 500% showing 1 page, setting MaxPagesAcross to 1 will //cause the Zoom to change to show precisely one column. if (!dv._internalIDSIChange) { dv._documentScrollInfo.SetColumns((int) e.NewValue); } } #endregion GridColumnCount #region VerticalPageSpacing ////// Validate the value passed in as a possible PageSpacing, either vertical or horizontal /// /// A value representing the requested page spacing ///True if the offset is valid, false otherwise. private static bool ValidatePageSpacing(object value) { return DoubleValue_Validate(value) && ((double)value >= 0.0); } ////// The VerticalPageSpacing has changed, and needs to be updated. /// private static void OnVerticalPageSpacingChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { DocumentViewer dv = (DocumentViewer)d; // If the VerticalPageSpacing has changed, then set the new value on IDocumentScrollInfo. if (dv._documentScrollInfo != null) { dv._documentScrollInfo.VerticalPageSpacing = (double) e.NewValue; } } #endregion VerticalPageSpacing #region HorizontalPageSpacing ////// The HorizontalPageSpacing has changed, and needs to be updated. /// private static void OnHorizontalPageSpacingChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { DocumentViewer dv = (DocumentViewer)d; // If the HorizontalPageSpacing has changed, then set the new value on IDocumentScrollInfo. if (dv._documentScrollInfo != null) { dv._documentScrollInfo.HorizontalPageSpacing = (double) e.NewValue; } } #endregion HorizontalPageSpacing #endregion Dependency Properties #endregion Private Methods //------------------------------------------------------ // // Private Fields // //----------------------------------------------------- #region Private Fields // UI Elements private IDocumentScrollInfo _documentScrollInfo; private ScrollViewer _scrollViewer; private ZoomPercentageConverter _zoomPercentageConverter; //Find ToolBar private FindToolBar _findToolbar; // The FindToolbar UI // Default values for DPs private const double _horizontalOffsetDefault = 0.0; private const double _verticalOffsetDefault = 0.0; private const double _extentWidthDefault = 0.0; private const double _extentHeightDefault = 0.0; private const double _viewportWidthDefault = 0.0; private const double _viewportHeightDefault = 0.0; private const bool _showPageBordersDefault = true; private const double _zoomPercentageDefault = 100.0; private const int _maxPagesAcrossDefault = 1; private const double _verticalPageSpacingDefault = 10.0; private const double _horizontalPageSpacingDefault = 10.0; private const bool _canMoveUpDefault = false; private const bool _canMoveDownDefault = false; private const bool _canMoveLeftDefault = false; private const bool _canMoveRightDefault = false; private const bool _canIncreaseZoomDefault = true; private const bool _canDecreaseZoomDefault = true; // private const bool _isToolbarMaximizedDefault = true; // Our Commands, instantiated on a pay-for-play basis private static RoutedUICommand _viewThumbnailsCommand; private static RoutedUICommand _fitToWidthCommand; private static RoutedUICommand _fitToHeightCommand; private static RoutedUICommand _fitToMaxPagesAcrossCommand; // This list is assumed to be in decreasing order. private static double[] _zoomLevelCollection = {5000.0, 4000.0, 3200.0, 2400.0, 2000.0, 1600.0, 1200.0, 800.0, 400.0, 300.0, 200.0, 175.0, 150.0, 125.0, 100.0, 75.0, 66.0, 50.0, 33.0, 25.0, 10.0, 5.0}; private int _zoomLevelIndex; // = 0 private bool _zoomLevelIndexValid; // = false private bool _updatingInternalZoomLevel; // = false private bool _internalIDSIChange; // = false private bool _pageViewCollectionChanged; // = false private bool _firstDocumentAssignment = true; private const string _findToolBarHostName = "PART_FindToolBarHost"; private const string _contentHostName = "PART_ContentHost"; #endregion #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
- FlowDocumentFormatter.cs
- TableCellsCollectionEditor.cs
- BrowserCapabilitiesCodeGenerator.cs
- ListControl.cs
- ColumnTypeConverter.cs
- XmlUtil.cs
- RawTextInputReport.cs
- CompositeKey.cs
- CqlGenerator.cs
- RelationshipConverter.cs
- PointCollectionValueSerializer.cs
- SerialStream.cs
- BoolExpression.cs
- SqlCacheDependencyDatabase.cs
- UInt16Converter.cs
- TextContainerChangeEventArgs.cs
- SecurityRuntime.cs
- XmlDictionary.cs
- ScriptControlManager.cs
- ScriptRegistrationManager.cs
- XmlSchemaGroupRef.cs
- CacheMode.cs
- SaveFileDialog.cs
- ToolStripItemClickedEventArgs.cs
- Random.cs
- VectorCollection.cs
- EventMappingSettings.cs
- FileSecurity.cs
- Point3DCollection.cs
- AppDomainProtocolHandler.cs
- DataGridViewAdvancedBorderStyle.cs
- PageParser.cs
- ObjectDataSource.cs
- ImageDesigner.cs
- WebBrowserBase.cs
- CacheDependency.cs
- AstTree.cs
- ApplicationInfo.cs
- TemplateContent.cs
- Vector3DAnimationUsingKeyFrames.cs
- DiscoveryDocument.cs
- HttpCachePolicyElement.cs
- SpnEndpointIdentityExtension.cs
- OpenFileDialog.cs
- ProtocolsSection.cs
- ColorMap.cs
- ConfigXmlReader.cs
- ApplicationSecurityInfo.cs
- ErrorRuntimeConfig.cs
- StyleSelector.cs
- ValidationSummary.cs
- InvokeHandlers.cs
- FileIOPermission.cs
- ListViewHitTestInfo.cs
- SystemIPAddressInformation.cs
- wmiutil.cs
- CompressionTracing.cs
- ConstraintEnumerator.cs
- InputMethodStateChangeEventArgs.cs
- SequenceDesigner.cs
- Brush.cs
- Effect.cs
- Msec.cs
- EncoderParameters.cs
- DiscoveryExceptionDictionary.cs
- ObservableDictionary.cs
- DataGridViewSortCompareEventArgs.cs
- StringFormat.cs
- _ListenerResponseStream.cs
- DynamicUpdateCommand.cs
- ValueTypeFixupInfo.cs
- xmlglyphRunInfo.cs
- SecurityMessageProperty.cs
- Glyph.cs
- InstanceView.cs
- Rect.cs
- ApplicationBuildProvider.cs
- FreezableCollection.cs
- ResponseStream.cs
- AssemblyName.cs
- LastQueryOperator.cs
- ConfigXmlAttribute.cs
- TraceListeners.cs
- Pen.cs
- FixedSOMSemanticBox.cs
- DbgUtil.cs
- SystemIPGlobalProperties.cs
- Thread.cs
- NonBatchDirectoryCompiler.cs
- ObjectDataSourceDesigner.cs
- NullRuntimeConfig.cs
- ListViewUpdateEventArgs.cs
- SerialPort.cs
- ExpressionBinding.cs
- PropertyChangingEventArgs.cs
- MetadataSerializer.cs
- DesignerTransaction.cs
- oledbmetadatacollectionnames.cs
- TraceHwndHost.cs
- TransformDescriptor.cs