Code:
/ Dotnetfx_Vista_SP2 / Dotnetfx_Vista_SP2 / 8.0.50727.4016 / DEVDIV / depot / DevDiv / releases / Orcas / QFE / wpf / src / Framework / System / Windows / Documents / FlowDocument.cs / 1 / FlowDocument.cs
//---------------------------------------------------------------------------- // // Copyright (C) Microsoft Corporation. All rights reserved. // // File: FlowDocument.cs // // Description: Hosts and formats text with advanced document features. // // History: // 17/08/2004 : grzegorz - created. // //--------------------------------------------------------------------------- using System.Collections; using System.ComponentModel; using System.Windows.Automation.Peers; // AutomationPeer using System.Windows.Controls; using System.Windows.Markup; using System.Windows.Media; using System.Windows.Threading; using MS.Internal; // DoubleUtil using MS.Internal.Documents; using MS.Internal.PtsHost; using MS.Internal.PtsHost.UnsafeNativeMethods; // PTS restrictions using MS.Internal.Text; namespace System.Windows.Documents { ////// FlowDocument is the paginating container for text content. /// ////// [Localizability(LocalizationCategory.Inherit, Readability = Readability.Unreadable)] [ContentProperty("Blocks")] public class FlowDocument : FrameworkContentElement, IDocumentPaginatorSource, IServiceProvider, IAddChild { static private readonly Type _typeofThis = typeof(FlowDocument); //------------------------------------------------------------------- // // Constructors // //------------------------------------------------------------------- #region Constructors ////// FlowDocument does not derive from Visual, and therefore cannot /// be added as a direct child of UIElements such as Grid. /// In order to be displayed, FlowDocument must be viewed within a FlowDocumentPageViewer, /// DocumentViewerBase-derived class, or a custom paginated viewer that utilizes the /// IDocumentPaginatorSource API. /// It also can be viewed and edited within RichTextBox control, /// available as it child in xaml markup or via Document property in api. /// ////// FlowDocument's content allows elements in some particular hierarchical structure /// specified by Flow Content Schema. The Flow Cotent Schema includes a variety /// of element classes that you can use to create rich formatted and structured text content. /// ////// Classes in Flow Content Schema belong to several categories: "Block content", /// "Inline Content", "Embedded UIElements". /// ////// Top-level children of Flow Document must be one of ///-derived classes: /// , , , . /// - Block-level of flow content schema. /// /// Each of block elements has specific schema, only ///allowing /// inline content - elements deived from class: /// , , , , . /// /// Only ///element can contain text directly. All other elements can only contain /// elements specified by Flow Schema. /// /// Static constructor. Registers metadata for its properties. /// static FlowDocument() { PropertyChangedCallback typographyChanged = new PropertyChangedCallback(OnTypographyChanged); // Registering typography properties metadata DependencyProperty[] typographyProperties = Typography.TypographyPropertiesList; for (int i = 0; i < typographyProperties.Length; i++) { typographyProperties[i].OverrideMetadata(_typeofThis, new FrameworkPropertyMetadata(typographyChanged)); } DefaultStyleKeyProperty.OverrideMetadata(_typeofThis, new FrameworkPropertyMetadata(_typeofThis)); FocusableProperty.OverrideMetadata(_typeofThis, new FrameworkPropertyMetadata(true)); } ////// FlowDocument constructor. /// public FlowDocument() : base() { Initialize(null); // null means to create its own TextContainer } ////// Initialized the new instance of a FlowDocument specifying a Block added /// as its first child. /// /// /// Block added as a first initial child of the FlowDocument. /// public FlowDocument(Block block) : base() { Initialize(null); // null means to create its own TextContainer if (block == null) { throw new ArgumentNullException("block"); } this.Blocks.Add(block); } ////// FlowDocument constructor with TextContainer. /// internal FlowDocument(TextContainer textContainer) : base() { Initialize(textContainer); } #endregion Constructors //-------------------------------------------------------------------- // // Public Properties // //------------------------------------------------------------------- #region Public Properties ////// Collection of Blocks contained in this element /// [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] public BlockCollection Blocks { get { return new BlockCollection(this, /*isOwnerParent*/true); } } ////// A TextRange spanning the content of this element. /// internal TextRange TextRange { get { return new TextRange(this.ContentStart, this.ContentEnd); } } ////// TextPointer preceding all content. /// ////// The TextPointer returned always has its IsFrozen property set true /// and LogicalDirection property set to LogicalDirection.Backward. /// public TextPointer ContentStart { get { return _structuralCache.TextContainer.Start; } } ////// TextPointer following all content. /// ////// The TextPointer returned always has its IsFrozen property set true /// and LogicalDirection property set to LogicalDirection.Forward. /// public TextPointer ContentEnd { get { return _structuralCache.TextContainer.End; } } #region Public Dynamic Properties ////// DependencyProperty for public static readonly DependencyProperty FontFamilyProperty = TextElement.FontFamilyProperty.AddOwner(_typeofThis); ///property. /// /// The FontFamily property specifies the font family. /// [Localizability( LocalizationCategory.Font, Modifiability = Modifiability.Unmodifiable )] public FontFamily FontFamily { get { return (FontFamily) GetValue(FontFamilyProperty); } set { SetValue(FontFamilyProperty, value); } } ////// DependencyProperty for public static readonly DependencyProperty FontStyleProperty = TextElement.FontStyleProperty.AddOwner(_typeofThis); ///property. /// /// The FontStyle property requests normal, italic, and oblique faces within a font family. /// public FontStyle FontStyle { get { return (FontStyle) GetValue(FontStyleProperty); } set { SetValue(FontStyleProperty, value); } } ////// DependencyProperty for public static readonly DependencyProperty FontWeightProperty = TextElement.FontWeightProperty.AddOwner(_typeofThis); ///property. /// /// The FontWeight property specifies the weight of the font. /// public FontWeight FontWeight { get { return (FontWeight) GetValue(FontWeightProperty); } set { SetValue(FontWeightProperty, value); } } ////// DependencyProperty for public static readonly DependencyProperty FontStretchProperty = TextElement.FontStretchProperty.AddOwner(_typeofThis); ///property. /// /// The FontStretch property selects a normal, condensed, or extended face from a font family. /// public FontStretch FontStretch { get { return (FontStretch) GetValue(FontStretchProperty); } set { SetValue(FontStretchProperty, value); } } ////// DependencyProperty for public static readonly DependencyProperty FontSizeProperty = TextElement.FontSizeProperty.AddOwner( _typeofThis); ///property. /// /// The FontSize property specifies the size of the font. /// [TypeConverter(typeof(FontSizeConverter))] [Localizability(LocalizationCategory.None)] public double FontSize { get { return (double) GetValue(FontSizeProperty); } set { SetValue(FontSizeProperty, value); } } ////// DependencyProperty for public static readonly DependencyProperty ForegroundProperty = TextElement.ForegroundProperty.AddOwner( _typeofThis); ///property. /// /// The Foreground property specifies the foreground brush of an element's text content. /// public Brush Foreground { get { return (Brush) GetValue(ForegroundProperty); } set { SetValue(ForegroundProperty, value); } } ////// DependencyProperty for public static readonly DependencyProperty BackgroundProperty = TextElement.BackgroundProperty.AddOwner( _typeofThis, new FrameworkPropertyMetadata( null, FrameworkPropertyMetadataOptions.AffectsRender)); ///property. /// /// The Background property defines the brush used to fill the content area. /// public Brush Background { get { return (Brush) GetValue(BackgroundProperty); } set { SetValue(BackgroundProperty, value); } } ////// DependencyProperty for public static readonly DependencyProperty TextEffectsProperty = TextElement.TextEffectsProperty.AddOwner( _typeofThis, new FrameworkPropertyMetadata( new FreezableDefaultValueFactory(TextEffectCollection.Empty), FrameworkPropertyMetadataOptions.AffectsRender)); ///property. /// /// The TextEffects property specifies effects that are added to the text of an element. /// public TextEffectCollection TextEffects { get { return (TextEffectCollection) GetValue(TextEffectsProperty); } set { SetValue(TextEffectsProperty, value); } } ////// DependencyProperty for public static readonly DependencyProperty TextAlignmentProperty = Block.TextAlignmentProperty.AddOwner(_typeofThis); ///property. /// /// The TextAlignment property specifies the alignmnet of the element. /// public TextAlignment TextAlignment { get { return (TextAlignment)GetValue(TextAlignmentProperty); } set { SetValue(TextAlignmentProperty, value); } } ////// DependencyProperty for public static readonly DependencyProperty FlowDirectionProperty = Block.FlowDirectionProperty.AddOwner(_typeofThis); ///property. /// /// The FlowDirection property specifies the flow direction of the element. /// public FlowDirection FlowDirection { get { return (FlowDirection)GetValue(FlowDirectionProperty); } set { SetValue(FlowDirectionProperty, value); } } ////// DependencyProperty for public static readonly DependencyProperty LineHeightProperty = Block.LineHeightProperty.AddOwner(_typeofThis); ///property. /// /// The LineHeight property specifies the height of each generated line box. /// [TypeConverter(typeof(LengthConverter))] public double LineHeight { get { return (double)GetValue(LineHeightProperty); } set { SetValue(LineHeightProperty, value); } } ////// DependencyProperty for public static readonly DependencyProperty LineStackingStrategyProperty = Block.LineStackingStrategyProperty.AddOwner(_typeofThis); ///property. /// /// The LineStackingStrategy property specifies how lines are placed /// public LineStackingStrategy LineStackingStrategy { get { return (LineStackingStrategy)GetValue(LineStackingStrategyProperty); } set { SetValue(LineStackingStrategyProperty, value); } } ////// DependencyProperty for public static readonly DependencyProperty ColumnWidthProperty = DependencyProperty.Register( "ColumnWidth", typeof(double), _typeofThis, new FrameworkPropertyMetadata( double.NaN, FrameworkPropertyMetadataOptions.AffectsMeasure)); ///property. /// /// The minimum width of each column. If IsColumnWidthIsFlexible is True, then this /// value is clamped to be no larger than the width of the page (specified by /// PageWidth or PageSize) minus the PagePadding. /// [TypeConverter(typeof(LengthConverter))] [Localizability(LocalizationCategory.None, Readability = Readability.Unreadable)] public double ColumnWidth { get { return (double)GetValue(ColumnWidthProperty); } set { SetValue(ColumnWidthProperty, value); } } ////// DependencyProperty for public static readonly DependencyProperty ColumnGapProperty = DependencyProperty.Register( "ColumnGap", typeof(double), _typeofThis, new FrameworkPropertyMetadata( double.NaN, FrameworkPropertyMetadataOptions.AffectsMeasure), new ValidateValueCallback(IsValidColumnGap)); ///property. /// /// The distance between each column. This value is clamped to be no larger than /// the width of the page (specified by PageWidth or PageSize) minus the PagePadding. /// [TypeConverter(typeof(LengthConverter))] [Localizability(LocalizationCategory.None, Readability = Readability.Unreadable)] public double ColumnGap { get { return (double) GetValue(ColumnGapProperty); } set { SetValue(ColumnGapProperty, value); } } ////// DependencyProperty for public static readonly DependencyProperty IsColumnWidthFlexibleProperty = DependencyProperty.Register( "IsColumnWidthFlexible", typeof(bool), _typeofThis, new FrameworkPropertyMetadata( true, FrameworkPropertyMetadataOptions.AffectsMeasure)); ///property. /// /// Whether the width of columns is flexible. If this property is true, then columns /// will frequently be wider than ColumnWidth. If false, columns will always be exactly /// ColumnWidth (as long as the value is smaller than the width of the page minus padding). /// public bool IsColumnWidthFlexible { get { return (bool)GetValue(IsColumnWidthFlexibleProperty); } set { SetValue(IsColumnWidthFlexibleProperty, value); } } ////// DependencyProperty for public static readonly DependencyProperty ColumnRuleWidthProperty = DependencyProperty.Register( "ColumnRuleWidth", typeof(double), _typeofThis, new FrameworkPropertyMetadata( 0.0, FrameworkPropertyMetadataOptions.AffectsMeasure), new ValidateValueCallback(IsValidColumnRuleWidth)); ///property. /// /// The width of the line drawn in between columns. This value is clamped /// to be no larger than the ColumnGap. /// [TypeConverter(typeof(LengthConverter))] [Localizability(LocalizationCategory.None, Readability = Readability.Unreadable)] public double ColumnRuleWidth { get { return (double)GetValue(ColumnRuleWidthProperty); } set { SetValue(ColumnRuleWidthProperty, value); } } ////// DependencyProperty for public static readonly DependencyProperty ColumnRuleBrushProperty = DependencyProperty.Register( "ColumnRuleBrush", typeof(Brush), _typeofThis, new FrameworkPropertyMetadata( null, FrameworkPropertyMetadataOptions.AffectsRender)); ///property. /// /// The brush used to draw the line between columns. /// public Brush ColumnRuleBrush { get { return (Brush)GetValue(ColumnRuleBrushProperty); } set { SetValue(ColumnRuleBrushProperty, value); } } ////// DependencyProperty for public static readonly DependencyProperty IsOptimalParagraphEnabledProperty = DependencyProperty.Register( "IsOptimalParagraphEnabled", typeof(bool), _typeofThis, new FrameworkPropertyMetadata( false, FrameworkPropertyMetadataOptions.AffectsMeasure)); ///property. /// /// Whether FlowDocument should attempt to construct optimal text paragraphs. /// public bool IsOptimalParagraphEnabled { get { return (bool)GetValue(IsOptimalParagraphEnabledProperty); } set { SetValue(IsOptimalParagraphEnabledProperty, value); } } ////// DependencyProperty for public static readonly DependencyProperty PageWidthProperty = DependencyProperty.Register( "PageWidth", typeof(double), _typeofThis, new FrameworkPropertyMetadata( double.NaN, FrameworkPropertyMetadataOptions.AffectsMeasure, new PropertyChangedCallback(OnPageMetricsChanged), new CoerceValueCallback(CoercePageWidth)), new ValidateValueCallback(IsValidPageSize)); ///property. /// /// The width of pages returned by GetPage. This value takes precedence over /// PageSize.Width, MinPageWidth, and MaxPageWidth. /// [TypeConverter(typeof(LengthConverter))] public double PageWidth { get { return (double) GetValue(PageWidthProperty); } set { SetValue(PageWidthProperty, value); } } ////// DependencyProperty for public static readonly DependencyProperty MinPageWidthProperty = DependencyProperty.Register( "MinPageWidth", typeof(double), _typeofThis, new FrameworkPropertyMetadata( 0.0, FrameworkPropertyMetadataOptions.AffectsMeasure, new PropertyChangedCallback(OnMinPageWidthChanged)), new ValidateValueCallback(IsValidMinPageSize)); ///property. /// /// The minimum width of pages returned by GetPage. This value takes /// precedence over PageSize.Width, but not PageWidth. /// [TypeConverter(typeof(LengthConverter))] public double MinPageWidth { get { return (double) GetValue(MinPageWidthProperty); } set { SetValue(MinPageWidthProperty, value); } } ////// DependencyProperty for public static readonly DependencyProperty MaxPageWidthProperty = DependencyProperty.Register( "MaxPageWidth", typeof(double), _typeofThis, new FrameworkPropertyMetadata( double.PositiveInfinity, FrameworkPropertyMetadataOptions.AffectsMeasure, new PropertyChangedCallback(OnMaxPageWidthChanged), new CoerceValueCallback(CoerceMaxPageWidth)), new ValidateValueCallback(IsValidMaxPageSize)); ///property. /// /// The maximum width of pages returned by GetPage. This value takes /// precedence over PageSize.Width, but not PageWidth. /// [TypeConverter(typeof(LengthConverter))] public double MaxPageWidth { get { return (double) GetValue(MaxPageWidthProperty); } set { SetValue(MaxPageWidthProperty, value); } } ////// DependencyProperty for public static readonly DependencyProperty PageHeightProperty = DependencyProperty.Register( "PageHeight", typeof(double), _typeofThis, new FrameworkPropertyMetadata( double.NaN, FrameworkPropertyMetadataOptions.AffectsMeasure, new PropertyChangedCallback(OnPageMetricsChanged), new CoerceValueCallback(CoercePageHeight)), new ValidateValueCallback(IsValidPageSize)); ///property. /// /// The height of pages returned by GetPage. This value takes precedence /// over PageSize.Height, MinPageHeight, and MaxPageHeight. /// [TypeConverter(typeof(LengthConverter))] public double PageHeight { get { return (double) GetValue(PageHeightProperty); } set { SetValue(PageHeightProperty, value); } } ////// DependencyProperty for public static readonly DependencyProperty MinPageHeightProperty = DependencyProperty.Register( "MinPageHeight", typeof(double), _typeofThis, new FrameworkPropertyMetadata( 0.0, FrameworkPropertyMetadataOptions.AffectsMeasure, new PropertyChangedCallback(OnMinPageHeightChanged)), new ValidateValueCallback(IsValidMinPageSize)); ///property. /// /// The minimum height of pages returned by GetPage. This value takes /// precedence over PageSize.Height, but not PageHeight. /// [TypeConverter(typeof(LengthConverter))] public double MinPageHeight { get { return (double) GetValue(MinPageHeightProperty); } set { SetValue(MinPageHeightProperty, value); } } ////// DependencyProperty for public static readonly DependencyProperty MaxPageHeightProperty = DependencyProperty.Register( "MaxPageHeight", typeof(double), _typeofThis, new FrameworkPropertyMetadata( double.PositiveInfinity, FrameworkPropertyMetadataOptions.AffectsMeasure, new PropertyChangedCallback(OnMaxPageHeightChanged), new CoerceValueCallback(CoerceMaxPageHeight)), new ValidateValueCallback(IsValidMaxPageSize)); ///property. /// /// The maximum height of pages returned by GetPage. This value takes /// precedence over PageSize.Height, but not PageHeight. /// [TypeConverter(typeof(LengthConverter))] public double MaxPageHeight { get { return (double) GetValue(MaxPageHeightProperty); } set { SetValue(MaxPageHeightProperty, value); } } ////// DependencyProperty for public static readonly DependencyProperty PagePaddingProperty = DependencyProperty.Register( "PagePadding", typeof(Thickness), _typeofThis, new FrameworkPropertyMetadata( new Thickness(Double.NaN), FrameworkPropertyMetadataOptions.AffectsMeasure, new PropertyChangedCallback(OnPageMetricsChanged)), new ValidateValueCallback(IsValidPagePadding)); ///property. /// /// Padding applied between the page boundaries and the content of the page. /// If the sum of the specified padding in a dimension is greater than the /// corresponding page dimension, then the padding values in that dimension /// will be proportionally reduced such that the sum of the padding in that /// dimension is equal to the page dimension. /// For example, if the PageSize is (100, 100) and PagePadding is (0, 120, 0, 80), /// then the page will be formatted as if the PagePadding were actually (0, 60, 0, 40). /// public Thickness PagePadding { get { return (Thickness) GetValue(PagePaddingProperty); } set { SetValue(PagePaddingProperty, value); } } ////// Class providing access to all text typography properties /// public Typography Typography { get { return new Typography(this); } } ////// DependencyProperty for hyphenation property. /// public static readonly DependencyProperty IsHyphenationEnabledProperty = Block.IsHyphenationEnabledProperty.AddOwner(_typeofThis); ////// CLR property for hyphenation /// public bool IsHyphenationEnabled { get { return (bool)GetValue(IsHyphenationEnabledProperty); } set { SetValue(IsHyphenationEnabledProperty, value); } } #endregion Public Dynamic Properties #endregion Public Properties //-------------------------------------------------------------------- // // Protected Methods // //-------------------------------------------------------------------- #region Protected Methods ////// Notification that a specified property has been invalidated /// /// EventArgs that contains the property, metadata, old value, and new value for this change protected sealed override void OnPropertyChanged(DependencyPropertyChangedEventArgs e) { // Always call base.OnPropertyChanged, otherwise Property Engine will not work. base.OnPropertyChanged(e); if (e.IsAValueChange || e.IsASubPropertyChange) { // Skip caches invalidation if content has not been formatted yet - non of caches are valid, // so they will be aquired during first formatting (full format). if (_structuralCache != null && _structuralCache.IsFormattedOnce) { FrameworkPropertyMetadata fmetadata = e.Metadata as FrameworkPropertyMetadata; if (fmetadata != null) { bool affectsRender = (fmetadata.AffectsRender && (e.IsAValueChange || !fmetadata.SubPropertiesDoNotAffectRender)); if (fmetadata.AffectsMeasure || fmetadata.AffectsArrange || affectsRender || fmetadata.AffectsParentMeasure || fmetadata.AffectsParentArrange) { // Detect invalid content change operations. if (_structuralCache.IsFormattingInProgress) { _structuralCache.OnInvalidOperationDetected(); throw new InvalidOperationException(SR.Get(SRID.FlowDocumentInvalidContnetChange)); } // None of FlowDocument properties can invalidate structural caches (the NameTable), // but most likely it invalidates format caches. Invalidate all format caches // accumulated in the NameTable. _structuralCache.InvalidateFormatCache(!affectsRender); // Notify formatter about content invalidation. if (_formatter != null) { _formatter.OnContentInvalidated(!affectsRender); } } } } } } ////// Creates AutomationPeer ( protected override AutomationPeer OnCreateAutomationPeer() { return new DocumentAutomationPeer(this); } #endregion Protected Methods //------------------------------------------------------------------- // // Protected Properties // //-------------------------------------------------------------------- #region Protected Properties ///) /// /// Returns enumerator to logical children. /// protected internal override IEnumerator LogicalChildren { get { return new RangeContentEnumerator(_structuralCache.TextContainer.Start, _structuralCache.TextContainer.End); } } ////// Fetches the value of the IsEnabled property /// ////// We want to coerce ContentElements and UIElement children of FlowDocument to be disabled in _editable_ content (ie, RichTextBox). /// In read-only mode, in say the FlowDocumentReader, we don't want any coercing. /// protected override bool IsEnabledCore { get { if (!base.IsEnabledCore) { return false; } RichTextBox parentRichTextBox = this.Parent as RichTextBox; return (parentRichTextBox == null) ? true : parentRichTextBox.IsDocumentEnabled; } } #endregion Protected Properties //------------------------------------------------------------------- // // Internal Methods // //------------------------------------------------------------------- #region Internal Methods ////// Returns a ContentPosition for an object. /// /// Object within this element's tree. ///Returns a ContentPosition for an object. internal ContentPosition GetObjectPosition(Object element) { TextPointer flowContentPosition; ITextPointer textPointer = null; DependencyObject parentOfEmbeddedElement; // If element is 'this', return ContentPosition representing ContentStart. if (element == this) { textPointer = this.ContentStart; } // If element is a TextElement, return its ContentStart. else if (element is TextElement) { textPointer = ((TextElement)element).ContentStart; } // Otherwise we are dealing with embedded element. Find its position in the // TextContainer and return it. // It is possible that somebody asks for FrameworkElement that is not an immediate // child of FlowDocument's content. In such case walk up the parent chain and // get FrameworkElement that is directly embedded within FlowDocument's content. else if (element is FrameworkElement) { parentOfEmbeddedElement = null; while (element is FrameworkElement) { parentOfEmbeddedElement = LogicalTreeHelper.GetParent((DependencyObject)element); if (parentOfEmbeddedElement == null) { parentOfEmbeddedElement = VisualTreeHelper.GetParent((Visual)element); } if (!(parentOfEmbeddedElement is FrameworkElement)) { break; } element = parentOfEmbeddedElement; } if (parentOfEmbeddedElement is BlockUIContainer || parentOfEmbeddedElement is InlineUIContainer) { textPointer = TextContainerHelper.GetTextPointerForEmbeddedObject((FrameworkElement)element); } } // Check if the TextPointer belongs to our tree. if (textPointer != null && textPointer.TextContainer != _structuralCache.TextContainer) { textPointer = null; } flowContentPosition = textPointer as TextPointer; return (flowContentPosition != null) ? flowContentPosition : ContentPosition.Missing; } ////// OnChildDesiredSizeChanged /// Called from FlowDocumentPage for IContentHost implementation /// internal void OnChildDesiredSizeChanged(UIElement child) { if (_structuralCache != null && _structuralCache.IsFormattedOnce && !_structuralCache.ForceReformat) { // If executed during formatting process, delay invalidation. // This may happen during formatting when text host notifies its about // baseline changes. if (_structuralCache.IsFormattingInProgress) { Dispatcher.BeginInvoke(DispatcherPriority.Normal, new DispatcherOperationCallback(OnChildDesiredSizeChangedAsync), child); return; } // Get start and end positions int childStartIndex = TextContainerHelper.GetCPFromEmbeddedObject(child, ElementEdge.BeforeStart); if (childStartIndex < 0) { return; } TextPointer childStart = new TextPointer(_structuralCache.TextContainer.Start); childStart.MoveByOffset(childStartIndex); TextPointer childEnd = new TextPointer(childStart); childEnd.MoveByOffset(TextContainerHelper.EmbeddedObjectLength); // Create new DTR for changing UIElement and add it to DRTList. DirtyTextRange dtr = new DirtyTextRange(childStartIndex, TextContainerHelper.EmbeddedObjectLength, TextContainerHelper.EmbeddedObjectLength); _structuralCache.AddDirtyTextRange(dtr); // Notify formatter about content invalidation. if (_formatter != null) { _formatter.OnContentInvalidated(true, childStart, childEnd); } } } /// /// Do delayed initialization before first formatting. /// internal void InitializeForFirstFormatting() { _structuralCache.TextContainer.Changing += new EventHandler(OnTextContainerChanging); _structuralCache.TextContainer.Change += new TextContainerChangeEventHandler(OnTextContainerChange); _structuralCache.TextContainer.Highlights.Changed += new HighlightChangedEventHandler(OnHighlightChanged); } ////// Clear the TextContainer and unregister events. Called by TextBox on style change. /// internal void Uninitialize() { _structuralCache.TextContainer.Changing -= new EventHandler(OnTextContainerChanging); _structuralCache.TextContainer.Change -= new TextContainerChangeEventHandler(OnTextContainerChange); _structuralCache.TextContainer.Highlights.Changed -= new HighlightChangedEventHandler(OnHighlightChanged); _structuralCache.IsFormattedOnce = false; } ////// Compute margin for a page. /// internal Thickness ComputePageMargin() { double lineHeight = DynamicPropertyReader.GetLineHeightValue(this); Thickness pageMargin = this.PagePadding; // If Padding value is 'Auto', treat it as 1*LineHeight. if (DoubleUtil.IsNaN(pageMargin.Left)) { pageMargin.Left = lineHeight; } if (DoubleUtil.IsNaN(pageMargin.Top)) { pageMargin.Top = lineHeight; } if (DoubleUtil.IsNaN(pageMargin.Right)) { pageMargin.Right = lineHeight; } if (DoubleUtil.IsNaN(pageMargin.Bottom)) { pageMargin.Bottom = lineHeight; } return pageMargin; } ////// Called before the parent is changed to the new value. /// We listen to parent change notifications to enforce coercing FlowDocument's IsEnabled property to false /// (when it is parented by RichTextBox). /// This property coersion is done in 2 parts. /// 1. Implement IsEnabledCore for property coersion /// 2. Listen to changes to parent /// (2) needs to be done, since property system does not coerce default values. /// Listening to parent changes guarantees that every time FlowDocument is removed or connected to a RichTextBox parent, /// we explicitly coerce IsEnabled for the new tree. /// /// internal override void OnNewParent(DependencyObject newParent) { DependencyObject oldParent = this.Parent; base.OnNewParent(newParent); if (newParent is RichTextBox || oldParent is RichTextBox) { CoerceValue(IsEnabledProperty); } } #endregion Internal Methods //------------------------------------------------------------------- // // Internal Properties // //-------------------------------------------------------------------- #region Internal Properties ////// An object which formats botomless content. /// internal FlowDocumentFormatter BottomlessFormatter { get { if (_formatter != null && !(_formatter is FlowDocumentFormatter)) { _formatter.Suspend(); _formatter = null; } if (_formatter == null) { _formatter = new FlowDocumentFormatter(this); } return (FlowDocumentFormatter)_formatter; } } ////// StructuralCache. /// internal StructuralCache StructuralCache { get { return _structuralCache; } } ////// Typography properties group. /// internal TypographyProperties TypographyPropertiesGroup { get { if (_typographyPropertiesGroup == null) { _typographyPropertiesGroup = TextElement.GetTypographyProperties(this); } return _typographyPropertiesGroup; } } ////// TextWrapping property value (set by TextBox/RichTextBox) /// internal TextWrapping TextWrapping { get { return _textWrapping; } set { _textWrapping = value; } } ////// Formatter value /// internal IFlowDocumentFormatter Formatter { get { return _formatter; } } //------------------------------------------------------------------- // Is layout data is in a valid state. //-------------------------------------------------------------------- internal bool IsLayoutDataValid { get { if(_formatter != null) { return _formatter.IsLayoutDataValid; } return false; } } //-------------------------------------------------------------------- // TextContainer associated with this FlowDocument. //------------------------------------------------------------------- internal TextContainer TextContainer { get { return _structuralCache.TextContainer; } } #endregion Internal Properties //-------------------------------------------------------------------- // // Internal Events // //------------------------------------------------------------------- #region Internal Events ////// Fired when a PageSize property is changed /// internal event EventHandler PageSizeChanged; #endregion Internal Events //------------------------------------------------------------------- // // Private Methods // //------------------------------------------------------------------- #region Private Methods ////// One of the properties which comprises TypographyProperties has changed -- reset cache. /// private static void OnTypographyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { ((FlowDocument)d)._typographyPropertiesGroup = null; } ////// OnChildDesiredSizeChanged delayed to avoid changes during page /// formatting. /// /// ///private object OnChildDesiredSizeChangedAsync(object arg) { OnChildDesiredSizeChanged(arg as UIElement); return null; } /// /// Initialize FlowDocument. /// /// private void Initialize(TextContainer textContainer) { if (textContainer == null) { // Create text tree that contains content of the element. textContainer = new TextContainer(this, false /* plainTextOnly */); } // Create structural cache object _structuralCache = new StructuralCache(this, textContainer); _structuralCache.Section = new MS.Internal.PtsHost.Section(_structuralCache); // Get rid of the current formatter. if (_formatter != null) { _formatter.Suspend(); _formatter = null; } } ////// Respond to page metrics changes. /// private static void OnPageMetricsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { FlowDocument fd = (FlowDocument)d; if (fd._structuralCache != null && fd._structuralCache.IsFormattedOnce) { // Notify formatter about content invalidation. if (fd._formatter != null) { // Any change of page metrics invalidates the layout. // Hence page metrics change is treated in the same way as ContentChanged // spanning entire content. fd._formatter.OnContentInvalidated(true); } // Fire notification about the PageSize change - needed in RichTextBox if (fd.PageSizeChanged != null) { // NOTE: May execute external code, so it is possible to get // an exception here. fd.PageSizeChanged(fd, EventArgs.Empty); } } } ////// Respond to MinPageWidth change. /// private static void OnMinPageWidthChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { d.CoerceValue(MaxPageWidthProperty); d.CoerceValue(PageWidthProperty); } ////// Respond to MinPageHeight change. /// private static void OnMinPageHeightChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { d.CoerceValue(MaxPageHeightProperty); d.CoerceValue(PageHeightProperty); } ////// Respond to MaxPageWidth change. /// private static void OnMaxPageWidthChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { d.CoerceValue(PageWidthProperty); } ////// Respond to MaxPageHeight change. /// private static void OnMaxPageHeightChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { d.CoerceValue(PageHeightProperty); } ////// Coerce MaxPageWidth value. /// private static object CoerceMaxPageWidth(DependencyObject d, object value) { FlowDocument fd = (FlowDocument) d; double max = (double) value; double min = fd.MinPageWidth; if (max < min) { return min; } return value; } ////// Coerce MaxPageHeight value. /// private static object CoerceMaxPageHeight(DependencyObject d, object value) { FlowDocument fd = (FlowDocument) d; double max = (double) value; double min = fd.MinPageHeight; if (max < min) { return min; } return value; } ////// Coerce PageWidth value. /// private static object CoercePageWidth(DependencyObject d, object value) { FlowDocument fd = (FlowDocument) d; double width = (double) value; if (!DoubleUtil.IsNaN(width)) { double max = fd.MaxPageWidth; if (width > max) { width = max; } double min = fd.MinPageWidth; if (width < min) { width = min; } } return value; } ////// Coerce PageHeight value. /// private static object CoercePageHeight(DependencyObject d, object value) { FlowDocument fd = (FlowDocument) d; double height = (double) value; if (!DoubleUtil.IsNaN(height)) { double max = fd.MaxPageHeight; if (height > max) { height = max; } double min = fd.MinPageHeight; if (height < min) { height = min; } } return value; } ////// Invalidates a portion of text affected by a highlight change. /// /// /// private void OnHighlightChanged(object sender, HighlightChangedEventArgs args) { TextSegment textSegment; int i; Invariant.Assert(args != null); Invariant.Assert(args.Ranges != null); Invariant.Assert(_structuralCache != null && _structuralCache.IsFormattedOnce, "Unexpected Highlights.Changed callback before first format!"); // Detect invalid content change operations. if (_structuralCache.IsFormattingInProgress) { _structuralCache.OnInvalidOperationDetected(); throw new InvalidOperationException(SR.Get(SRID.FlowDocumentInvalidContnetChange)); } // The only supported highlight type for FlowDocument is SpellerHightlight. // TextSelection and HighlightComponent are ignored, because they are handled by // separate layer. if (args.OwnerType != typeof(SpellerHighlightLayer)) { return; } if (args.Ranges.Count > 0) { // Invalidate affected pages and break records. // We DTR invalidate if we're using a formatter as well for incremental update. if (_formatter == null || !(_formatter is FlowDocumentFormatter)) { _structuralCache.InvalidateFormatCache(/*Clear structure*/ false); } // Notify formatter about content invalidation. if (_formatter != null) { for (i = 0; i < args.Ranges.Count; i++) { textSegment = (TextSegment)args.Ranges[i]; _formatter.OnContentInvalidated(false, textSegment.Start, textSegment.End); if (_formatter is FlowDocumentFormatter) { DirtyTextRange dtr = new DirtyTextRange(textSegment.Start.Offset, textSegment.Start.GetOffsetToPosition(textSegment.End), textSegment.Start.GetOffsetToPosition(textSegment.End) ); _structuralCache.AddDirtyTextRange(dtr); } } } } } ////// Handler for TextContainer changing notifications. /// private void OnTextContainerChanging(object sender, EventArgs args) { Invariant.Assert(sender == _structuralCache.TextContainer, "Received text change for foreign TextContainer."); Invariant.Assert(_structuralCache != null && _structuralCache.IsFormattedOnce, "Unexpected TextContainer.Changing callback before first format!"); // Detect invalid content change operations. if (_structuralCache.IsFormattingInProgress) { _structuralCache.OnInvalidOperationDetected(); throw new InvalidOperationException(SR.Get(SRID.FlowDocumentInvalidContnetChange)); } // Remember the fact that content is changing. // OnTextContainerChange has to be received after this event. _structuralCache.IsContentChangeInProgress = true; } ////// Handler for TextContainer change notifications. /// /// /// private void OnTextContainerChange(object sender, TextContainerChangeEventArgs args) { DirtyTextRange dtr; ITextPointer segmentEnd; Invariant.Assert(args != null); Invariant.Assert(sender == _structuralCache.TextContainer); Invariant.Assert(_structuralCache != null && _structuralCache.IsFormattedOnce, "Unexpected TextContainer.Change callback before first format!"); if (args.Count == 0) { // A no-op for this control. Happens when IMECharCount updates happen // without corresponding SymbolCount changes. return; } try { // Detect invalid content change operations. if (_structuralCache.IsFormattingInProgress) { _structuralCache.OnInvalidOperationDetected(); throw new InvalidOperationException(SR.Get(SRID.FlowDocumentInvalidContnetChange)); } // Since content is changeing, do partial invalidation of BreakRecordTable. if (args.TextChange != TextChangeType.ContentRemoved) { segmentEnd = args.ITextPosition.CreatePointer(args.Count, LogicalDirection.Forward); } else { segmentEnd = args.ITextPosition; } // Invalidate affected pages and break records. // We DTR invalidate if we're using a formatter as well for incremental update. if (!args.AffectsRenderOnly || (_formatter != null && _formatter is FlowDocumentFormatter)) { // Create new DTR for changing range and add it to DRTList. dtr = new DirtyTextRange(args); _structuralCache.AddDirtyTextRange(dtr); } else { // Clear format caches. _structuralCache.InvalidateFormatCache(/*Clear structure*/ false); } // Notify formatter about content invalidation. if (_formatter != null) { _formatter.OnContentInvalidated(!args.AffectsRenderOnly, args.ITextPosition, segmentEnd); } } finally { // Content has been changed, so reset appropriate flag. _structuralCache.IsContentChangeInProgress = false; } } private static bool IsValidPageSize(object o) { double value = (double)o; double maxSize = Math.Min(1000000, PTS.MaxPageSize); if (Double.IsNaN(value)) { return true; } if (value < 0 || value > maxSize) { return false; } return true; } private static bool IsValidMinPageSize(object o) { double value = (double)o; double maxSize = Math.Min(1000000, PTS.MaxPageSize); if (Double.IsNaN(value)) { return false; } if (!Double.IsNegativeInfinity(value) && (value < 0 || value > maxSize)) { return false; } return true; } private static bool IsValidMaxPageSize(object o) { double value = (double)o; double maxSize = Math.Min(1000000, PTS.MaxPageSize); if (Double.IsNaN(value)) { return false; } if (!Double.IsPositiveInfinity(value) && (value < 0 || value > maxSize)) { return false; } return true; } private static bool IsValidPagePadding(object o) { Thickness value = (Thickness)o; return Block.IsValidThickness(value, /*allow NaN*/true); } private static bool IsValidColumnRuleWidth(object o) { double ruleWidth = (double)o; double maxRuleWidth = Math.Min(1000000, PTS.MaxPageSize); if (Double.IsNaN(ruleWidth) || ruleWidth < 0 || ruleWidth > maxRuleWidth) { return false; } return true; } private static bool IsValidColumnGap(object o) { double gap = (double)o; double maxGap = Math.Min(1000000, PTS.MaxPageSize); if (Double.IsNaN(gap)) { // Default value. return true; } if (gap < 0 || gap > maxGap) { return false; } return true; } #endregion Private methods //-------------------------------------------------------------------- // // Private Fields // //------------------------------------------------------------------- #region Private Fields private StructuralCache _structuralCache; // Structural cache for the content. private TypographyProperties _typographyPropertiesGroup; // Cache for typography properties. private IFlowDocumentFormatter _formatter; // Current formatter asociated with FlowDocument. private TextWrapping _textWrapping = TextWrapping.Wrap; // internal cache for TextBox/RichTextBox #endregion Private Fields //-------------------------------------------------------------------- // // IAddChild Members // //-------------------------------------------------------------------- #region IAddChild Members ////// Called to Add the object as a Child. /// /// /// Object to add as a child /// void IAddChild.AddChild(Object value) { if (value == null) { throw new ArgumentNullException("value"); } if (!TextSchema.IsValidChildOfContainer(/*parentType:*/_typeofThis, /*childType:*/value.GetType())) { throw new ArgumentException(SR.Get(SRID.TextSchema_ChildTypeIsInvalid, _typeofThis.Name, value.GetType().Name)); } // Checking that the element inserted does not have a parent if (value is TextElement && ((TextElement)value).Parent != null) { throw new ArgumentException(SR.Get(SRID.TextSchema_TheChildElementBelongsToAnotherTreeAlready, value.GetType().Name)); } if (value is Block) { TextContainer textContainer = _structuralCache.TextContainer; ((Block)value).RepositionWithContent(textContainer.End); } else { Invariant.Assert(false); // We do not expect anything except Blocks on top level of a FlowDocument } } ////// Called when text appears under the tag in markup /// /// /// Text to Add to the Object /// void IAddChild.AddText(string text) { XamlSerializerUtil.ThrowIfNonWhiteSpaceInAddText(text, this); } #endregion IAddChild Members //------------------------------------------------------------------- // // IServiceProvider Members // //-------------------------------------------------------------------- #region IServiceProvider Members ////// Gets the service object of the specified type. /// ////// FlowDocument supports only TextContainer. /// /// /// An object that specifies the type of service object to get. /// ////// A service object of type serviceType. A null reference if there is no /// service object of type serviceType. /// object IServiceProvider.GetService(Type serviceType) { if (serviceType == null) { throw new ArgumentNullException("serviceType"); } if (serviceType == typeof(ITextContainer)) { return _structuralCache.TextContainer; } else if (serviceType == typeof(TextContainer)) { return _structuralCache.TextContainer as TextContainer; } return null; } #endregion IServiceProvider Members //------------------------------------------------------------------- // // IDocumentPaginatorSource Members // //------------------------------------------------------------------- #region IDocumentPaginatorSource Members ////// An object which paginates content. /// DocumentPaginator IDocumentPaginatorSource.DocumentPaginator { get { if (_formatter != null && !(_formatter is FlowDocumentPaginator)) { _formatter.Suspend(); _formatter = null; } if (_formatter == null) { _formatter = new FlowDocumentPaginator(this); } return (FlowDocumentPaginator)_formatter; } } #endregion IDocumentPaginatorSource Members } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved. //---------------------------------------------------------------------------- // // Copyright (C) Microsoft Corporation. All rights reserved. // // File: FlowDocument.cs // // Description: Hosts and formats text with advanced document features. // // History: // 17/08/2004 : grzegorz - created. // //--------------------------------------------------------------------------- using System.Collections; using System.ComponentModel; using System.Windows.Automation.Peers; // AutomationPeer using System.Windows.Controls; using System.Windows.Markup; using System.Windows.Media; using System.Windows.Threading; using MS.Internal; // DoubleUtil using MS.Internal.Documents; using MS.Internal.PtsHost; using MS.Internal.PtsHost.UnsafeNativeMethods; // PTS restrictions using MS.Internal.Text; namespace System.Windows.Documents { ////// FlowDocument is the paginating container for text content. /// ////// [Localizability(LocalizationCategory.Inherit, Readability = Readability.Unreadable)] [ContentProperty("Blocks")] public class FlowDocument : FrameworkContentElement, IDocumentPaginatorSource, IServiceProvider, IAddChild { static private readonly Type _typeofThis = typeof(FlowDocument); //------------------------------------------------------------------- // // Constructors // //------------------------------------------------------------------- #region Constructors ////// FlowDocument does not derive from Visual, and therefore cannot /// be added as a direct child of UIElements such as Grid. /// In order to be displayed, FlowDocument must be viewed within a FlowDocumentPageViewer, /// DocumentViewerBase-derived class, or a custom paginated viewer that utilizes the /// IDocumentPaginatorSource API. /// It also can be viewed and edited within RichTextBox control, /// available as it child in xaml markup or via Document property in api. /// ////// FlowDocument's content allows elements in some particular hierarchical structure /// specified by Flow Content Schema. The Flow Cotent Schema includes a variety /// of element classes that you can use to create rich formatted and structured text content. /// ////// Classes in Flow Content Schema belong to several categories: "Block content", /// "Inline Content", "Embedded UIElements". /// ////// Top-level children of Flow Document must be one of ///-derived classes: /// , , , . /// - Block-level of flow content schema. /// /// Each of block elements has specific schema, only ///allowing /// inline content - elements deived from class: /// , , , , . /// /// Only ///element can contain text directly. All other elements can only contain /// elements specified by Flow Schema. /// /// Static constructor. Registers metadata for its properties. /// static FlowDocument() { PropertyChangedCallback typographyChanged = new PropertyChangedCallback(OnTypographyChanged); // Registering typography properties metadata DependencyProperty[] typographyProperties = Typography.TypographyPropertiesList; for (int i = 0; i < typographyProperties.Length; i++) { typographyProperties[i].OverrideMetadata(_typeofThis, new FrameworkPropertyMetadata(typographyChanged)); } DefaultStyleKeyProperty.OverrideMetadata(_typeofThis, new FrameworkPropertyMetadata(_typeofThis)); FocusableProperty.OverrideMetadata(_typeofThis, new FrameworkPropertyMetadata(true)); } ////// FlowDocument constructor. /// public FlowDocument() : base() { Initialize(null); // null means to create its own TextContainer } ////// Initialized the new instance of a FlowDocument specifying a Block added /// as its first child. /// /// /// Block added as a first initial child of the FlowDocument. /// public FlowDocument(Block block) : base() { Initialize(null); // null means to create its own TextContainer if (block == null) { throw new ArgumentNullException("block"); } this.Blocks.Add(block); } ////// FlowDocument constructor with TextContainer. /// internal FlowDocument(TextContainer textContainer) : base() { Initialize(textContainer); } #endregion Constructors //-------------------------------------------------------------------- // // Public Properties // //------------------------------------------------------------------- #region Public Properties ////// Collection of Blocks contained in this element /// [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] public BlockCollection Blocks { get { return new BlockCollection(this, /*isOwnerParent*/true); } } ////// A TextRange spanning the content of this element. /// internal TextRange TextRange { get { return new TextRange(this.ContentStart, this.ContentEnd); } } ////// TextPointer preceding all content. /// ////// The TextPointer returned always has its IsFrozen property set true /// and LogicalDirection property set to LogicalDirection.Backward. /// public TextPointer ContentStart { get { return _structuralCache.TextContainer.Start; } } ////// TextPointer following all content. /// ////// The TextPointer returned always has its IsFrozen property set true /// and LogicalDirection property set to LogicalDirection.Forward. /// public TextPointer ContentEnd { get { return _structuralCache.TextContainer.End; } } #region Public Dynamic Properties ////// DependencyProperty for public static readonly DependencyProperty FontFamilyProperty = TextElement.FontFamilyProperty.AddOwner(_typeofThis); ///property. /// /// The FontFamily property specifies the font family. /// [Localizability( LocalizationCategory.Font, Modifiability = Modifiability.Unmodifiable )] public FontFamily FontFamily { get { return (FontFamily) GetValue(FontFamilyProperty); } set { SetValue(FontFamilyProperty, value); } } ////// DependencyProperty for public static readonly DependencyProperty FontStyleProperty = TextElement.FontStyleProperty.AddOwner(_typeofThis); ///property. /// /// The FontStyle property requests normal, italic, and oblique faces within a font family. /// public FontStyle FontStyle { get { return (FontStyle) GetValue(FontStyleProperty); } set { SetValue(FontStyleProperty, value); } } ////// DependencyProperty for public static readonly DependencyProperty FontWeightProperty = TextElement.FontWeightProperty.AddOwner(_typeofThis); ///property. /// /// The FontWeight property specifies the weight of the font. /// public FontWeight FontWeight { get { return (FontWeight) GetValue(FontWeightProperty); } set { SetValue(FontWeightProperty, value); } } ////// DependencyProperty for public static readonly DependencyProperty FontStretchProperty = TextElement.FontStretchProperty.AddOwner(_typeofThis); ///property. /// /// The FontStretch property selects a normal, condensed, or extended face from a font family. /// public FontStretch FontStretch { get { return (FontStretch) GetValue(FontStretchProperty); } set { SetValue(FontStretchProperty, value); } } ////// DependencyProperty for public static readonly DependencyProperty FontSizeProperty = TextElement.FontSizeProperty.AddOwner( _typeofThis); ///property. /// /// The FontSize property specifies the size of the font. /// [TypeConverter(typeof(FontSizeConverter))] [Localizability(LocalizationCategory.None)] public double FontSize { get { return (double) GetValue(FontSizeProperty); } set { SetValue(FontSizeProperty, value); } } ////// DependencyProperty for public static readonly DependencyProperty ForegroundProperty = TextElement.ForegroundProperty.AddOwner( _typeofThis); ///property. /// /// The Foreground property specifies the foreground brush of an element's text content. /// public Brush Foreground { get { return (Brush) GetValue(ForegroundProperty); } set { SetValue(ForegroundProperty, value); } } ////// DependencyProperty for public static readonly DependencyProperty BackgroundProperty = TextElement.BackgroundProperty.AddOwner( _typeofThis, new FrameworkPropertyMetadata( null, FrameworkPropertyMetadataOptions.AffectsRender)); ///property. /// /// The Background property defines the brush used to fill the content area. /// public Brush Background { get { return (Brush) GetValue(BackgroundProperty); } set { SetValue(BackgroundProperty, value); } } ////// DependencyProperty for public static readonly DependencyProperty TextEffectsProperty = TextElement.TextEffectsProperty.AddOwner( _typeofThis, new FrameworkPropertyMetadata( new FreezableDefaultValueFactory(TextEffectCollection.Empty), FrameworkPropertyMetadataOptions.AffectsRender)); ///property. /// /// The TextEffects property specifies effects that are added to the text of an element. /// public TextEffectCollection TextEffects { get { return (TextEffectCollection) GetValue(TextEffectsProperty); } set { SetValue(TextEffectsProperty, value); } } ////// DependencyProperty for public static readonly DependencyProperty TextAlignmentProperty = Block.TextAlignmentProperty.AddOwner(_typeofThis); ///property. /// /// The TextAlignment property specifies the alignmnet of the element. /// public TextAlignment TextAlignment { get { return (TextAlignment)GetValue(TextAlignmentProperty); } set { SetValue(TextAlignmentProperty, value); } } ////// DependencyProperty for public static readonly DependencyProperty FlowDirectionProperty = Block.FlowDirectionProperty.AddOwner(_typeofThis); ///property. /// /// The FlowDirection property specifies the flow direction of the element. /// public FlowDirection FlowDirection { get { return (FlowDirection)GetValue(FlowDirectionProperty); } set { SetValue(FlowDirectionProperty, value); } } ////// DependencyProperty for public static readonly DependencyProperty LineHeightProperty = Block.LineHeightProperty.AddOwner(_typeofThis); ///property. /// /// The LineHeight property specifies the height of each generated line box. /// [TypeConverter(typeof(LengthConverter))] public double LineHeight { get { return (double)GetValue(LineHeightProperty); } set { SetValue(LineHeightProperty, value); } } ////// DependencyProperty for public static readonly DependencyProperty LineStackingStrategyProperty = Block.LineStackingStrategyProperty.AddOwner(_typeofThis); ///property. /// /// The LineStackingStrategy property specifies how lines are placed /// public LineStackingStrategy LineStackingStrategy { get { return (LineStackingStrategy)GetValue(LineStackingStrategyProperty); } set { SetValue(LineStackingStrategyProperty, value); } } ////// DependencyProperty for public static readonly DependencyProperty ColumnWidthProperty = DependencyProperty.Register( "ColumnWidth", typeof(double), _typeofThis, new FrameworkPropertyMetadata( double.NaN, FrameworkPropertyMetadataOptions.AffectsMeasure)); ///property. /// /// The minimum width of each column. If IsColumnWidthIsFlexible is True, then this /// value is clamped to be no larger than the width of the page (specified by /// PageWidth or PageSize) minus the PagePadding. /// [TypeConverter(typeof(LengthConverter))] [Localizability(LocalizationCategory.None, Readability = Readability.Unreadable)] public double ColumnWidth { get { return (double)GetValue(ColumnWidthProperty); } set { SetValue(ColumnWidthProperty, value); } } ////// DependencyProperty for public static readonly DependencyProperty ColumnGapProperty = DependencyProperty.Register( "ColumnGap", typeof(double), _typeofThis, new FrameworkPropertyMetadata( double.NaN, FrameworkPropertyMetadataOptions.AffectsMeasure), new ValidateValueCallback(IsValidColumnGap)); ///property. /// /// The distance between each column. This value is clamped to be no larger than /// the width of the page (specified by PageWidth or PageSize) minus the PagePadding. /// [TypeConverter(typeof(LengthConverter))] [Localizability(LocalizationCategory.None, Readability = Readability.Unreadable)] public double ColumnGap { get { return (double) GetValue(ColumnGapProperty); } set { SetValue(ColumnGapProperty, value); } } ////// DependencyProperty for public static readonly DependencyProperty IsColumnWidthFlexibleProperty = DependencyProperty.Register( "IsColumnWidthFlexible", typeof(bool), _typeofThis, new FrameworkPropertyMetadata( true, FrameworkPropertyMetadataOptions.AffectsMeasure)); ///property. /// /// Whether the width of columns is flexible. If this property is true, then columns /// will frequently be wider than ColumnWidth. If false, columns will always be exactly /// ColumnWidth (as long as the value is smaller than the width of the page minus padding). /// public bool IsColumnWidthFlexible { get { return (bool)GetValue(IsColumnWidthFlexibleProperty); } set { SetValue(IsColumnWidthFlexibleProperty, value); } } ////// DependencyProperty for public static readonly DependencyProperty ColumnRuleWidthProperty = DependencyProperty.Register( "ColumnRuleWidth", typeof(double), _typeofThis, new FrameworkPropertyMetadata( 0.0, FrameworkPropertyMetadataOptions.AffectsMeasure), new ValidateValueCallback(IsValidColumnRuleWidth)); ///property. /// /// The width of the line drawn in between columns. This value is clamped /// to be no larger than the ColumnGap. /// [TypeConverter(typeof(LengthConverter))] [Localizability(LocalizationCategory.None, Readability = Readability.Unreadable)] public double ColumnRuleWidth { get { return (double)GetValue(ColumnRuleWidthProperty); } set { SetValue(ColumnRuleWidthProperty, value); } } ////// DependencyProperty for public static readonly DependencyProperty ColumnRuleBrushProperty = DependencyProperty.Register( "ColumnRuleBrush", typeof(Brush), _typeofThis, new FrameworkPropertyMetadata( null, FrameworkPropertyMetadataOptions.AffectsRender)); ///property. /// /// The brush used to draw the line between columns. /// public Brush ColumnRuleBrush { get { return (Brush)GetValue(ColumnRuleBrushProperty); } set { SetValue(ColumnRuleBrushProperty, value); } } ////// DependencyProperty for public static readonly DependencyProperty IsOptimalParagraphEnabledProperty = DependencyProperty.Register( "IsOptimalParagraphEnabled", typeof(bool), _typeofThis, new FrameworkPropertyMetadata( false, FrameworkPropertyMetadataOptions.AffectsMeasure)); ///property. /// /// Whether FlowDocument should attempt to construct optimal text paragraphs. /// public bool IsOptimalParagraphEnabled { get { return (bool)GetValue(IsOptimalParagraphEnabledProperty); } set { SetValue(IsOptimalParagraphEnabledProperty, value); } } ////// DependencyProperty for public static readonly DependencyProperty PageWidthProperty = DependencyProperty.Register( "PageWidth", typeof(double), _typeofThis, new FrameworkPropertyMetadata( double.NaN, FrameworkPropertyMetadataOptions.AffectsMeasure, new PropertyChangedCallback(OnPageMetricsChanged), new CoerceValueCallback(CoercePageWidth)), new ValidateValueCallback(IsValidPageSize)); ///property. /// /// The width of pages returned by GetPage. This value takes precedence over /// PageSize.Width, MinPageWidth, and MaxPageWidth. /// [TypeConverter(typeof(LengthConverter))] public double PageWidth { get { return (double) GetValue(PageWidthProperty); } set { SetValue(PageWidthProperty, value); } } ////// DependencyProperty for public static readonly DependencyProperty MinPageWidthProperty = DependencyProperty.Register( "MinPageWidth", typeof(double), _typeofThis, new FrameworkPropertyMetadata( 0.0, FrameworkPropertyMetadataOptions.AffectsMeasure, new PropertyChangedCallback(OnMinPageWidthChanged)), new ValidateValueCallback(IsValidMinPageSize)); ///property. /// /// The minimum width of pages returned by GetPage. This value takes /// precedence over PageSize.Width, but not PageWidth. /// [TypeConverter(typeof(LengthConverter))] public double MinPageWidth { get { return (double) GetValue(MinPageWidthProperty); } set { SetValue(MinPageWidthProperty, value); } } ////// DependencyProperty for public static readonly DependencyProperty MaxPageWidthProperty = DependencyProperty.Register( "MaxPageWidth", typeof(double), _typeofThis, new FrameworkPropertyMetadata( double.PositiveInfinity, FrameworkPropertyMetadataOptions.AffectsMeasure, new PropertyChangedCallback(OnMaxPageWidthChanged), new CoerceValueCallback(CoerceMaxPageWidth)), new ValidateValueCallback(IsValidMaxPageSize)); ///property. /// /// The maximum width of pages returned by GetPage. This value takes /// precedence over PageSize.Width, but not PageWidth. /// [TypeConverter(typeof(LengthConverter))] public double MaxPageWidth { get { return (double) GetValue(MaxPageWidthProperty); } set { SetValue(MaxPageWidthProperty, value); } } ////// DependencyProperty for public static readonly DependencyProperty PageHeightProperty = DependencyProperty.Register( "PageHeight", typeof(double), _typeofThis, new FrameworkPropertyMetadata( double.NaN, FrameworkPropertyMetadataOptions.AffectsMeasure, new PropertyChangedCallback(OnPageMetricsChanged), new CoerceValueCallback(CoercePageHeight)), new ValidateValueCallback(IsValidPageSize)); ///property. /// /// The height of pages returned by GetPage. This value takes precedence /// over PageSize.Height, MinPageHeight, and MaxPageHeight. /// [TypeConverter(typeof(LengthConverter))] public double PageHeight { get { return (double) GetValue(PageHeightProperty); } set { SetValue(PageHeightProperty, value); } } ////// DependencyProperty for public static readonly DependencyProperty MinPageHeightProperty = DependencyProperty.Register( "MinPageHeight", typeof(double), _typeofThis, new FrameworkPropertyMetadata( 0.0, FrameworkPropertyMetadataOptions.AffectsMeasure, new PropertyChangedCallback(OnMinPageHeightChanged)), new ValidateValueCallback(IsValidMinPageSize)); ///property. /// /// The minimum height of pages returned by GetPage. This value takes /// precedence over PageSize.Height, but not PageHeight. /// [TypeConverter(typeof(LengthConverter))] public double MinPageHeight { get { return (double) GetValue(MinPageHeightProperty); } set { SetValue(MinPageHeightProperty, value); } } ////// DependencyProperty for public static readonly DependencyProperty MaxPageHeightProperty = DependencyProperty.Register( "MaxPageHeight", typeof(double), _typeofThis, new FrameworkPropertyMetadata( double.PositiveInfinity, FrameworkPropertyMetadataOptions.AffectsMeasure, new PropertyChangedCallback(OnMaxPageHeightChanged), new CoerceValueCallback(CoerceMaxPageHeight)), new ValidateValueCallback(IsValidMaxPageSize)); ///property. /// /// The maximum height of pages returned by GetPage. This value takes /// precedence over PageSize.Height, but not PageHeight. /// [TypeConverter(typeof(LengthConverter))] public double MaxPageHeight { get { return (double) GetValue(MaxPageHeightProperty); } set { SetValue(MaxPageHeightProperty, value); } } ////// DependencyProperty for public static readonly DependencyProperty PagePaddingProperty = DependencyProperty.Register( "PagePadding", typeof(Thickness), _typeofThis, new FrameworkPropertyMetadata( new Thickness(Double.NaN), FrameworkPropertyMetadataOptions.AffectsMeasure, new PropertyChangedCallback(OnPageMetricsChanged)), new ValidateValueCallback(IsValidPagePadding)); ///property. /// /// Padding applied between the page boundaries and the content of the page. /// If the sum of the specified padding in a dimension is greater than the /// corresponding page dimension, then the padding values in that dimension /// will be proportionally reduced such that the sum of the padding in that /// dimension is equal to the page dimension. /// For example, if the PageSize is (100, 100) and PagePadding is (0, 120, 0, 80), /// then the page will be formatted as if the PagePadding were actually (0, 60, 0, 40). /// public Thickness PagePadding { get { return (Thickness) GetValue(PagePaddingProperty); } set { SetValue(PagePaddingProperty, value); } } ////// Class providing access to all text typography properties /// public Typography Typography { get { return new Typography(this); } } ////// DependencyProperty for hyphenation property. /// public static readonly DependencyProperty IsHyphenationEnabledProperty = Block.IsHyphenationEnabledProperty.AddOwner(_typeofThis); ////// CLR property for hyphenation /// public bool IsHyphenationEnabled { get { return (bool)GetValue(IsHyphenationEnabledProperty); } set { SetValue(IsHyphenationEnabledProperty, value); } } #endregion Public Dynamic Properties #endregion Public Properties //-------------------------------------------------------------------- // // Protected Methods // //-------------------------------------------------------------------- #region Protected Methods ////// Notification that a specified property has been invalidated /// /// EventArgs that contains the property, metadata, old value, and new value for this change protected sealed override void OnPropertyChanged(DependencyPropertyChangedEventArgs e) { // Always call base.OnPropertyChanged, otherwise Property Engine will not work. base.OnPropertyChanged(e); if (e.IsAValueChange || e.IsASubPropertyChange) { // Skip caches invalidation if content has not been formatted yet - non of caches are valid, // so they will be aquired during first formatting (full format). if (_structuralCache != null && _structuralCache.IsFormattedOnce) { FrameworkPropertyMetadata fmetadata = e.Metadata as FrameworkPropertyMetadata; if (fmetadata != null) { bool affectsRender = (fmetadata.AffectsRender && (e.IsAValueChange || !fmetadata.SubPropertiesDoNotAffectRender)); if (fmetadata.AffectsMeasure || fmetadata.AffectsArrange || affectsRender || fmetadata.AffectsParentMeasure || fmetadata.AffectsParentArrange) { // Detect invalid content change operations. if (_structuralCache.IsFormattingInProgress) { _structuralCache.OnInvalidOperationDetected(); throw new InvalidOperationException(SR.Get(SRID.FlowDocumentInvalidContnetChange)); } // None of FlowDocument properties can invalidate structural caches (the NameTable), // but most likely it invalidates format caches. Invalidate all format caches // accumulated in the NameTable. _structuralCache.InvalidateFormatCache(!affectsRender); // Notify formatter about content invalidation. if (_formatter != null) { _formatter.OnContentInvalidated(!affectsRender); } } } } } } ////// Creates AutomationPeer ( protected override AutomationPeer OnCreateAutomationPeer() { return new DocumentAutomationPeer(this); } #endregion Protected Methods //------------------------------------------------------------------- // // Protected Properties // //-------------------------------------------------------------------- #region Protected Properties ///) /// /// Returns enumerator to logical children. /// protected internal override IEnumerator LogicalChildren { get { return new RangeContentEnumerator(_structuralCache.TextContainer.Start, _structuralCache.TextContainer.End); } } ////// Fetches the value of the IsEnabled property /// ////// We want to coerce ContentElements and UIElement children of FlowDocument to be disabled in _editable_ content (ie, RichTextBox). /// In read-only mode, in say the FlowDocumentReader, we don't want any coercing. /// protected override bool IsEnabledCore { get { if (!base.IsEnabledCore) { return false; } RichTextBox parentRichTextBox = this.Parent as RichTextBox; return (parentRichTextBox == null) ? true : parentRichTextBox.IsDocumentEnabled; } } #endregion Protected Properties //------------------------------------------------------------------- // // Internal Methods // //------------------------------------------------------------------- #region Internal Methods ////// Returns a ContentPosition for an object. /// /// Object within this element's tree. ///Returns a ContentPosition for an object. internal ContentPosition GetObjectPosition(Object element) { TextPointer flowContentPosition; ITextPointer textPointer = null; DependencyObject parentOfEmbeddedElement; // If element is 'this', return ContentPosition representing ContentStart. if (element == this) { textPointer = this.ContentStart; } // If element is a TextElement, return its ContentStart. else if (element is TextElement) { textPointer = ((TextElement)element).ContentStart; } // Otherwise we are dealing with embedded element. Find its position in the // TextContainer and return it. // It is possible that somebody asks for FrameworkElement that is not an immediate // child of FlowDocument's content. In such case walk up the parent chain and // get FrameworkElement that is directly embedded within FlowDocument's content. else if (element is FrameworkElement) { parentOfEmbeddedElement = null; while (element is FrameworkElement) { parentOfEmbeddedElement = LogicalTreeHelper.GetParent((DependencyObject)element); if (parentOfEmbeddedElement == null) { parentOfEmbeddedElement = VisualTreeHelper.GetParent((Visual)element); } if (!(parentOfEmbeddedElement is FrameworkElement)) { break; } element = parentOfEmbeddedElement; } if (parentOfEmbeddedElement is BlockUIContainer || parentOfEmbeddedElement is InlineUIContainer) { textPointer = TextContainerHelper.GetTextPointerForEmbeddedObject((FrameworkElement)element); } } // Check if the TextPointer belongs to our tree. if (textPointer != null && textPointer.TextContainer != _structuralCache.TextContainer) { textPointer = null; } flowContentPosition = textPointer as TextPointer; return (flowContentPosition != null) ? flowContentPosition : ContentPosition.Missing; } ////// OnChildDesiredSizeChanged /// Called from FlowDocumentPage for IContentHost implementation /// internal void OnChildDesiredSizeChanged(UIElement child) { if (_structuralCache != null && _structuralCache.IsFormattedOnce && !_structuralCache.ForceReformat) { // If executed during formatting process, delay invalidation. // This may happen during formatting when text host notifies its about // baseline changes. if (_structuralCache.IsFormattingInProgress) { Dispatcher.BeginInvoke(DispatcherPriority.Normal, new DispatcherOperationCallback(OnChildDesiredSizeChangedAsync), child); return; } // Get start and end positions int childStartIndex = TextContainerHelper.GetCPFromEmbeddedObject(child, ElementEdge.BeforeStart); if (childStartIndex < 0) { return; } TextPointer childStart = new TextPointer(_structuralCache.TextContainer.Start); childStart.MoveByOffset(childStartIndex); TextPointer childEnd = new TextPointer(childStart); childEnd.MoveByOffset(TextContainerHelper.EmbeddedObjectLength); // Create new DTR for changing UIElement and add it to DRTList. DirtyTextRange dtr = new DirtyTextRange(childStartIndex, TextContainerHelper.EmbeddedObjectLength, TextContainerHelper.EmbeddedObjectLength); _structuralCache.AddDirtyTextRange(dtr); // Notify formatter about content invalidation. if (_formatter != null) { _formatter.OnContentInvalidated(true, childStart, childEnd); } } } /// /// Do delayed initialization before first formatting. /// internal void InitializeForFirstFormatting() { _structuralCache.TextContainer.Changing += new EventHandler(OnTextContainerChanging); _structuralCache.TextContainer.Change += new TextContainerChangeEventHandler(OnTextContainerChange); _structuralCache.TextContainer.Highlights.Changed += new HighlightChangedEventHandler(OnHighlightChanged); } ////// Clear the TextContainer and unregister events. Called by TextBox on style change. /// internal void Uninitialize() { _structuralCache.TextContainer.Changing -= new EventHandler(OnTextContainerChanging); _structuralCache.TextContainer.Change -= new TextContainerChangeEventHandler(OnTextContainerChange); _structuralCache.TextContainer.Highlights.Changed -= new HighlightChangedEventHandler(OnHighlightChanged); _structuralCache.IsFormattedOnce = false; } ////// Compute margin for a page. /// internal Thickness ComputePageMargin() { double lineHeight = DynamicPropertyReader.GetLineHeightValue(this); Thickness pageMargin = this.PagePadding; // If Padding value is 'Auto', treat it as 1*LineHeight. if (DoubleUtil.IsNaN(pageMargin.Left)) { pageMargin.Left = lineHeight; } if (DoubleUtil.IsNaN(pageMargin.Top)) { pageMargin.Top = lineHeight; } if (DoubleUtil.IsNaN(pageMargin.Right)) { pageMargin.Right = lineHeight; } if (DoubleUtil.IsNaN(pageMargin.Bottom)) { pageMargin.Bottom = lineHeight; } return pageMargin; } ////// Called before the parent is changed to the new value. /// We listen to parent change notifications to enforce coercing FlowDocument's IsEnabled property to false /// (when it is parented by RichTextBox). /// This property coersion is done in 2 parts. /// 1. Implement IsEnabledCore for property coersion /// 2. Listen to changes to parent /// (2) needs to be done, since property system does not coerce default values. /// Listening to parent changes guarantees that every time FlowDocument is removed or connected to a RichTextBox parent, /// we explicitly coerce IsEnabled for the new tree. /// /// internal override void OnNewParent(DependencyObject newParent) { DependencyObject oldParent = this.Parent; base.OnNewParent(newParent); if (newParent is RichTextBox || oldParent is RichTextBox) { CoerceValue(IsEnabledProperty); } } #endregion Internal Methods //------------------------------------------------------------------- // // Internal Properties // //-------------------------------------------------------------------- #region Internal Properties ////// An object which formats botomless content. /// internal FlowDocumentFormatter BottomlessFormatter { get { if (_formatter != null && !(_formatter is FlowDocumentFormatter)) { _formatter.Suspend(); _formatter = null; } if (_formatter == null) { _formatter = new FlowDocumentFormatter(this); } return (FlowDocumentFormatter)_formatter; } } ////// StructuralCache. /// internal StructuralCache StructuralCache { get { return _structuralCache; } } ////// Typography properties group. /// internal TypographyProperties TypographyPropertiesGroup { get { if (_typographyPropertiesGroup == null) { _typographyPropertiesGroup = TextElement.GetTypographyProperties(this); } return _typographyPropertiesGroup; } } ////// TextWrapping property value (set by TextBox/RichTextBox) /// internal TextWrapping TextWrapping { get { return _textWrapping; } set { _textWrapping = value; } } ////// Formatter value /// internal IFlowDocumentFormatter Formatter { get { return _formatter; } } //------------------------------------------------------------------- // Is layout data is in a valid state. //-------------------------------------------------------------------- internal bool IsLayoutDataValid { get { if(_formatter != null) { return _formatter.IsLayoutDataValid; } return false; } } //-------------------------------------------------------------------- // TextContainer associated with this FlowDocument. //------------------------------------------------------------------- internal TextContainer TextContainer { get { return _structuralCache.TextContainer; } } #endregion Internal Properties //-------------------------------------------------------------------- // // Internal Events // //------------------------------------------------------------------- #region Internal Events ////// Fired when a PageSize property is changed /// internal event EventHandler PageSizeChanged; #endregion Internal Events //------------------------------------------------------------------- // // Private Methods // //------------------------------------------------------------------- #region Private Methods ////// One of the properties which comprises TypographyProperties has changed -- reset cache. /// private static void OnTypographyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { ((FlowDocument)d)._typographyPropertiesGroup = null; } ////// OnChildDesiredSizeChanged delayed to avoid changes during page /// formatting. /// /// ///private object OnChildDesiredSizeChangedAsync(object arg) { OnChildDesiredSizeChanged(arg as UIElement); return null; } /// /// Initialize FlowDocument. /// /// private void Initialize(TextContainer textContainer) { if (textContainer == null) { // Create text tree that contains content of the element. textContainer = new TextContainer(this, false /* plainTextOnly */); } // Create structural cache object _structuralCache = new StructuralCache(this, textContainer); _structuralCache.Section = new MS.Internal.PtsHost.Section(_structuralCache); // Get rid of the current formatter. if (_formatter != null) { _formatter.Suspend(); _formatter = null; } } ////// Respond to page metrics changes. /// private static void OnPageMetricsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { FlowDocument fd = (FlowDocument)d; if (fd._structuralCache != null && fd._structuralCache.IsFormattedOnce) { // Notify formatter about content invalidation. if (fd._formatter != null) { // Any change of page metrics invalidates the layout. // Hence page metrics change is treated in the same way as ContentChanged // spanning entire content. fd._formatter.OnContentInvalidated(true); } // Fire notification about the PageSize change - needed in RichTextBox if (fd.PageSizeChanged != null) { // NOTE: May execute external code, so it is possible to get // an exception here. fd.PageSizeChanged(fd, EventArgs.Empty); } } } ////// Respond to MinPageWidth change. /// private static void OnMinPageWidthChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { d.CoerceValue(MaxPageWidthProperty); d.CoerceValue(PageWidthProperty); } ////// Respond to MinPageHeight change. /// private static void OnMinPageHeightChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { d.CoerceValue(MaxPageHeightProperty); d.CoerceValue(PageHeightProperty); } ////// Respond to MaxPageWidth change. /// private static void OnMaxPageWidthChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { d.CoerceValue(PageWidthProperty); } ////// Respond to MaxPageHeight change. /// private static void OnMaxPageHeightChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { d.CoerceValue(PageHeightProperty); } ////// Coerce MaxPageWidth value. /// private static object CoerceMaxPageWidth(DependencyObject d, object value) { FlowDocument fd = (FlowDocument) d; double max = (double) value; double min = fd.MinPageWidth; if (max < min) { return min; } return value; } ////// Coerce MaxPageHeight value. /// private static object CoerceMaxPageHeight(DependencyObject d, object value) { FlowDocument fd = (FlowDocument) d; double max = (double) value; double min = fd.MinPageHeight; if (max < min) { return min; } return value; } ////// Coerce PageWidth value. /// private static object CoercePageWidth(DependencyObject d, object value) { FlowDocument fd = (FlowDocument) d; double width = (double) value; if (!DoubleUtil.IsNaN(width)) { double max = fd.MaxPageWidth; if (width > max) { width = max; } double min = fd.MinPageWidth; if (width < min) { width = min; } } return value; } ////// Coerce PageHeight value. /// private static object CoercePageHeight(DependencyObject d, object value) { FlowDocument fd = (FlowDocument) d; double height = (double) value; if (!DoubleUtil.IsNaN(height)) { double max = fd.MaxPageHeight; if (height > max) { height = max; } double min = fd.MinPageHeight; if (height < min) { height = min; } } return value; } ////// Invalidates a portion of text affected by a highlight change. /// /// /// private void OnHighlightChanged(object sender, HighlightChangedEventArgs args) { TextSegment textSegment; int i; Invariant.Assert(args != null); Invariant.Assert(args.Ranges != null); Invariant.Assert(_structuralCache != null && _structuralCache.IsFormattedOnce, "Unexpected Highlights.Changed callback before first format!"); // Detect invalid content change operations. if (_structuralCache.IsFormattingInProgress) { _structuralCache.OnInvalidOperationDetected(); throw new InvalidOperationException(SR.Get(SRID.FlowDocumentInvalidContnetChange)); } // The only supported highlight type for FlowDocument is SpellerHightlight. // TextSelection and HighlightComponent are ignored, because they are handled by // separate layer. if (args.OwnerType != typeof(SpellerHighlightLayer)) { return; } if (args.Ranges.Count > 0) { // Invalidate affected pages and break records. // We DTR invalidate if we're using a formatter as well for incremental update. if (_formatter == null || !(_formatter is FlowDocumentFormatter)) { _structuralCache.InvalidateFormatCache(/*Clear structure*/ false); } // Notify formatter about content invalidation. if (_formatter != null) { for (i = 0; i < args.Ranges.Count; i++) { textSegment = (TextSegment)args.Ranges[i]; _formatter.OnContentInvalidated(false, textSegment.Start, textSegment.End); if (_formatter is FlowDocumentFormatter) { DirtyTextRange dtr = new DirtyTextRange(textSegment.Start.Offset, textSegment.Start.GetOffsetToPosition(textSegment.End), textSegment.Start.GetOffsetToPosition(textSegment.End) ); _structuralCache.AddDirtyTextRange(dtr); } } } } } ////// Handler for TextContainer changing notifications. /// private void OnTextContainerChanging(object sender, EventArgs args) { Invariant.Assert(sender == _structuralCache.TextContainer, "Received text change for foreign TextContainer."); Invariant.Assert(_structuralCache != null && _structuralCache.IsFormattedOnce, "Unexpected TextContainer.Changing callback before first format!"); // Detect invalid content change operations. if (_structuralCache.IsFormattingInProgress) { _structuralCache.OnInvalidOperationDetected(); throw new InvalidOperationException(SR.Get(SRID.FlowDocumentInvalidContnetChange)); } // Remember the fact that content is changing. // OnTextContainerChange has to be received after this event. _structuralCache.IsContentChangeInProgress = true; } ////// Handler for TextContainer change notifications. /// /// /// private void OnTextContainerChange(object sender, TextContainerChangeEventArgs args) { DirtyTextRange dtr; ITextPointer segmentEnd; Invariant.Assert(args != null); Invariant.Assert(sender == _structuralCache.TextContainer); Invariant.Assert(_structuralCache != null && _structuralCache.IsFormattedOnce, "Unexpected TextContainer.Change callback before first format!"); if (args.Count == 0) { // A no-op for this control. Happens when IMECharCount updates happen // without corresponding SymbolCount changes. return; } try { // Detect invalid content change operations. if (_structuralCache.IsFormattingInProgress) { _structuralCache.OnInvalidOperationDetected(); throw new InvalidOperationException(SR.Get(SRID.FlowDocumentInvalidContnetChange)); } // Since content is changeing, do partial invalidation of BreakRecordTable. if (args.TextChange != TextChangeType.ContentRemoved) { segmentEnd = args.ITextPosition.CreatePointer(args.Count, LogicalDirection.Forward); } else { segmentEnd = args.ITextPosition; } // Invalidate affected pages and break records. // We DTR invalidate if we're using a formatter as well for incremental update. if (!args.AffectsRenderOnly || (_formatter != null && _formatter is FlowDocumentFormatter)) { // Create new DTR for changing range and add it to DRTList. dtr = new DirtyTextRange(args); _structuralCache.AddDirtyTextRange(dtr); } else { // Clear format caches. _structuralCache.InvalidateFormatCache(/*Clear structure*/ false); } // Notify formatter about content invalidation. if (_formatter != null) { _formatter.OnContentInvalidated(!args.AffectsRenderOnly, args.ITextPosition, segmentEnd); } } finally { // Content has been changed, so reset appropriate flag. _structuralCache.IsContentChangeInProgress = false; } } private static bool IsValidPageSize(object o) { double value = (double)o; double maxSize = Math.Min(1000000, PTS.MaxPageSize); if (Double.IsNaN(value)) { return true; } if (value < 0 || value > maxSize) { return false; } return true; } private static bool IsValidMinPageSize(object o) { double value = (double)o; double maxSize = Math.Min(1000000, PTS.MaxPageSize); if (Double.IsNaN(value)) { return false; } if (!Double.IsNegativeInfinity(value) && (value < 0 || value > maxSize)) { return false; } return true; } private static bool IsValidMaxPageSize(object o) { double value = (double)o; double maxSize = Math.Min(1000000, PTS.MaxPageSize); if (Double.IsNaN(value)) { return false; } if (!Double.IsPositiveInfinity(value) && (value < 0 || value > maxSize)) { return false; } return true; } private static bool IsValidPagePadding(object o) { Thickness value = (Thickness)o; return Block.IsValidThickness(value, /*allow NaN*/true); } private static bool IsValidColumnRuleWidth(object o) { double ruleWidth = (double)o; double maxRuleWidth = Math.Min(1000000, PTS.MaxPageSize); if (Double.IsNaN(ruleWidth) || ruleWidth < 0 || ruleWidth > maxRuleWidth) { return false; } return true; } private static bool IsValidColumnGap(object o) { double gap = (double)o; double maxGap = Math.Min(1000000, PTS.MaxPageSize); if (Double.IsNaN(gap)) { // Default value. return true; } if (gap < 0 || gap > maxGap) { return false; } return true; } #endregion Private methods //-------------------------------------------------------------------- // // Private Fields // //------------------------------------------------------------------- #region Private Fields private StructuralCache _structuralCache; // Structural cache for the content. private TypographyProperties _typographyPropertiesGroup; // Cache for typography properties. private IFlowDocumentFormatter _formatter; // Current formatter asociated with FlowDocument. private TextWrapping _textWrapping = TextWrapping.Wrap; // internal cache for TextBox/RichTextBox #endregion Private Fields //-------------------------------------------------------------------- // // IAddChild Members // //-------------------------------------------------------------------- #region IAddChild Members ////// Called to Add the object as a Child. /// /// /// Object to add as a child /// void IAddChild.AddChild(Object value) { if (value == null) { throw new ArgumentNullException("value"); } if (!TextSchema.IsValidChildOfContainer(/*parentType:*/_typeofThis, /*childType:*/value.GetType())) { throw new ArgumentException(SR.Get(SRID.TextSchema_ChildTypeIsInvalid, _typeofThis.Name, value.GetType().Name)); } // Checking that the element inserted does not have a parent if (value is TextElement && ((TextElement)value).Parent != null) { throw new ArgumentException(SR.Get(SRID.TextSchema_TheChildElementBelongsToAnotherTreeAlready, value.GetType().Name)); } if (value is Block) { TextContainer textContainer = _structuralCache.TextContainer; ((Block)value).RepositionWithContent(textContainer.End); } else { Invariant.Assert(false); // We do not expect anything except Blocks on top level of a FlowDocument } } ////// Called when text appears under the tag in markup /// /// /// Text to Add to the Object /// void IAddChild.AddText(string text) { XamlSerializerUtil.ThrowIfNonWhiteSpaceInAddText(text, this); } #endregion IAddChild Members //------------------------------------------------------------------- // // IServiceProvider Members // //-------------------------------------------------------------------- #region IServiceProvider Members ////// Gets the service object of the specified type. /// ////// FlowDocument supports only TextContainer. /// /// /// An object that specifies the type of service object to get. /// ////// A service object of type serviceType. A null reference if there is no /// service object of type serviceType. /// object IServiceProvider.GetService(Type serviceType) { if (serviceType == null) { throw new ArgumentNullException("serviceType"); } if (serviceType == typeof(ITextContainer)) { return _structuralCache.TextContainer; } else if (serviceType == typeof(TextContainer)) { return _structuralCache.TextContainer as TextContainer; } return null; } #endregion IServiceProvider Members //------------------------------------------------------------------- // // IDocumentPaginatorSource Members // //------------------------------------------------------------------- #region IDocumentPaginatorSource Members ////// An object which paginates content. /// DocumentPaginator IDocumentPaginatorSource.DocumentPaginator { get { if (_formatter != null && !(_formatter is FlowDocumentPaginator)) { _formatter.Suspend(); _formatter = null; } if (_formatter == null) { _formatter = new FlowDocumentPaginator(this); } return (FlowDocumentPaginator)_formatter; } } #endregion IDocumentPaginatorSource Members } } // 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
- HttpResponseInternalWrapper.cs
- WSTrust.cs
- TextSyndicationContentKindHelper.cs
- printdlgexmarshaler.cs
- ActivityCompletionCallbackWrapper.cs
- BinaryObjectWriter.cs
- QilSortKey.cs
- Positioning.cs
- CompiledQuery.cs
- SQLMoney.cs
- ExpressionNode.cs
- Environment.cs
- CompositeCollection.cs
- TaskResultSetter.cs
- FontDriver.cs
- CodeActivity.cs
- LocatorManager.cs
- DragDropManager.cs
- CookieParameter.cs
- LoaderAllocator.cs
- ThicknessConverter.cs
- GrammarBuilderPhrase.cs
- XdrBuilder.cs
- ObjectConverter.cs
- SchemaCollectionCompiler.cs
- TransportDefaults.cs
- RectangleGeometry.cs
- Query.cs
- ValidatorUtils.cs
- SectionInformation.cs
- GraphicsState.cs
- ClassicBorderDecorator.cs
- DeviceContext.cs
- SessionStateUtil.cs
- TransformPattern.cs
- PasswordRecovery.cs
- InputScope.cs
- TableDetailsCollection.cs
- DataSpaceManager.cs
- BaseDataList.cs
- EmptyEnumerator.cs
- Validator.cs
- TextSelectionHelper.cs
- TextModifierScope.cs
- TreeWalker.cs
- TypeGeneratedEventArgs.cs
- XmlAnyAttributeAttribute.cs
- NullExtension.cs
- PageThemeCodeDomTreeGenerator.cs
- FormViewCommandEventArgs.cs
- BamlBinaryReader.cs
- ServicePointManager.cs
- SerializationException.cs
- EncodingDataItem.cs
- FontCollection.cs
- Rfc4050KeyFormatter.cs
- smtppermission.cs
- Debug.cs
- ConstraintManager.cs
- DocumentSequence.cs
- HttpServerChannel.cs
- ObjectResult.cs
- ImageButton.cs
- PointUtil.cs
- ILGenerator.cs
- InputLanguageManager.cs
- SafeNativeMethods.cs
- AdapterDictionary.cs
- DesignerActionItemCollection.cs
- ChannelPool.cs
- ImportedNamespaceContextItem.cs
- PublisherMembershipCondition.cs
- DesignerVerb.cs
- _ListenerAsyncResult.cs
- RegexWorker.cs
- FixedFindEngine.cs
- ThemeDirectoryCompiler.cs
- SmiEventSink_DeferedProcessing.cs
- MouseOverProperty.cs
- GridItem.cs
- ComponentConverter.cs
- UnsafeNativeMethodsCLR.cs
- AccessDataSourceWizardForm.cs
- WebPartTransformerCollection.cs
- CodeTypeDeclarationCollection.cs
- CompositionTarget.cs
- XmlSchemaType.cs
- HtmlInputText.cs
- DefaultShape.cs
- CommandConverter.cs
- CapabilitiesUse.cs
- PointLight.cs
- ContentTypeSettingDispatchMessageFormatter.cs
- PersonalizationEntry.cs
- DeploymentSectionCache.cs
- CommandField.cs
- SimpleHandlerBuildProvider.cs
- KnownTypes.cs
- DataGridViewAdvancedBorderStyle.cs
- ValidatingReaderNodeData.cs