RichTextBox.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

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

                            //---------------------------------------------------------------------------- 
//
// File: RichTextBox.cs
//
// Copyright (C) Microsoft Corporation.  All rights reserved. 
//
// Description: The stock rich text editing control. 
// 
//---------------------------------------------------------------------------
 
namespace System.Windows.Controls
{
    using MS.Internal;
    using MS.Internal.Documents; 
    using System.Windows.Threading;
    using System.Windows.Input; // KeyboardNavigation 
    using System.ComponentModel; // DefaultValue 
    using System.Windows.Controls.Primitives; // TextBoxBase
    using System.Windows.Documents; // TextEditor 
    using System.Windows.Automation.Peers; // AutomationPattern
    using System.Windows.Media; // GlyphRun
    using System.Windows.Markup; // IAddChild
    using System.Collections; // IEnumerator 
    using System.Collections.ObjectModel; // ReadOnlyCollection
    using MS.Internal.Automation;     // For TextAdaptor 
    using MS.Internal.Controls; // EmptyEnumerator 

    ///  
    /// RichTextBox control
    /// 
    [Localizability(LocalizationCategory.Inherit)]
    [ContentProperty("Document")] 
    public class RichTextBox : TextBoxBase, IAddChild
    { 
        // ----------------------------------------------------------- 
        //
        // Constructors 
        //
        // -----------------------------------------------------------

        #region Constructors 

        ///  
        /// Static constructor for RichTextBox. 
        /// 
        static RichTextBox() 
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(RichTextBox), new FrameworkPropertyMetadata(typeof(RichTextBox)));
            _dType = DependencyObjectType.FromSystemTypeInternal(typeof(RichTextBox));
 
            // Default value for AcceptsReturn is true
            KeyboardNavigation.AcceptsReturnProperty.OverrideMetadata(typeof(RichTextBox), new FrameworkPropertyMetadata(true)); 
 
            // Default value for AutoWordSelection is false.  We want true.
            TextBoxBase.AutoWordSelectionProperty.OverrideMetadata(typeof(RichTextBox), new FrameworkPropertyMetadata(true)); 

            // We need to transfer all character formatting properties and some behavioral inheriting properties
            // from RichTextBox level into its FlowDocument.
            // For this purpose we set listeners for all these properties: 
            HookupInheritablePropertyListeners();
        } 
 
        /// 
        /// Initializes a new instance of RichTextBox control. 
        /// 
        /// 
        /// Creates implicit instance of a FlowDocument as its oinitial content.
        /// The initial document will contain one Paragraph with an empty Run in it. 
        /// 
        public RichTextBox() 
            : this(null) 
        {
        } 

        /// 
        /// Initializes a new instance of RichTextBox control ans specifies a FlowDocument as its content
        ///  
        /// 
        /// A FlowDocument specified as a content for this instance of RichTextBox. 
        ///  
        public RichTextBox(FlowDocument document)
            : base() 
        {
            // Register static editing command handlers.
            // This only has an effect that first time we make the call.
            // We don't use the static ctor because there are cases 
            // where another control will want to alias our properties
            // but doesn't need this overhead. 
            TextEditor.RegisterCommandHandlers(typeof(RichTextBox), /*acceptsRichContent:*/true, /*readOnly*/false, /*registerEventListeners*/false); 

            // Create TextContainer and TextEditor associated with it 
            if (document == null)
            {
                document = new FlowDocument();
                document.Blocks.Add(new Paragraph()); 

                // Mark the document as implicit. 
                // This flag will affect these behaviors: 
                //  a) RichTextBox serialization will not output FlowDocument child if it is implicit and still empty
                //  b) IAddChild will allow adding the first child (which will become non-implicit, and would not allow the subsecuent additions) 
                //  c) Property inheritance from RichTextBox to its FlowDocument will work only for implicit document
                // This call must be done after Document assignment, as it always clears the _implicitDocument field.
                _implicitDocument = true;
            } 

            // Initialize the Document property. 
            // Note that _implicitDocument flag was set to true/false just before that. 
            // The peemptive flag setting has its effect only when _document is null (this case only),
            // otherwise the new document would be considered as explicit (so flag would be cleared by the Document property assignment). 
            this.Document = document;

            // Values that must be set as a side effect of Document assignment,
            // that are required for the RichTextBox instance functioning. 
            Invariant.Assert(this.TextContainer != null);
            Invariant.Assert(this.TextEditor != null); 
            Invariant.Assert(this.TextEditor.TextContainer == this.TextContainer); 
        }
 
        #endregion Constructors

        // ------------------------------------------------------------
        // 
        // Public Methods
        // 
        // ----------------------------------------------------------- 

        #region Public Methods 

        // ------------------------------------------------------------
        //
        // IAddChild interface 
        //
        // ------------------------------------------------------------ 
 
        ///
        /// This method is called to Add the object as a child of the RichTextBox.  This method is used primarily 
        /// by the parser; a more direct way of adding a child to a RichTextBox is to use the 
        /// property.
        ///
        /// 
        /// The object to add as a child; it must be a UIElement.
        /// 
        void IAddChild.AddChild(Object value) 
        {
            if (value == null) 
            {
                throw new ArgumentNullException("value");
            }
 
            if (!(value is FlowDocument))
            { 
                throw new ArgumentException(SR.Get(SRID.UnexpectedParameterType, value.GetType(), typeof(FlowDocument)), "value"); 
            }
 
            if (!_implicitDocument)
            {
                throw new ArgumentException(SR.Get(SRID.CanOnlyHaveOneChild, this.GetType(), value.GetType()));
            } 

            this.Document = (FlowDocument)value; 
        } 

        /// 
        /// This method is called by the parser when text appears under the tag in markup.
        /// As RichTextBox do not support text, calling this method has no effect if the text
        /// is all whitespace.  For non-whitespace text, throw an exception.
        /// 
        ///
        /// Text to add as a child. 
        /// 
        void IAddChild.AddText(string text)
        { 
            if (text == null)
            {
                throw new ArgumentNullException("text");
            } 

            XamlSerializerUtil.ThrowIfNonWhiteSpaceInAddText(text, this); 
        } 

 
        ///
        /// Returns the TextPointer located closest to a supplied Point.
        /// 
        ///  
        /// Point to query, in the coordinate space of the RichTextBox.
        ///  
        ///  
        /// If true, this method will always return a TextPointer --
        /// the closest position as calculated by the control's heuristics. 
        /// If false, this method will return a null position if the test
        /// point does not fall within any character bounding box.
        /// 
        ///  
        /// The closest TextPointer to the supplied Point, or null if
        /// snapToText is false and the supplied Point is not contained 
        /// within any character bounding box, or if no content element yet exists. 
        /// 
        ///  
        /// Throws InvalidOperationException if layout is dirty.
        /// 
        public TextPointer GetPositionFromPoint(Point point, bool snapToText)
        { 
            if (this.RenderScope == null)
            { 
                return null; 
            }
 
            return (TextPointer)GetTextPositionFromPointInternal(point, snapToText);
        }

        ///  
        /// Returns the associated SpellingError at a specified position.
        ///  
        ///  
        /// Position of text to query.
        ///  
        /// 
        /// The position and its LogicalDirection specify a character to query.
        /// If the specificed character is not part of a misspelled word then
        /// this method will return null. 
        /// 
        public SpellingError GetSpellingError(TextPointer position) 
        { 
            ValidationHelper.VerifyPosition(this.TextContainer, position);
 
            return this.TextEditor.GetSpellingErrorAtPosition(position, position.LogicalDirection);
        }

        ///  
        /// Returns the TextRange covering a misspelled word at a specified
        /// position. 
        ///  
        /// 
        /// Position of text to query. 
        /// 
        /// 
        /// The position and its LogicalDirection specify a character to query.
        /// If the specificed character is not part of a misspelled word then 
        /// this method will return null.
        ///  
        public TextRange GetSpellingErrorRange(TextPointer position) 
        {
            ValidationHelper.VerifyPosition(this.TextContainer, position); 

            SpellingError spellingError = this.TextEditor.GetSpellingErrorAtPosition(position, position.LogicalDirection);

            return (spellingError == null) ? null : new TextRange(spellingError.Start, spellingError.End); 
        }
 
        ///  
        /// Returns the position of the next character in a specificed direction
        /// that is the start of a misspelled word. 
        /// 
        /// 
        /// Position of text to query.
        ///  
        /// 
        /// Direction to query. 
        ///  
        /// 
        /// The position and its LogicalDirection specify a character to query. 
        /// The search includes the spelling error containing the character
        /// specified by position/direction (if any).
        ///
        /// If no misspelled word is encountered, the method returns null. 
        /// 
        public TextPointer GetNextSpellingErrorPosition(TextPointer position, LogicalDirection direction) 
        { 
            ValidationHelper.VerifyPosition(this.TextContainer, position);
 
            return (TextPointer)this.TextEditor.GetNextSpellingErrorPosition(position, direction);
        }

        #endregion Public Methods 

        //----------------------------------------------------- 
        // 
        //  Protected Methods
        // 
        //------------------------------------------------------

        #region Protected Methods
 
        /// 
        /// Creates AutomationPeer () 
        ///  
        protected override AutomationPeer OnCreateAutomationPeer()
        { 
            return new RichTextBoxAutomationPeer(this);
        }

        ///  
        /// Measurement override. Implement your size-to-content logic here.
        ///  
        ///  
        /// Sizing constraint.
        ///  
        protected override Size MeasureOverride(Size constraint)
        {
            if (constraint.Width == Double.PositiveInfinity)
            { 
                // If we're sized to infinity, we won't behave the same way TextBox does under
                // the same conditions.  So, we fake it. 
                constraint.Width = this.MinWidth; 
            }
            return base.MeasureOverride(constraint); 
        }

        // Allocates the initial render scope for this control.
        internal override FrameworkElement CreateRenderScope() 
        {
            FlowDocumentView renderScope = new FlowDocumentView(); 
            renderScope.Document = this.Document; 

            // Set a margin so that the BiDi Or Italic caret has room to render at the edges of content. 
            // Otherwise, anti-aliasing or italic causes the caret to be partially clipped.
            renderScope.Document.PagePadding = new Thickness(CaretElement.CaretPaddingWidth, 0, CaretElement.CaretPaddingWidth, 0);

            // We want current style to ignore all properties from theme style for renderScope. 
            renderScope.OverridesDefaultStyle = true;
 
            return renderScope; 
        }
 
        #endregion Protected Methods

        // -----------------------------------------------------------
        // 
        // Public Properties
        // 
        // ----------------------------------------------------------- 

        #region Public Properties 

        /// 
        /// A Property representing a content of this RichTextBox
        ///  
        public FlowDocument Document
        { 
            get 
            {
                Invariant.Assert(_document != null); 
                return _document;
            }

            set 
            {
                if (value == null) 
                { 
                    throw new ArgumentNullException("value");
                } 

                if (value != _document &&
                    value.StructuralCache != null && value.StructuralCache.TextContainer != null &&
                    value.StructuralCache.TextContainer.TextSelection != null) 
                {
                    throw new ArgumentException(SR.Get(SRID.RichTextBox_DocumentBelongsToAnotherRichTextBoxAlready)); 
                } 

                if (_document != null && this.TextSelectionInternal.ChangeBlockLevel > 0) 
                {
                    throw new InvalidOperationException(SR.Get(SRID.RichTextBox_CantSetDocumentInsideChangeBlock));
                }
 
                if (value == _document)
                { 
                    // Same document nothing to do. 
                    return;
                } 

                // Identify the case for the _document initialization
                bool initialSetting = _document == null;
 
                // Detach existing FlowDocument
                if (_document != null) 
                { 
                    // Detach PageSize change listener
                    _document.PageSizeChanged -= new EventHandler(this.OnPageSizeChangedHandler); 

                    // Remove the document from the logical tree
                    this.RemoveLogicalChild(_document);
 
                    // Stop collecting text changes
                    _document.TextContainer.CollectTextChanges = false; 
 
                    // Clear thereference to a document
                    _document = null; 
                }

                // Clear the implicitDocument flag.
                // Any assignment to the Document property clears the _implicitDocument flag 
                // expect for the initial one, which may happen from a RichTextBox constructor which
                // can create an empolicit document and sets _implicitDocument flag before 
                // the Document property assignment. 
                if (!initialSetting)
                { 
                    _implicitDocument = false;
                }

                // Store the document for future use - just for comparing when it changes and detaching from it 
                _document = value;
 
                // Save existing renderScope before calling TextBoxBase.InitializeTextContainer, 
                // because it will discard it.
                UIElement renderScope = this.RenderScope; 

                // Start collecting text changes
                _document.TextContainer.CollectTextChanges = true;
 
                // Attach to new text container and re-create TextEditor instance
                this.InitializeTextContainer(_document.TextContainer); 
 
                // Add listener for PageSize - to redirect it to inner renderScope.Width
                _document.PageSizeChanged += new EventHandler(this.OnPageSizeChangedHandler); 

                // Add the document as a child to the logical tree
                this.AddLogicalChild(_document);
 
                // Re-attach to visual tree
                if (renderScope != null) 
                { 
                    // Re-atach to visual tree if we have a new TextContainer.
                    this.AttachToVisualTree(); 
                }

                // Make sure that all inherited properties properly transferred
                // to the new document according to its Standalone/Inherited status. 
                TransferInheritedPropertiesToFlowDocument();
 
                // Raise a TextChanged event for all assignments except initializing one. 
                if (!initialSetting)
                { 
                    //Re-apply the cached undo properties
                    this.ChangeUndoLimit(this.UndoLimit);
                    this.ChangeUndoEnabled(this.IsUndoEnabled);
 
                    Invariant.Assert(this.PendingUndoAction == UndoAction.None);
                    this.PendingUndoAction = UndoAction.Clear; 
                    try 
                    {
                        this.OnTextChanged(new TextChangedEventArgs(TextChangedEvent, UndoAction.Clear)); 
                    }
                    finally
                    {
                        this.PendingUndoAction = UndoAction.None; 
                    }
                } 
            } 
        }
 
        /// 
        /// This method is used by TypeDescriptor to determine if this property should
        /// be serialized.
        ///  
        // According to the contract with the serializer the (private) method named as
        // ShouldSerialize tells the serializer whether it should serialize the 
        // property for this instance or not. 
        // We want to avoid serializing implicitly created document if it does not have any meaningful content.
        [EditorBrowsable(EditorBrowsableState.Never)] 
        public bool ShouldSerializeDocument()
        {
            Block firstBlock = _document.Blocks.FirstBlock;
 
            if (_implicitDocument &&
                (firstBlock == null 
                    || 
                    firstBlock == _document.Blocks.LastBlock &&
                    firstBlock is Paragraph)) 
            {
                Inline firstInline = (firstBlock == null) ? null : ((Paragraph)firstBlock).Inlines.FirstInline;
                if (firstInline == null
                        || 
                        firstInline == ((Paragraph)firstBlock).Inlines.LastInline &&
                        firstInline is Run && 
                        firstInline.ContentStart.CompareTo(firstInline.ContentEnd) == 0) 
                {
                    // We have implicit document without any text content. 
                    return false;
                }
            }
 
            // In all other cases we should serialize the FlowDocument child.
            return true; 
        } 

        ///  
        /// Enables or disables TextElements and UIElements contained in this RichTextBox's FlowDocument.
        /// 
        /// 
        /// By default child elements have their IsEnabled property coerced 
        /// false when hosted by RichTextBox.  Use this property to enable
        /// contained elements. 
        ///  
        public static readonly DependencyProperty IsDocumentEnabledProperty =
            DependencyProperty.Register("IsDocumentEnabled", typeof(bool), typeof(RichTextBox), 
            new FrameworkPropertyMetadata(false, new PropertyChangedCallback(OnIsDocumentEnabledChanged)));

        /// 
        /// Enables or disables TextElements and UIElements contained in this RichTextBox's FlowDocument. 
        /// 
        ///  
        ///  
        /// 
        public bool IsDocumentEnabled 
        {
            get
            {
                return (bool)GetValue(IsDocumentEnabledProperty); 
            }
 
            set 
            {
                SetValue(IsDocumentEnabledProperty, value); 
            }
        }

        // ........................................................... 
        //
        // Content Accessing Properties 
        // 
        // ..........................................................
 
        #region Content Accessing Properties

        /// 
        /// Returns enumerator to logical children 
        /// 
        protected internal override IEnumerator LogicalChildren 
        { 
            get
            { 
                if (this._document == null)
                {
                    // Using _document (not .Document),as it can be null on destruction scenarios
                    // (even though .Document cannot be null) - it is called for property invalidation reasons... 
                    return EmptyEnumerator.Instance;
                } 
                else 
                {
                    return new SingleChildEnumerator(this._document); 
                }
            }
        }
 
        /// 
        /// Text Selection (readonly) 
        ///  
        public TextSelection Selection
        { 
            get
            {
                return (TextSelection)TextSelectionInternal;
            } 
        }
 
        ///  
        /// Position of the caret.
        ///  
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public TextPointer CaretPosition
        {
            get 
            {
                return Selection.MovingPosition; 
            } 

            set 
            {
                if (value == null)
                {
                    throw new ArgumentNullException("value"); 
                }
                if (!Selection.Start.IsInSameDocument(value)) 
                { 
                    throw new ArgumentException(SR.Get(SRID.RichTextBox_PointerNotInSameDocument), "value");
                } 
                Selection.SetCaretToPosition(value, value.LogicalDirection, /*allowStopAtLineEnd:*/true, /*allowStopNearSpace:*/false);
            }
        }
 
        #endregion Content Accessing Properties
 
        #endregion Public Properties 

        //----------------------------------------------------- 
        //
        //  Internal Methods
        //
        //------------------------------------------------------ 

        #region Internal Methods 
 
        // 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;
            } 
        } 

        #endregion Internal Methods 

        // -----------------------------------------------------------
        //
        // Private Methods 
        //
        // ------------------------------------------------------------ 
 
        #region Private Methods
 
        // ...........................................................
        //
        // Transferring Properties from RichTextBox down to FlowDocument
        // 
        // ...........................................................
 
        // We need to transfer all character formatting properties from RichTextBox level into its FlowDocument. 
        //
        // Note that we have to set all properties explicitly - not even trying 
        // to bypass some of them when using assumptions about their default values (for non-implicit document)
        // or a coincidence with the current context values (for implicit document) -
        // the FlowDocument mast have all properties explicitly set to keep them intact
        // after being moved to another contextual location (both in Save-Load and in Print scenarios). 

        // For this purpose we set listeners for all these properties: 
        private static void HookupInheritablePropertyListeners() 
        {
            // All inhgeriting formatting properties need to be transferred over the implicit document boundary. 
            // This is required for treating UIContext as default setting for implicit document.
            // Note that mechanism is not applied to explicit document.
            PropertyChangedCallback formattingPropertyCallback = new PropertyChangedCallback(OnFormattingPropertyChanged);
            DependencyProperty[] inheritableFormattingProperties = TextSchema.GetInheritableProperties(typeof(FlowDocument)); 
            for (int i = 0; i < inheritableFormattingProperties.Length; i++)
            { 
                inheritableFormattingProperties[i].OverrideMetadata(typeof(RichTextBox), new FrameworkPropertyMetadata(formattingPropertyCallback)); 
            }
 
            // Inheriting behavioral properties need to be transferred over any Standalone document boundary.
            PropertyChangedCallback behavioralPropertyCallback = new PropertyChangedCallback(OnBehavioralPropertyChanged);
            DependencyProperty[] inheritableBehavioralProperties = TextSchema.BehavioralProperties;
            for (int i = 0; i < inheritableBehavioralProperties.Length; i++) 
            {
                inheritableBehavioralProperties[i].OverrideMetadata(typeof(RichTextBox), new FrameworkPropertyMetadata(behavioralPropertyCallback)); 
            } 
        }
 
        // Transfer all properties from the current context to this
        // implicit document - to simulate inheritance.
        // This is how implicit document gets its initial values -
        // from the context. 
        // After that RichTextBox will maintain such inheritance simulation
        // (for implicit document only) by listening for property 
        // change notifications. 
        private void TransferInheritedPropertiesToFlowDocument()
        { 
            // Implicit document needs all formatting properties be transferred to it
            if (_implicitDocument)
            {
                DependencyProperty[] inheritableFormattingProperties = TextSchema.GetInheritableProperties(typeof(FlowDocument)); 
                for (int i = 0; i < inheritableFormattingProperties.Length; i++)
                { 
                    DependencyProperty property = inheritableFormattingProperties[i]; 
                    TransferFormattingProperty(property, this.GetValue(property));
                } 
            }

            // Behavioral properties must be transferred to any document whether it has Standalone
            // or Inherited FormattingDefaults. All such values are set as local values even 
            // in case when they are equal to the ones inherited from the UI context
            // (see TransferBehavioralProperty method implementation). 
            // Such strong logic is needed to work correctly in any sequence of 
            // setting FormattingDefaults property and adding children.
            DependencyProperty[] inheritableBehavioralProperties = TextSchema.BehavioralProperties; 
            for (int i = 0; i < inheritableBehavioralProperties.Length; i++)
            {
                DependencyProperty property = inheritableBehavioralProperties[i];
                TransferBehavioralProperty(property, this.GetValue(property)); 
            }
        } 
 
        /// 
        /// Callback for changes to the any text formatting property. 
        /// Transfers the new value to explisit setting on a FlowDocument.
        /// 
        private static void OnFormattingPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        { 
            RichTextBox richTextBox = (RichTextBox)d;
 
            if (richTextBox._implicitDocument) 
            {
                richTextBox.TransferFormattingProperty(e.Property, e.NewValue); 
            }
        }

        // Transfers single formatting property from this RichTextBox to its implicit document 
        private void TransferFormattingProperty(DependencyProperty property, object inheritedValue)
        { 
            Invariant.Assert(_implicitDocument, "We only supposed to do this for implicit documents"); 

            object defaultValue = _document.GetValue(property); 
            if (!TextSchema.ValuesAreEqual(inheritedValue, defaultValue))
            {
                _document.ClearValue(property);
                defaultValue = _document.GetValue(property); 
                if (!TextSchema.ValuesAreEqual(inheritedValue, defaultValue))
                { 
                    _document.SetValue(property, inheritedValue); 
                }
            } 
        }

        /// 
        /// Callback for changes to the any behavioral property. 
        /// Transfers the new value to a FlowDocument.
        ///  
        ///  
        /// Behavioral properties must be transferred to any document whether it has Standalone
        /// or Inherited FormattingDefaults. All such values are set as local values even 
        /// in case when they are equal to the ones inherited from the UI context.
        /// Such strong logic is needed to work correctly in any sequence of
        /// setting FormattingDefaults property and adding children.
        ///  
        private static void OnBehavioralPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        { 
            RichTextBox richTextBox = (RichTextBox)d; 

            richTextBox.TransferBehavioralProperty(e.Property, e.NewValue); 
        }

        /// 
        /// Transfers single behavioral property from this RichTextBox to its implicit document 
        /// 
        ///  
        /// Behavioral properties must be transferred to any document whether it has Standalone 
        /// or Inherited FormattingDefaults. All such values are set as local values even
        /// in case when they are equal to the ones inherited from the UI context. 
        /// Such strong logic is needed to work correctly in any sequence of
        /// setting FormattingDefaults property and adding children.
        /// 
        private void TransferBehavioralProperty(DependencyProperty property, object inheritedValue) 
        {
            // Set the value unconditionally as explicit local value 
            _document.SetValue(property, inheritedValue); 
        }
 
        // ...........................................................
        //
        // TextEditor Parameterization Properties Access
        // 
        // ...........................................................
 
        #region TextEditor Parameterization Propeties Access 

        private void OnPageSizeChangedHandler(object sender, EventArgs e) 
        {
            if (this.RenderScope == null)
            {
                return; 
            }
 
            // Make sure that the TextWrapping property is set correctly 
            if (this.Document != null)
            { 
                this.Document.TextWrapping = TextWrapping.Wrap;
            }

            // The Document does not have explicit PageWidth set OR Wrap/WrapWithOverflow is requested. 
            // The RenderScope must occupy as much space as its content required (no wrapping)
            // We could set Width to positive infinity, but that would make horizontal scrollbar 
            // look wrong. So we need to make sure that render scope has a size of 
            // its actual content. For that we clear loal value of Width property
            // from RenderScope. 

            // To let RenderScope occupy all space we clear Width local value on it.
            this.RenderScope.ClearValue(FlowDocumentView.WidthProperty);
 
            // Set alighment to Stretch - for RenderScope to occupy the whole viewport.
            this.RenderScope.ClearValue(FrameworkElement.HorizontalAlignmentProperty); 
            // Normally TextBox style does not set any balue for HorizontalAlignment property, 
            // so clearing would set it to a required default - Stretch.
            // However, if style author sets some other value - it will be set as a result of ClearValue, 
            // so we need to enforce that.
            // Note, that trying to clear first saves a memory for inline property application.
            if (this.RenderScope.HorizontalAlignment != HorizontalAlignment.Stretch)
            { 
                this.RenderScope.HorizontalAlignment = HorizontalAlignment.Stretch;
            } 
        } 

 
        #endregion TextEditor Parameterization Properties Access

        // Callback for IsDocumentEnabledProperty changes.
        // Forces a coercion of the child FlowDocument, with the new setting. 
        private static void OnIsDocumentEnabledChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        { 
            RichTextBox richTextBox = (RichTextBox)d; 

            if (richTextBox.Document != null) 
            {
                richTextBox.Document.CoerceValue(IsEnabledProperty);
            }
        } 

        #endregion Private Methods 
 
        // ------------------------------------------------------------
        // 
        // Private Fields
        //
        // -----------------------------------------------------------
 
        #region Private Fields
 
        private FlowDocument _document; 
        private bool _implicitDocument; // true if Document property was set by AddChild or Document setter (not in constructor)
 
        private static DependencyObjectType _dType; // Needed for property system optimization

        #endregion Private Fields
    } 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
//---------------------------------------------------------------------------- 
//
// File: RichTextBox.cs
//
// Copyright (C) Microsoft Corporation.  All rights reserved. 
//
// Description: The stock rich text editing control. 
// 
//---------------------------------------------------------------------------
 
namespace System.Windows.Controls
{
    using MS.Internal;
    using MS.Internal.Documents; 
    using System.Windows.Threading;
    using System.Windows.Input; // KeyboardNavigation 
    using System.ComponentModel; // DefaultValue 
    using System.Windows.Controls.Primitives; // TextBoxBase
    using System.Windows.Documents; // TextEditor 
    using System.Windows.Automation.Peers; // AutomationPattern
    using System.Windows.Media; // GlyphRun
    using System.Windows.Markup; // IAddChild
    using System.Collections; // IEnumerator 
    using System.Collections.ObjectModel; // ReadOnlyCollection
    using MS.Internal.Automation;     // For TextAdaptor 
    using MS.Internal.Controls; // EmptyEnumerator 

    ///  
    /// RichTextBox control
    /// 
    [Localizability(LocalizationCategory.Inherit)]
    [ContentProperty("Document")] 
    public class RichTextBox : TextBoxBase, IAddChild
    { 
        // ----------------------------------------------------------- 
        //
        // Constructors 
        //
        // -----------------------------------------------------------

        #region Constructors 

        ///  
        /// Static constructor for RichTextBox. 
        /// 
        static RichTextBox() 
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(RichTextBox), new FrameworkPropertyMetadata(typeof(RichTextBox)));
            _dType = DependencyObjectType.FromSystemTypeInternal(typeof(RichTextBox));
 
            // Default value for AcceptsReturn is true
            KeyboardNavigation.AcceptsReturnProperty.OverrideMetadata(typeof(RichTextBox), new FrameworkPropertyMetadata(true)); 
 
            // Default value for AutoWordSelection is false.  We want true.
            TextBoxBase.AutoWordSelectionProperty.OverrideMetadata(typeof(RichTextBox), new FrameworkPropertyMetadata(true)); 

            // We need to transfer all character formatting properties and some behavioral inheriting properties
            // from RichTextBox level into its FlowDocument.
            // For this purpose we set listeners for all these properties: 
            HookupInheritablePropertyListeners();
        } 
 
        /// 
        /// Initializes a new instance of RichTextBox control. 
        /// 
        /// 
        /// Creates implicit instance of a FlowDocument as its oinitial content.
        /// The initial document will contain one Paragraph with an empty Run in it. 
        /// 
        public RichTextBox() 
            : this(null) 
        {
        } 

        /// 
        /// Initializes a new instance of RichTextBox control ans specifies a FlowDocument as its content
        ///  
        /// 
        /// A FlowDocument specified as a content for this instance of RichTextBox. 
        ///  
        public RichTextBox(FlowDocument document)
            : base() 
        {
            // Register static editing command handlers.
            // This only has an effect that first time we make the call.
            // We don't use the static ctor because there are cases 
            // where another control will want to alias our properties
            // but doesn't need this overhead. 
            TextEditor.RegisterCommandHandlers(typeof(RichTextBox), /*acceptsRichContent:*/true, /*readOnly*/false, /*registerEventListeners*/false); 

            // Create TextContainer and TextEditor associated with it 
            if (document == null)
            {
                document = new FlowDocument();
                document.Blocks.Add(new Paragraph()); 

                // Mark the document as implicit. 
                // This flag will affect these behaviors: 
                //  a) RichTextBox serialization will not output FlowDocument child if it is implicit and still empty
                //  b) IAddChild will allow adding the first child (which will become non-implicit, and would not allow the subsecuent additions) 
                //  c) Property inheritance from RichTextBox to its FlowDocument will work only for implicit document
                // This call must be done after Document assignment, as it always clears the _implicitDocument field.
                _implicitDocument = true;
            } 

            // Initialize the Document property. 
            // Note that _implicitDocument flag was set to true/false just before that. 
            // The peemptive flag setting has its effect only when _document is null (this case only),
            // otherwise the new document would be considered as explicit (so flag would be cleared by the Document property assignment). 
            this.Document = document;

            // Values that must be set as a side effect of Document assignment,
            // that are required for the RichTextBox instance functioning. 
            Invariant.Assert(this.TextContainer != null);
            Invariant.Assert(this.TextEditor != null); 
            Invariant.Assert(this.TextEditor.TextContainer == this.TextContainer); 
        }
 
        #endregion Constructors

        // ------------------------------------------------------------
        // 
        // Public Methods
        // 
        // ----------------------------------------------------------- 

        #region Public Methods 

        // ------------------------------------------------------------
        //
        // IAddChild interface 
        //
        // ------------------------------------------------------------ 
 
        ///
        /// This method is called to Add the object as a child of the RichTextBox.  This method is used primarily 
        /// by the parser; a more direct way of adding a child to a RichTextBox is to use the 
        /// property.
        ///
        /// 
        /// The object to add as a child; it must be a UIElement.
        /// 
        void IAddChild.AddChild(Object value) 
        {
            if (value == null) 
            {
                throw new ArgumentNullException("value");
            }
 
            if (!(value is FlowDocument))
            { 
                throw new ArgumentException(SR.Get(SRID.UnexpectedParameterType, value.GetType(), typeof(FlowDocument)), "value"); 
            }
 
            if (!_implicitDocument)
            {
                throw new ArgumentException(SR.Get(SRID.CanOnlyHaveOneChild, this.GetType(), value.GetType()));
            } 

            this.Document = (FlowDocument)value; 
        } 

        /// 
        /// This method is called by the parser when text appears under the tag in markup.
        /// As RichTextBox do not support text, calling this method has no effect if the text
        /// is all whitespace.  For non-whitespace text, throw an exception.
        /// 
        ///
        /// Text to add as a child. 
        /// 
        void IAddChild.AddText(string text)
        { 
            if (text == null)
            {
                throw new ArgumentNullException("text");
            } 

            XamlSerializerUtil.ThrowIfNonWhiteSpaceInAddText(text, this); 
        } 

 
        ///
        /// Returns the TextPointer located closest to a supplied Point.
        /// 
        ///  
        /// Point to query, in the coordinate space of the RichTextBox.
        ///  
        ///  
        /// If true, this method will always return a TextPointer --
        /// the closest position as calculated by the control's heuristics. 
        /// If false, this method will return a null position if the test
        /// point does not fall within any character bounding box.
        /// 
        ///  
        /// The closest TextPointer to the supplied Point, or null if
        /// snapToText is false and the supplied Point is not contained 
        /// within any character bounding box, or if no content element yet exists. 
        /// 
        ///  
        /// Throws InvalidOperationException if layout is dirty.
        /// 
        public TextPointer GetPositionFromPoint(Point point, bool snapToText)
        { 
            if (this.RenderScope == null)
            { 
                return null; 
            }
 
            return (TextPointer)GetTextPositionFromPointInternal(point, snapToText);
        }

        ///  
        /// Returns the associated SpellingError at a specified position.
        ///  
        ///  
        /// Position of text to query.
        ///  
        /// 
        /// The position and its LogicalDirection specify a character to query.
        /// If the specificed character is not part of a misspelled word then
        /// this method will return null. 
        /// 
        public SpellingError GetSpellingError(TextPointer position) 
        { 
            ValidationHelper.VerifyPosition(this.TextContainer, position);
 
            return this.TextEditor.GetSpellingErrorAtPosition(position, position.LogicalDirection);
        }

        ///  
        /// Returns the TextRange covering a misspelled word at a specified
        /// position. 
        ///  
        /// 
        /// Position of text to query. 
        /// 
        /// 
        /// The position and its LogicalDirection specify a character to query.
        /// If the specificed character is not part of a misspelled word then 
        /// this method will return null.
        ///  
        public TextRange GetSpellingErrorRange(TextPointer position) 
        {
            ValidationHelper.VerifyPosition(this.TextContainer, position); 

            SpellingError spellingError = this.TextEditor.GetSpellingErrorAtPosition(position, position.LogicalDirection);

            return (spellingError == null) ? null : new TextRange(spellingError.Start, spellingError.End); 
        }
 
        ///  
        /// Returns the position of the next character in a specificed direction
        /// that is the start of a misspelled word. 
        /// 
        /// 
        /// Position of text to query.
        ///  
        /// 
        /// Direction to query. 
        ///  
        /// 
        /// The position and its LogicalDirection specify a character to query. 
        /// The search includes the spelling error containing the character
        /// specified by position/direction (if any).
        ///
        /// If no misspelled word is encountered, the method returns null. 
        /// 
        public TextPointer GetNextSpellingErrorPosition(TextPointer position, LogicalDirection direction) 
        { 
            ValidationHelper.VerifyPosition(this.TextContainer, position);
 
            return (TextPointer)this.TextEditor.GetNextSpellingErrorPosition(position, direction);
        }

        #endregion Public Methods 

        //----------------------------------------------------- 
        // 
        //  Protected Methods
        // 
        //------------------------------------------------------

        #region Protected Methods
 
        /// 
        /// Creates AutomationPeer () 
        ///  
        protected override AutomationPeer OnCreateAutomationPeer()
        { 
            return new RichTextBoxAutomationPeer(this);
        }

        ///  
        /// Measurement override. Implement your size-to-content logic here.
        ///  
        ///  
        /// Sizing constraint.
        ///  
        protected override Size MeasureOverride(Size constraint)
        {
            if (constraint.Width == Double.PositiveInfinity)
            { 
                // If we're sized to infinity, we won't behave the same way TextBox does under
                // the same conditions.  So, we fake it. 
                constraint.Width = this.MinWidth; 
            }
            return base.MeasureOverride(constraint); 
        }

        // Allocates the initial render scope for this control.
        internal override FrameworkElement CreateRenderScope() 
        {
            FlowDocumentView renderScope = new FlowDocumentView(); 
            renderScope.Document = this.Document; 

            // Set a margin so that the BiDi Or Italic caret has room to render at the edges of content. 
            // Otherwise, anti-aliasing or italic causes the caret to be partially clipped.
            renderScope.Document.PagePadding = new Thickness(CaretElement.CaretPaddingWidth, 0, CaretElement.CaretPaddingWidth, 0);

            // We want current style to ignore all properties from theme style for renderScope. 
            renderScope.OverridesDefaultStyle = true;
 
            return renderScope; 
        }
 
        #endregion Protected Methods

        // -----------------------------------------------------------
        // 
        // Public Properties
        // 
        // ----------------------------------------------------------- 

        #region Public Properties 

        /// 
        /// A Property representing a content of this RichTextBox
        ///  
        public FlowDocument Document
        { 
            get 
            {
                Invariant.Assert(_document != null); 
                return _document;
            }

            set 
            {
                if (value == null) 
                { 
                    throw new ArgumentNullException("value");
                } 

                if (value != _document &&
                    value.StructuralCache != null && value.StructuralCache.TextContainer != null &&
                    value.StructuralCache.TextContainer.TextSelection != null) 
                {
                    throw new ArgumentException(SR.Get(SRID.RichTextBox_DocumentBelongsToAnotherRichTextBoxAlready)); 
                } 

                if (_document != null && this.TextSelectionInternal.ChangeBlockLevel > 0) 
                {
                    throw new InvalidOperationException(SR.Get(SRID.RichTextBox_CantSetDocumentInsideChangeBlock));
                }
 
                if (value == _document)
                { 
                    // Same document nothing to do. 
                    return;
                } 

                // Identify the case for the _document initialization
                bool initialSetting = _document == null;
 
                // Detach existing FlowDocument
                if (_document != null) 
                { 
                    // Detach PageSize change listener
                    _document.PageSizeChanged -= new EventHandler(this.OnPageSizeChangedHandler); 

                    // Remove the document from the logical tree
                    this.RemoveLogicalChild(_document);
 
                    // Stop collecting text changes
                    _document.TextContainer.CollectTextChanges = false; 
 
                    // Clear thereference to a document
                    _document = null; 
                }

                // Clear the implicitDocument flag.
                // Any assignment to the Document property clears the _implicitDocument flag 
                // expect for the initial one, which may happen from a RichTextBox constructor which
                // can create an empolicit document and sets _implicitDocument flag before 
                // the Document property assignment. 
                if (!initialSetting)
                { 
                    _implicitDocument = false;
                }

                // Store the document for future use - just for comparing when it changes and detaching from it 
                _document = value;
 
                // Save existing renderScope before calling TextBoxBase.InitializeTextContainer, 
                // because it will discard it.
                UIElement renderScope = this.RenderScope; 

                // Start collecting text changes
                _document.TextContainer.CollectTextChanges = true;
 
                // Attach to new text container and re-create TextEditor instance
                this.InitializeTextContainer(_document.TextContainer); 
 
                // Add listener for PageSize - to redirect it to inner renderScope.Width
                _document.PageSizeChanged += new EventHandler(this.OnPageSizeChangedHandler); 

                // Add the document as a child to the logical tree
                this.AddLogicalChild(_document);
 
                // Re-attach to visual tree
                if (renderScope != null) 
                { 
                    // Re-atach to visual tree if we have a new TextContainer.
                    this.AttachToVisualTree(); 
                }

                // Make sure that all inherited properties properly transferred
                // to the new document according to its Standalone/Inherited status. 
                TransferInheritedPropertiesToFlowDocument();
 
                // Raise a TextChanged event for all assignments except initializing one. 
                if (!initialSetting)
                { 
                    //Re-apply the cached undo properties
                    this.ChangeUndoLimit(this.UndoLimit);
                    this.ChangeUndoEnabled(this.IsUndoEnabled);
 
                    Invariant.Assert(this.PendingUndoAction == UndoAction.None);
                    this.PendingUndoAction = UndoAction.Clear; 
                    try 
                    {
                        this.OnTextChanged(new TextChangedEventArgs(TextChangedEvent, UndoAction.Clear)); 
                    }
                    finally
                    {
                        this.PendingUndoAction = UndoAction.None; 
                    }
                } 
            } 
        }
 
        /// 
        /// This method is used by TypeDescriptor to determine if this property should
        /// be serialized.
        ///  
        // According to the contract with the serializer the (private) method named as
        // ShouldSerialize tells the serializer whether it should serialize the 
        // property for this instance or not. 
        // We want to avoid serializing implicitly created document if it does not have any meaningful content.
        [EditorBrowsable(EditorBrowsableState.Never)] 
        public bool ShouldSerializeDocument()
        {
            Block firstBlock = _document.Blocks.FirstBlock;
 
            if (_implicitDocument &&
                (firstBlock == null 
                    || 
                    firstBlock == _document.Blocks.LastBlock &&
                    firstBlock is Paragraph)) 
            {
                Inline firstInline = (firstBlock == null) ? null : ((Paragraph)firstBlock).Inlines.FirstInline;
                if (firstInline == null
                        || 
                        firstInline == ((Paragraph)firstBlock).Inlines.LastInline &&
                        firstInline is Run && 
                        firstInline.ContentStart.CompareTo(firstInline.ContentEnd) == 0) 
                {
                    // We have implicit document without any text content. 
                    return false;
                }
            }
 
            // In all other cases we should serialize the FlowDocument child.
            return true; 
        } 

        ///  
        /// Enables or disables TextElements and UIElements contained in this RichTextBox's FlowDocument.
        /// 
        /// 
        /// By default child elements have their IsEnabled property coerced 
        /// false when hosted by RichTextBox.  Use this property to enable
        /// contained elements. 
        ///  
        public static readonly DependencyProperty IsDocumentEnabledProperty =
            DependencyProperty.Register("IsDocumentEnabled", typeof(bool), typeof(RichTextBox), 
            new FrameworkPropertyMetadata(false, new PropertyChangedCallback(OnIsDocumentEnabledChanged)));

        /// 
        /// Enables or disables TextElements and UIElements contained in this RichTextBox's FlowDocument. 
        /// 
        ///  
        ///  
        /// 
        public bool IsDocumentEnabled 
        {
            get
            {
                return (bool)GetValue(IsDocumentEnabledProperty); 
            }
 
            set 
            {
                SetValue(IsDocumentEnabledProperty, value); 
            }
        }

        // ........................................................... 
        //
        // Content Accessing Properties 
        // 
        // ..........................................................
 
        #region Content Accessing Properties

        /// 
        /// Returns enumerator to logical children 
        /// 
        protected internal override IEnumerator LogicalChildren 
        { 
            get
            { 
                if (this._document == null)
                {
                    // Using _document (not .Document),as it can be null on destruction scenarios
                    // (even though .Document cannot be null) - it is called for property invalidation reasons... 
                    return EmptyEnumerator.Instance;
                } 
                else 
                {
                    return new SingleChildEnumerator(this._document); 
                }
            }
        }
 
        /// 
        /// Text Selection (readonly) 
        ///  
        public TextSelection Selection
        { 
            get
            {
                return (TextSelection)TextSelectionInternal;
            } 
        }
 
        ///  
        /// Position of the caret.
        ///  
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public TextPointer CaretPosition
        {
            get 
            {
                return Selection.MovingPosition; 
            } 

            set 
            {
                if (value == null)
                {
                    throw new ArgumentNullException("value"); 
                }
                if (!Selection.Start.IsInSameDocument(value)) 
                { 
                    throw new ArgumentException(SR.Get(SRID.RichTextBox_PointerNotInSameDocument), "value");
                } 
                Selection.SetCaretToPosition(value, value.LogicalDirection, /*allowStopAtLineEnd:*/true, /*allowStopNearSpace:*/false);
            }
        }
 
        #endregion Content Accessing Properties
 
        #endregion Public Properties 

        //----------------------------------------------------- 
        //
        //  Internal Methods
        //
        //------------------------------------------------------ 

        #region Internal Methods 
 
        // 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;
            } 
        } 

        #endregion Internal Methods 

        // -----------------------------------------------------------
        //
        // Private Methods 
        //
        // ------------------------------------------------------------ 
 
        #region Private Methods
 
        // ...........................................................
        //
        // Transferring Properties from RichTextBox down to FlowDocument
        // 
        // ...........................................................
 
        // We need to transfer all character formatting properties from RichTextBox level into its FlowDocument. 
        //
        // Note that we have to set all properties explicitly - not even trying 
        // to bypass some of them when using assumptions about their default values (for non-implicit document)
        // or a coincidence with the current context values (for implicit document) -
        // the FlowDocument mast have all properties explicitly set to keep them intact
        // after being moved to another contextual location (both in Save-Load and in Print scenarios). 

        // For this purpose we set listeners for all these properties: 
        private static void HookupInheritablePropertyListeners() 
        {
            // All inhgeriting formatting properties need to be transferred over the implicit document boundary. 
            // This is required for treating UIContext as default setting for implicit document.
            // Note that mechanism is not applied to explicit document.
            PropertyChangedCallback formattingPropertyCallback = new PropertyChangedCallback(OnFormattingPropertyChanged);
            DependencyProperty[] inheritableFormattingProperties = TextSchema.GetInheritableProperties(typeof(FlowDocument)); 
            for (int i = 0; i < inheritableFormattingProperties.Length; i++)
            { 
                inheritableFormattingProperties[i].OverrideMetadata(typeof(RichTextBox), new FrameworkPropertyMetadata(formattingPropertyCallback)); 
            }
 
            // Inheriting behavioral properties need to be transferred over any Standalone document boundary.
            PropertyChangedCallback behavioralPropertyCallback = new PropertyChangedCallback(OnBehavioralPropertyChanged);
            DependencyProperty[] inheritableBehavioralProperties = TextSchema.BehavioralProperties;
            for (int i = 0; i < inheritableBehavioralProperties.Length; i++) 
            {
                inheritableBehavioralProperties[i].OverrideMetadata(typeof(RichTextBox), new FrameworkPropertyMetadata(behavioralPropertyCallback)); 
            } 
        }
 
        // Transfer all properties from the current context to this
        // implicit document - to simulate inheritance.
        // This is how implicit document gets its initial values -
        // from the context. 
        // After that RichTextBox will maintain such inheritance simulation
        // (for implicit document only) by listening for property 
        // change notifications. 
        private void TransferInheritedPropertiesToFlowDocument()
        { 
            // Implicit document needs all formatting properties be transferred to it
            if (_implicitDocument)
            {
                DependencyProperty[] inheritableFormattingProperties = TextSchema.GetInheritableProperties(typeof(FlowDocument)); 
                for (int i = 0; i < inheritableFormattingProperties.Length; i++)
                { 
                    DependencyProperty property = inheritableFormattingProperties[i]; 
                    TransferFormattingProperty(property, this.GetValue(property));
                } 
            }

            // Behavioral properties must be transferred to any document whether it has Standalone
            // or Inherited FormattingDefaults. All such values are set as local values even 
            // in case when they are equal to the ones inherited from the UI context
            // (see TransferBehavioralProperty method implementation). 
            // Such strong logic is needed to work correctly in any sequence of 
            // setting FormattingDefaults property and adding children.
            DependencyProperty[] inheritableBehavioralProperties = TextSchema.BehavioralProperties; 
            for (int i = 0; i < inheritableBehavioralProperties.Length; i++)
            {
                DependencyProperty property = inheritableBehavioralProperties[i];
                TransferBehavioralProperty(property, this.GetValue(property)); 
            }
        } 
 
        /// 
        /// Callback for changes to the any text formatting property. 
        /// Transfers the new value to explisit setting on a FlowDocument.
        /// 
        private static void OnFormattingPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        { 
            RichTextBox richTextBox = (RichTextBox)d;
 
            if (richTextBox._implicitDocument) 
            {
                richTextBox.TransferFormattingProperty(e.Property, e.NewValue); 
            }
        }

        // Transfers single formatting property from this RichTextBox to its implicit document 
        private void TransferFormattingProperty(DependencyProperty property, object inheritedValue)
        { 
            Invariant.Assert(_implicitDocument, "We only supposed to do this for implicit documents"); 

            object defaultValue = _document.GetValue(property); 
            if (!TextSchema.ValuesAreEqual(inheritedValue, defaultValue))
            {
                _document.ClearValue(property);
                defaultValue = _document.GetValue(property); 
                if (!TextSchema.ValuesAreEqual(inheritedValue, defaultValue))
                { 
                    _document.SetValue(property, inheritedValue); 
                }
            } 
        }

        /// 
        /// Callback for changes to the any behavioral property. 
        /// Transfers the new value to a FlowDocument.
        ///  
        ///  
        /// Behavioral properties must be transferred to any document whether it has Standalone
        /// or Inherited FormattingDefaults. All such values are set as local values even 
        /// in case when they are equal to the ones inherited from the UI context.
        /// Such strong logic is needed to work correctly in any sequence of
        /// setting FormattingDefaults property and adding children.
        ///  
        private static void OnBehavioralPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        { 
            RichTextBox richTextBox = (RichTextBox)d; 

            richTextBox.TransferBehavioralProperty(e.Property, e.NewValue); 
        }

        /// 
        /// Transfers single behavioral property from this RichTextBox to its implicit document 
        /// 
        ///  
        /// Behavioral properties must be transferred to any document whether it has Standalone 
        /// or Inherited FormattingDefaults. All such values are set as local values even
        /// in case when they are equal to the ones inherited from the UI context. 
        /// Such strong logic is needed to work correctly in any sequence of
        /// setting FormattingDefaults property and adding children.
        /// 
        private void TransferBehavioralProperty(DependencyProperty property, object inheritedValue) 
        {
            // Set the value unconditionally as explicit local value 
            _document.SetValue(property, inheritedValue); 
        }
 
        // ...........................................................
        //
        // TextEditor Parameterization Properties Access
        // 
        // ...........................................................
 
        #region TextEditor Parameterization Propeties Access 

        private void OnPageSizeChangedHandler(object sender, EventArgs e) 
        {
            if (this.RenderScope == null)
            {
                return; 
            }
 
            // Make sure that the TextWrapping property is set correctly 
            if (this.Document != null)
            { 
                this.Document.TextWrapping = TextWrapping.Wrap;
            }

            // The Document does not have explicit PageWidth set OR Wrap/WrapWithOverflow is requested. 
            // The RenderScope must occupy as much space as its content required (no wrapping)
            // We could set Width to positive infinity, but that would make horizontal scrollbar 
            // look wrong. So we need to make sure that render scope has a size of 
            // its actual content. For that we clear loal value of Width property
            // from RenderScope. 

            // To let RenderScope occupy all space we clear Width local value on it.
            this.RenderScope.ClearValue(FlowDocumentView.WidthProperty);
 
            // Set alighment to Stretch - for RenderScope to occupy the whole viewport.
            this.RenderScope.ClearValue(FrameworkElement.HorizontalAlignmentProperty); 
            // Normally TextBox style does not set any balue for HorizontalAlignment property, 
            // so clearing would set it to a required default - Stretch.
            // However, if style author sets some other value - it will be set as a result of ClearValue, 
            // so we need to enforce that.
            // Note, that trying to clear first saves a memory for inline property application.
            if (this.RenderScope.HorizontalAlignment != HorizontalAlignment.Stretch)
            { 
                this.RenderScope.HorizontalAlignment = HorizontalAlignment.Stretch;
            } 
        } 

 
        #endregion TextEditor Parameterization Properties Access

        // Callback for IsDocumentEnabledProperty changes.
        // Forces a coercion of the child FlowDocument, with the new setting. 
        private static void OnIsDocumentEnabledChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        { 
            RichTextBox richTextBox = (RichTextBox)d; 

            if (richTextBox.Document != null) 
            {
                richTextBox.Document.CoerceValue(IsEnabledProperty);
            }
        } 

        #endregion Private Methods 
 
        // ------------------------------------------------------------
        // 
        // Private Fields
        //
        // -----------------------------------------------------------
 
        #region Private Fields
 
        private FlowDocument _document; 
        private bool _implicitDocument; // true if Document property was set by AddChild or Document setter (not in constructor)
 
        private static DependencyObjectType _dType; // Needed for property system optimization

        #endregion Private Fields
    } 
}

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

Link Menu

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