TextBoxBase.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / wpf / src / Framework / System / Windows / Controls / Primitives / TextBoxBase.cs / 1305600 / TextBoxBase.cs

                            //---------------------------------------------------------------------------- 
//
// File: TextBoxBase.cs
//
// Copyright (C) Microsoft Corporation.  All rights reserved. 
//
// Description: The base class for TextBox and RichTextBox. 
// 
//---------------------------------------------------------------------------
 
namespace System.Windows.Controls.Primitives
{
    using MS.Internal;
    using System.Threading; 
    using System.Collections.ObjectModel;
    using System.ComponentModel; // DefaultValue 
 
    using System.Security;
    using System.Security.Permissions; 

    using System.Windows.Automation; // TextPattern
    using System.Windows.Automation.Provider; // AutomationProvider
    using System.Windows.Data; // Binding 
    using System.Windows.Documents; // TextEditor
    using System.Windows.Input; // MouseButtonEventArgs 
    using System.Windows.Markup; // XamlDesignerSerializer 

    using MS.Internal.Documents;    // Undo 

    using System.Windows.Media; // VisualTreeHelper

    //----------------------------------------------------- 
    //
    //  Public Enumerations 
    // 
    //-----------------------------------------------------
 
    #region Public Enumerations

    #endregion Public Enumerations
 
    /// 
    /// The base class for text editing controls. 
    ///  
    [Localizability(LocalizationCategory.Text)]
    [TemplatePart(Name = "PART_ContentHost", Type = typeof(FrameworkElement))] 
    public abstract class TextBoxBase : Control
    {
        //------------------------------------------------------
        // 
        //  Constructors
        // 
        //----------------------------------------------------- 

        #region Constructors 

        /// 
        /// Static constructor - provides metadata for some properties
        ///  
        static TextBoxBase()
        { 
            DefaultStyleKeyProperty.OverrideMetadata(typeof(TextBoxBase), new FrameworkPropertyMetadata(typeof(TextBoxBase))); 
            _dType = DependencyObjectType.FromSystemTypeInternal(typeof(TextBoxBase));
 
            // Declaree listener for Padding property
            Control.PaddingProperty.OverrideMetadata(typeof(TextBoxBase),
                new FrameworkPropertyMetadata(new PropertyChangedCallback(OnScrollViewerPropertyChanged)));
 
            // Listner for InputMethod enabled/disabled property
            // TextEditor needs to set the document manager focus. 
            InputMethod.IsInputMethodEnabledProperty.OverrideMetadata(typeof(TextBoxBase), 
                new FrameworkPropertyMetadata(new PropertyChangedCallback(OnInputMethodEnabledPropertyChanged)));
 
            IsEnabledProperty.OverrideMetadata(typeof(TextBoxBase), new UIPropertyMetadata(new PropertyChangedCallback(OnVisualStatePropertyChanged)));
            IsMouseOverPropertyKey.OverrideMetadata(typeof(TextBoxBase), new UIPropertyMetadata(new PropertyChangedCallback(OnVisualStatePropertyChanged)));
        }
 
        /// 
        /// Constructor. 
        ///  
        internal TextBoxBase() : base()
        { 
            // Subclass is expected to do three things:
            // a) Register class command handlers
            // b) create TextContainer and call InitializeTextContainer
            // c) configure TextEditor by setting appropriate properties 
            CoerceValue(HorizontalScrollBarVisibilityProperty);
 
            // Security team really wants to set AllowDrop property value as "False" 
            // not to generate the security exception that can be happened in the
            // partial trust environment. 
            if (!SecurityHelper.CallerHasPermissionWithAppDomainOptimization(new SecurityPermission(SecurityPermissionFlag.UnmanagedCode)))
            {
                AllowDrop = false;
            } 
        }
 
        #endregion Constructors 

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

        #region Public Methods 
 
        /// 
        /// Appends text to the current text of text box 
        /// You can use this method to add text to the existing text
        /// in the control instead of using the concatenation operator
        /// (+) to concatenate text to the Text property
        ///  
        /// 
        /// The text to append to the current contents of the text box 
        ///  
        /// 
        /// For RichTextBox this method works similar to TextRange.set_Text: 
        /// every NewLine combination will insert a new Paragraph element.
        /// 
        public void AppendText(string textData)
        { 
            if (textData == null)
            { 
                return; 
            }
 
            TextRange range = new TextRange(_textContainer.End, _textContainer.End);
            range.Text = textData; // Note that in RichTextBox this assignment will convert NewLines into Paragraphs
        }
 
        /// 
        /// Called when the Template's tree has been generated 
        ///  
        public override void OnApplyTemplate()
        { 
            base.OnApplyTemplate();
            AttachToVisualTree();
        }
 
        /// 
        /// Copy the current selection in the text box to the clipboard 
        ///  
        /// 
        ///   Critical - Calls TextEditorCopyPaste.Copy which sets data on the clipboard. 
        ///   PublicOK - Indicates that this was not a user-initiated call, so TextEditorCopyPaste.Copy will
        ///     check for clipboard permission.
        /// 
        [SecurityCritical] 
        public void Copy()
        { 
            TextEditorCopyPaste.Copy(this.TextEditor, false); 
        }
 
        /// 
        /// Moves the current selection in the textbox to the clipboard
        /// 
        ///  
        ///   Critical - Calls TextEditorCopyPaste.Cut which sets data on the clipboard.
        ///   PublicOK - Indicates that this was not a user-initiated call, so TextEditorCopyPaste.Cut will 
        ///     check for clipboard permission. 
        /// 
        [SecurityCritical] 
        public void Cut()
        {
            TextEditorCopyPaste.Cut(this.TextEditor, false);
        } 

        ///  
        /// Replaces the current selection in the textbox with the contents 
        /// of the Clipboard
        ///  
        public void Paste()
        {
            TextEditorCopyPaste.Paste(this.TextEditor);
        } 

        ///  
        /// Select all text in the TextBox 
        /// 
        public void SelectAll() 
        {
            using (this.TextSelectionInternal.DeclareChangeBlock())
            {
                TextSelectionInternal.Select(_textContainer.Start, _textContainer.End); 
            }
        } 
 
        /// 
        /// Scroll content by one line to the left. 
        /// 
        public void LineLeft()
        {
            if (this.ScrollViewer != null) 
            {
                UpdateLayout(); 
                this.ScrollViewer.LineLeft(); 
            }
        } 

        /// 
        /// Scroll content by one line to the right.
        ///  
        public void LineRight()
        { 
            if (this.ScrollViewer != null) 
            {
                UpdateLayout(); 
                this.ScrollViewer.LineRight();
            }
        }
 
        /// 
        /// Scroll content by one page to the left. 
        ///  
        public void PageLeft()
        { 
            if (this.ScrollViewer != null)
            {
                UpdateLayout();
                this.ScrollViewer.PageLeft(); 
            }
        } 
 
        /// 
        /// Scroll content by one page to the right. 
        /// 
        public void PageRight()
        {
            if (this.ScrollViewer != null) 
            {
                UpdateLayout(); 
                this.ScrollViewer.PageRight(); 
            }
        } 

        /// 
        /// Scroll content by one line to the top.
        ///  
        public void LineUp()
        { 
            UpdateLayout(); 
            DoLineUp();
        } 

        /// 
        /// Scroll content by one line to the bottom.
        ///  
        public void LineDown()
        { 
            UpdateLayout(); 
            DoLineDown();
        } 

        /// 
        /// Scroll content by one page to the top.
        ///  
        public void PageUp()
        { 
            if (this.ScrollViewer != null) 
            {
                UpdateLayout(); 
                this.ScrollViewer.PageUp();
            }
        }
 
        /// 
        /// Scroll content by one page to the bottom. 
        ///  
        public void PageDown()
        { 
            if (this.ScrollViewer != null)
            {
                UpdateLayout();
                this.ScrollViewer.PageDown(); 
            }
        } 
 
        /// 
        /// Vertically scroll to the beginning of the content. 
        /// 
        public void ScrollToHome()
        {
            if (this.ScrollViewer != null) 
            {
                UpdateLayout(); 
                this.ScrollViewer.ScrollToHome(); 
            }
        } 

        /// 
        /// Vertically scroll to the end of the content.
        ///  
        public void ScrollToEnd()
        { 
            if (this.ScrollViewer != null) 
            {
                UpdateLayout(); 
                this.ScrollViewer.ScrollToEnd();
            }
        }
 
        /// 
        /// Scroll horizontally to the specified offset. 
        ///  
        public void ScrollToHorizontalOffset(double offset)
        { 
            if (Double.IsNaN(offset))
            {
                throw new ArgumentOutOfRangeException("offset");
            } 

            if (this.ScrollViewer != null) 
            { 
                UpdateLayout();
                this.ScrollViewer.ScrollToHorizontalOffset(offset); 
            }
        }

        ///  
        /// Scroll vertically to the specified offset.
        ///  
        public void ScrollToVerticalOffset(double offset) 
        {
            if (Double.IsNaN(offset)) 
            {
                throw new ArgumentOutOfRangeException("offset");
            }
 
            if (this.ScrollViewer != null)
            { 
                UpdateLayout(); 
                this.ScrollViewer.ScrollToVerticalOffset(offset);
            } 
        }

        /// 
        /// Undo the most recent undo unit on the stack. 
        /// 
        ///  
        /// true if undo succeeds, false otherwise (including when the stack is empty) 
        /// 
        public bool Undo() 
        {
            UndoManager undoManager = UndoManager.GetUndoManager(this);
            if (undoManager != null && undoManager.UndoCount > undoManager.MinUndoStackCount)
            { 
                this.TextEditor.Undo();
                return true; 
            } 

            return false; 
        }

        /// 
        /// Redo the most recent undo unit on the stack. 
        /// 
        ///  
        /// true if redo succeeds, false otherwise (including when the stack is empty) 
        /// 
        public bool Redo() 
        {
            UndoManager undoManager = UndoManager.GetUndoManager(this);
            if (undoManager != null && undoManager.RedoCount > 0)
            { 
                this.TextEditor.Redo();
                return true; 
            } 

            return false; 
        }

        /// 
        /// Lock the most recently added undo unit, preventing it from being reopened. 
        /// 
        ///  
        /// This method is intended to be called by an application when a non-text undo unit is added 
        /// to the application's own undo stack on top of a text undo unit.  By calling this method,
        /// the next text undo unit will not attempt to merge with the previous one. 
        /// 
        public void LockCurrentUndoUnit()
        {
            UndoManager undoManager = UndoManager.GetUndoManager(this); 
            if (undoManager != null)
            { 
                // find the deepest open unit, and lock the last unit added to it 
                IParentUndoUnit openedUnit = undoManager.OpenedUnit;
                if (openedUnit != null) 
                {
                    while (openedUnit.OpenedUnit != null)
                    {
                        openedUnit = openedUnit.OpenedUnit; 
                    }
                    if (openedUnit.LastUnit is IParentUndoUnit) 
                    { 
                        openedUnit.OnNextAdd();
                    } 
                }
                else if (undoManager.LastUnit is IParentUndoUnit)
                {
                    ((IParentUndoUnit)undoManager.LastUnit).OnNextAdd();  // 
                }
            } 
        } 

        //......................................................... 
        //
        //  Change Notifications
        //
        //......................................................... 

        ///  
        /// Begins a change block. 
        /// 
        public void BeginChange() 
        {
            this.TextEditor.Selection.BeginChange();
        }
 
        /// 
        /// Ends a change block. 
        ///  
        public void EndChange()
        { 
            if (this.TextEditor.Selection.ChangeBlockLevel == 0)
            {
                throw new InvalidOperationException(SR.Get(SRID.TextBoxBase_UnmatchedEndChange));
            } 

            this.TextEditor.Selection.EndChange(); 
        } 

        ///  
        /// Creates and returns a change block
        /// 
        /// IDisposable
        public IDisposable DeclareChangeBlock() 
        {
            return this.TextEditor.Selection.DeclareChangeBlock(); 
        } 

        #endregion Public Methods 

        //-----------------------------------------------------
        //
        //  Public Properties 
        //
        //------------------------------------------------------ 
 
        #region Public Properties
 
        /// 
        /// Alias for TextEditor.IsReadOnly dependency property.
        /// Enables editing within this textbox.
        ///  
        public static readonly DependencyProperty IsReadOnlyProperty =
                TextEditor.IsReadOnlyProperty.AddOwner( 
                    typeof(TextBoxBase), 
                    new FrameworkPropertyMetadata(
                        false, 
                        FrameworkPropertyMetadataOptions.Inherits,
                        new PropertyChangedCallback(OnVisualStatePropertyChanged)));

        ///  
        /// Whether or not the Textbox is read-only
        ///  
        public bool IsReadOnly 
        {
            get { return (bool) GetValue(TextEditor.IsReadOnlyProperty); } 
            set { SetValue(TextEditor.IsReadOnlyProperty, value); }
        }

        ///  
        /// DependencyProperty backing IsReadOnlyCaretVisible.
        ///  
        public static readonly DependencyProperty IsReadOnlyCaretVisibleProperty = 
            DependencyProperty.Register("IsReadOnlyCaretVisible",
                typeof(bool), 
                typeof(TextBoxBase),
                new FrameworkPropertyMetadata(false, new PropertyChangedCallback(OnIsReadOnlyCaretVisiblePropertyChanged)));

        ///  
        /// Whether or not the caret is visible when the textbox is read-only.
        ///  
        public bool IsReadOnlyCaretVisible 
        {
            get { return (bool)GetValue(IsReadOnlyCaretVisibleProperty); } 
            set { SetValue(IsReadOnlyCaretVisibleProperty, value); }
        }

        ///  
        /// Indicates if VK_Return character is accepted as a normal new-line character, if it is true, it will insert a new-line to the textbox
        /// or other editable controls, if it is false, it will not insert a new-line character to the controls's content, but just 
        /// activates the control with focus. 
        ///
        /// Default: true. 
        /// TextBox and/or RichTextBox need to set this value appropriately
        /// 
        public static readonly DependencyProperty AcceptsReturnProperty =
                KeyboardNavigation.AcceptsReturnProperty.AddOwner(typeof(TextBoxBase)); 

        ///  
        /// Whether or not the Textbox accepts newlines 
        /// 
        public bool AcceptsReturn 
        {
            get { return (bool) GetValue(AcceptsReturnProperty); }
            set { SetValue(AcceptsReturnProperty, value); }
        } 

        ///  
        /// Indicates if VK_TAB character is accepted as a normal tab char, if it is true, it will insert a tab character to the control's content, 
        /// otherwise, it will not insert new tab to the content of control, instead, it will navigate the focus to the next IsTabStop control.
        /// 
        /// Default: false.
        ///
        /// TextBox and RichTextBox need to set the value appropriately.
        ///  
        public static readonly DependencyProperty AcceptsTabProperty =
                DependencyProperty.Register( 
                        "AcceptsTab", // Property name 
                        typeof(bool), // Property type
                        typeof(TextBoxBase), // Property owner 
                        new FrameworkPropertyMetadata(false /*default value*/));

        /// 
        /// Whether or not the Textbox accepts tabs 
        /// 
        public bool AcceptsTab 
        { 
            get { return (bool) GetValue(AcceptsTabProperty); }
            set { SetValue(AcceptsTabProperty, value); } 
        }

        /// 
        /// Access to all spelling options. 
        /// 
        public SpellCheck SpellCheck 
        { 
            get
            { 
                return new SpellCheck(this);
            }
        }
 
        /// 
        /// Exposes ScrollViewer's HorizontalScrollBarVisibility property 
        /// Default: Hidden 
        /// 
        public static readonly DependencyProperty HorizontalScrollBarVisibilityProperty = 
                ScrollViewer.HorizontalScrollBarVisibilityProperty.AddOwner(
                        typeof(TextBoxBase),
                        new FrameworkPropertyMetadata(
                                ScrollBarVisibility.Hidden, 
                                new PropertyChangedCallback(OnScrollViewerPropertyChanged))); // PropertyChangedCallback
 
        ///  
        /// Whether or not a horizontal scrollbar is shown
        ///  
        public ScrollBarVisibility HorizontalScrollBarVisibility
        {
            get { return (ScrollBarVisibility) GetValue(HorizontalScrollBarVisibilityProperty); }
            set { SetValue(HorizontalScrollBarVisibilityProperty, value); } 
        }
 
        ///  
        /// Exposes ScrollViewer's VerticalScrollBarVisibility property
        /// Default: Hidden 
        /// 
        public static readonly DependencyProperty VerticalScrollBarVisibilityProperty =
                ScrollViewer.VerticalScrollBarVisibilityProperty.AddOwner(
                        typeof(TextBoxBase), 
                        new FrameworkPropertyMetadata(ScrollBarVisibility.Hidden,
                        new PropertyChangedCallback(OnScrollViewerPropertyChanged))); 
 
        /// 
        /// Whether or not a vertical scrollbar is shown 
        /// 
        public ScrollBarVisibility VerticalScrollBarVisibility
        {
            get { return (ScrollBarVisibility) GetValue(VerticalScrollBarVisibilityProperty); } 
            set { SetValue(VerticalScrollBarVisibilityProperty, value); }
        } 
 
        /// 
        /// Horizontal size of scrollable content; 0.0 if TextBox is non-scrolling 
        /// 
        public double ExtentWidth
        {
            get 
            {
                return (this.ScrollViewer != null) ? this.ScrollViewer.ExtentWidth : 0.0; 
            } 
        }
 
        /// 
        /// Vertical size of scrollable content; 0.0 if TextBox is non-scrolling
        /// 
        public double ExtentHeight 
        {
            get 
            { 
                return (this.ScrollViewer != null) ? this.ScrollViewer.ExtentHeight : 0.0;
            } 
        }

        /// 
        /// Horizontal size of scroll area; 0.0 if TextBox is non-scrolling 
        /// 
        public double ViewportWidth 
        { 
            get
            { 
                return (this.ScrollViewer != null) ? this.ScrollViewer.ViewportWidth : 0.0;
            }
        }
 
        /// 
        /// Vertical size of scroll area; 0.0 if TextBox is non-scrolling 
        ///  
        public double ViewportHeight
        { 
            get
            {
                return (this.ScrollViewer != null) ? this.ScrollViewer.ViewportHeight : 0.0;
            } 
        }
 
 
        /// 
        /// Actual HorizontalOffset contains the ScrollViewer's current horizontal offset. 
        /// This is a computed value, depending on the state of ScrollViewer, its Viewport, Extent
        /// and previous scrolling commands.
        /// 
        public double HorizontalOffset 
        {
            get 
            { 
                return (this.ScrollViewer != null) ? this.ScrollViewer.HorizontalOffset : 0.0;
            } 
        }

        /// 
        /// Actual VerticalOffset contains the ScrollViewer's current vertical offset. 
        /// This is a computed value, depending on the state of ScrollViewer, its Viewport, Extent
        /// and previous scrolling commands. 
        ///  
        public double VerticalOffset
        { 
            get
            {
                return (this.ScrollViewer != null) ? this.ScrollViewer.VerticalOffset : 0.0;
            } 
        }
 
        ///  
        /// Can the most recent action on the text box be undone?  Since we will frequently be called
        /// during a TextChanged event when the undo stack hasn't yet been modified to reflect the 
        /// pending change, just looking at the UndoCount isn't sufficient.  TextEditor caches
        /// the pending undo action with us so we can refer to it now.
        /// 
        public bool CanUndo 
        {
            get 
            { 
                UndoManager undoManager;
 
                undoManager = UndoManager.GetUndoManager(this);
                if (undoManager != null && (_pendingUndoAction != UndoAction.Clear &&
                    (undoManager.UndoCount > undoManager.MinUndoStackCount ||
                    (undoManager.State != UndoState.Undo && _pendingUndoAction == UndoAction.Create)))) 
                {
                    return true; 
                } 
                else
                { 
                    return false;
                }
            }
        } 

        ///  
        /// Can the most recent undone action on the text box be redone? 
        /// 
        public bool CanRedo 
        {
            get
            {
                UndoManager undoManager; 

                undoManager = UndoManager.GetUndoManager(this); 
                if (undoManager != null && (_pendingUndoAction != UndoAction.Clear && 
                    (undoManager.RedoCount > 0 ||
                    (undoManager.State == UndoState.Undo && _pendingUndoAction == UndoAction.Create)))) 
                {
                    return true;
                }
                else 
                {
                    return false; 
                } 
            }
        } 

        /// 
        /// Enables or disabled undo support on this Control.
        ///  
        /// 
        /// Defaults to true. 
        /// 
        /// The control's undo record is cleared when this property transitions
        /// to false. 
        /// 
        public static readonly DependencyProperty IsUndoEnabledProperty =
            DependencyProperty.Register("IsUndoEnabled", typeof(bool), typeof(TextBoxBase),
            new FrameworkPropertyMetadata(true, new PropertyChangedCallback(OnIsUndoEnabledChanged))); 

        ///  
        /// Enables or disabled undo support on this Control. 
        /// 
        ///  
        /// Defaults to true.
        ///
        /// The control's undo record is cleared when this property transitions
        /// to false. 
        /// 
        public bool IsUndoEnabled 
        { 
            get
            { 
                return (bool)GetValue(IsUndoEnabledProperty);
            }

            set 
            {
                SetValue(IsUndoEnabledProperty, value); 
            } 
        }
 
        /// 
        /// Sets the number of actions stored in the undo queue.
        /// 
        ///  
        /// The value must be >= -1.
        /// 
        /// -1 sets the storage to "infinite", limited only by available memory. 
        /// 0 disables undo.
        /// 
        /// Setting any value will clear the existing queue.
        ///
        /// An InvalidOperationException is thrown if the value is set inside to
        /// context of a BeginChange/EndChange pair while IsUndoEnabled is true 
        /// (ie, you may not set this property while an undo unit is open).
        /// 
        /// The default value is -1. 
        /// 
        public static readonly DependencyProperty UndoLimitProperty = 
            DependencyProperty.Register("UndoLimit", typeof(int), typeof(TextBoxBase),
            new FrameworkPropertyMetadata(UndoManager.UndoLimitDefaultValue, new PropertyChangedCallback(OnUndoLimitChanged)),
            new ValidateValueCallback(UndoLimitValidateValue));
 
        /// 
        ///  
        ///  
        public int UndoLimit
        { 
            get
            {
                return (int)GetValue(UndoLimitProperty);
            } 

            set 
            { 
                SetValue(UndoLimitProperty, value);
            } 
        }

        /// 
        /// The DependencyID for the AutoWordSelection property. 
        /// Flags:              Can be used in style rules
        /// Default Value:      false 
        ///  
        public static readonly DependencyProperty AutoWordSelectionProperty =
            DependencyProperty.Register( 
                "AutoWordSelection", // Property name
                typeof(bool), // Property type
                typeof(TextBoxBase), // Property owner
                new FrameworkPropertyMetadata(false)); 

        ///  
        /// Whether or not dragging with the mouse automatically selects words 
        /// 
        public bool AutoWordSelection 
        {
            get
            {
                return (bool)GetValue(AutoWordSelectionProperty); 
            }
 
            set 
            {
                SetValue(AutoWordSelectionProperty, value); 
            }
        }

        ///  
        /// Brush used for selection fill.
        ///  
        ///  
        /// If set to null, the selection will not be rendered.
        ///  
        public static readonly DependencyProperty SelectionBrushProperty =
            DependencyProperty.Register("SelectionBrush", typeof(Brush), typeof(TextBoxBase),
                new FrameworkPropertyMetadata(GetDefaultSelectionBrush(), new PropertyChangedCallback(UpdateCaretElement)));
 
        /// 
        ///  
        ///  
        public Brush SelectionBrush
        { 
            get { return (Brush)GetValue(SelectionBrushProperty); }
            set { SetValue(SelectionBrushProperty, value); }
        }
 
        /// 
        /// Opacity used for drawing the selection. 
        ///  
        /// 
        /// The opacity of SelectionBrush will also be respected (multiplied with this one during render). 
        /// 
        public static readonly DependencyProperty SelectionOpacityProperty =
            DependencyProperty.Register("SelectionOpacity", typeof(double), typeof(TextBoxBase),
                new FrameworkPropertyMetadata(0.4, new PropertyChangedCallback(UpdateCaretElement))); 

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

        ///  
        /// Brush used for the caret. 
        /// 
        ///  
        /// If set to null, the default behavior of setting the caret color to the inverse of the background color will be used.
        /// 
        public static readonly DependencyProperty CaretBrushProperty =
            DependencyProperty.Register("CaretBrush", typeof(Brush), typeof(TextBoxBase), 
                new FrameworkPropertyMetadata(null, new PropertyChangedCallback(UpdateCaretElement)));
 
        ///  
        /// 
        ///  
        public Brush CaretBrush
        {
            get { return (Brush)GetValue(CaretBrushProperty); }
            set { SetValue(CaretBrushProperty, value); } 
        }
 
        #endregion Public Properties 

        //----------------------------------------------------- 
        //
        //  Public Events
        //
        //----------------------------------------------------- 

        #region Public Events 
 
        /// 
        /// Event for "Text has changed" 
        /// 
        public static readonly RoutedEvent TextChangedEvent = EventManager.RegisterRoutedEvent(
            "TextChanged", // Event name
            RoutingStrategy.Bubble, // 
            typeof(TextChangedEventHandler), //
            typeof(TextBoxBase)); // 
 
        /// 
        /// Event fired from this text box when its inner content 
        /// has been changed.
        /// 
        /// 
        /// The event itself is defined on TextEditor. 
        /// 
        public event TextChangedEventHandler TextChanged 
        { 
            add
            { 
                AddHandler(TextChangedEvent, value);
            }

            remove 
            {
                RemoveHandler(TextChangedEvent, value); 
            } 
        }
 
        /// 
        /// Event for "Selection has changed"
        /// 
        public static readonly RoutedEvent SelectionChangedEvent = EventManager.RegisterRoutedEvent( 
            "SelectionChanged", // Event name
            RoutingStrategy.Bubble, // 
            typeof(RoutedEventHandler), // 
            typeof(TextBoxBase)); //
 
        /// 
        /// Event fired from this text box when its selection has been changed.
        /// 
        public event RoutedEventHandler SelectionChanged 
        {
            add 
            { 
                AddHandler(SelectionChangedEvent, value);
            } 

            remove
            {
                RemoveHandler(SelectionChangedEvent, value); 
            }
        } 
 
        #endregion Public Events
 
        //-----------------------------------------------------
        //
        //  Protected Methods
        // 
        //------------------------------------------------------
 
        #region Protected Methods 

        internal override void ChangeVisualState(bool useTransitions) 
        {
            // See ButtonBase.ChangeVisualState.
            // This method should be exactly like it, except we have a ReadOnly state instead of Pressed
            if (!IsEnabled) 
            {
                VisualStateManager.GoToState(this, VisualStates.StateDisabled, useTransitions); 
            } 
            else if (IsReadOnly)
            { 
                VisualStateManager.GoToState(this, VisualStates.StateReadOnly, useTransitions);
            }
            else if (IsMouseOver)
            { 
                VisualStateManager.GoToState(this, VisualStates.StateMouseOver, useTransitions);
            } 
            else 
            {
                VisualStateManager.GoToState(this, VisualStates.StateNormal, useTransitions); 
            }

            if (IsKeyboardFocused)
            { 
                VisualStateManager.GoToState(this, VisualStates.StateFocused, useTransitions);
            } 
            else 
            {
                VisualStateManager.GoToState(this, VisualStates.StateUnfocused, useTransitions); 
            }

            base.ChangeVisualState(useTransitions);
        } 

        ///  
        /// Called when content in this Control changes. 
        /// Raises the TextChanged event.
        ///  
        /// 
        protected virtual void OnTextChanged(TextChangedEventArgs e)
        {
            RaiseEvent(e); 
        }
 
        ///  
        /// Called when the caret or selection changes position.
        /// Raises the SelectionChanged event. 
        /// 
        /// 
        protected virtual void OnSelectionChanged(RoutedEventArgs e)
        { 
            RaiseEvent(e);
        } 
 
        /// 
        /// Template has changed 
        /// 
        /// 
        /// 
        ///  
        /// 
        protected override void OnTemplateChanged(ControlTemplate oldTemplate, ControlTemplate newTemplate) 
        { 
            base.OnTemplateChanged(oldTemplate, newTemplate);
 
            if (oldTemplate!=null && newTemplate!= null && oldTemplate.VisualTree != newTemplate.VisualTree)
            {
                DetachFromVisualTree();
            } 
        }
 
        ///  
        /// ScrollViewer marks all mouse wheel events as handled, even if no scrolling occurs.  This means that
        /// when mousewheeling through a document, if the cursor happens to land on a textbox, scrolling will 
        /// stop when the textbox reaches the end of its content.  We want the scroll event to continue to the
        /// outer control in such a case so that outer control continues scrolling.
        /// 
        /// MouseWheelEventArgs 
        protected override void OnMouseWheel(MouseWheelEventArgs e)
        { 
            if (e == null) 
            {
                throw new ArgumentNullException("e"); 
            }

            if (this.ScrollViewer != null)
            { 
                // Only raise the event on ScrollViewer if we're actually going to scroll
                if ((e.Delta > 0 && VerticalOffset != 0) /* scrolling up */ || (e.Delta < 0 && VerticalOffset < this.ScrollViewer.ScrollableHeight) /* scrolling down */ ) 
                { 
                    Invariant.Assert(this.RenderScope is IScrollInfo);
                    if (e.Delta > 0) 
                    {
                        ((IScrollInfo)this.RenderScope).MouseWheelUp();
                    }
                    else 
                    {
                        ((IScrollInfo)this.RenderScope).MouseWheelDown(); 
                    } 
                    e.Handled = true;
                } 
            }
            base.OnMouseWheel(e);
        }
 
        /// 
        ///     Virtual method reporting a key was pressed 
        ///  
        protected override void OnPreviewKeyDown(KeyEventArgs e)
        { 
            base.OnKeyDown(e);

            if (e.Handled)
            { 
                return;
            } 
 
            if (_textEditor != null)
            { 
                _textEditor.OnPreviewKeyDown(e);
            }
        }
 
        /// 
        ///     Virtual method reporting a key was pressed 
        ///  
        protected override void OnKeyDown(KeyEventArgs e)
        { 
            base.OnKeyDown(e);

            if (e.Handled)
            { 
                return;
            } 
 
            if (_textEditor != null)
            { 
                _textEditor.OnKeyDown(e);
            }
        }
 
        /// 
        ///     Virtual method reporting a key was released 
        ///  
        protected override void OnKeyUp(KeyEventArgs e)
        { 
            base.OnKeyUp(e);

            if (e.Handled)
            { 
                return;
            } 
 
            if (_textEditor != null)
            { 
                _textEditor.OnKeyUp(e);
            }
        }
 
        /// 
        ///     Virtual method reporting text composition 
        ///  
        protected override void OnTextInput(TextCompositionEventArgs e)
        { 
            base.OnTextInput(e);

            if (e.Handled)
            { 
                return;
            } 
 
            if (_textEditor != null)
            { 
                _textEditor.OnTextInput(e);
            }
        }
 
        /// 
        ///     Virtual method reporting the mouse button was pressed 
        ///  
        protected override void OnMouseDown(MouseButtonEventArgs e)
        { 
            base.OnMouseDown(e);

            if (e.Handled)
            { 
                return;
            } 
 
            if (_textEditor != null)
            { 
                _textEditor.OnMouseDown(e);
            }
        }
 
        /// 
        ///     Virtual method reporting a mouse move 
        ///  
        protected override void OnMouseMove(MouseEventArgs e)
        { 
            base.OnMouseMove(e);

            if (e.Handled)
            { 
                return;
            } 
 
            if (_textEditor != null)
            { 
                _textEditor.OnMouseMove(e);
            }
        }
 
        /// 
        ///     Virtual method reporting the mouse button was released 
        ///  
        protected override void OnMouseUp(MouseButtonEventArgs e)
        { 
            base.OnMouseUp(e);

            if (e.Handled)
            { 
                return;
            } 
 
            if (_textEditor != null)
            { 
                _textEditor.OnMouseUp(e);
            }
        }
 
        /// 
        ///     Virtual method reporting the cursor to display was requested 
        ///  
        protected override void OnQueryCursor(QueryCursorEventArgs e)
        { 
            base.OnQueryCursor(e);

            if (e.Handled)
            { 
                return;
            } 
 
            if (_textEditor != null)
            { 
                _textEditor.OnQueryCursor(e);
            }
        }
 
        /// 
        ///     Virtual method reporting the query continue drag is going to happen 
        ///  
        protected override void OnQueryContinueDrag(QueryContinueDragEventArgs e)
        { 
            base.OnQueryContinueDrag(e);

            if (e.Handled)
            { 
                return;
            } 
 
            if (_textEditor != null)
            { 
                _textEditor.OnQueryContinueDrag(e);
            }
        }
 
        /// 
        ///     Virtual method reporting the give feedback is going to happen 
        ///  
        protected override void OnGiveFeedback(GiveFeedbackEventArgs e)
        { 
            base.OnGiveFeedback(e);

            if (e.Handled)
            { 
                return;
            } 
 
            if (_textEditor != null)
            { 
                _textEditor.OnGiveFeedback(e);
            }
        }
 
        /// 
        ///     Virtual method reporting the drag enter is going to happen 
        ///  
        protected override void OnDragEnter(DragEventArgs e)
        { 
            base.OnDragEnter(e);

            if (e.Handled)
            { 
                return;
            } 
 
            if (_textEditor != null)
            { 
                _textEditor.OnDragEnter(e);
            }
        }
 
        /// 
        ///     Virtual method reporting the drag over is going to happen 
        ///  
        protected override void OnDragOver(DragEventArgs e)
        { 
            base.OnDragOver(e);

            if (e.Handled)
            { 
                return;
            } 
 
            if (_textEditor != null)
            { 
                _textEditor.OnDragOver(e);
            }
        }
 
        /// 
        ///     Virtual method reporting the drag leave is going to happen 
        ///  
        protected override void OnDragLeave(DragEventArgs e)
        { 
            base.OnDragLeave(e);

            if (e.Handled)
            { 
                return;
            } 
 
            if (_textEditor != null)
            { 
                _textEditor.OnDragLeave(e);
            }
        }
 
        /// 
        ///     Virtual method reporting the drag enter is going to happen 
        ///  
        protected override void OnDrop(DragEventArgs e)
        { 
            base.OnDrop(e);

            if (e.Handled)
            { 
                return;
            } 
 
            if (_textEditor != null)
            { 
                _textEditor.OnDrop(e);
            }
        }
 
        /// 
        ///     Called when ContextMenuOpening is raised on this element. 
        ///  
        /// Event arguments
        protected override void OnContextMenuOpening(ContextMenuEventArgs e) 
        {
            base.OnContextMenuOpening(e);

            if (e.Handled) 
            {
                return; 
            } 

            if (_textEditor != null) 
            {
                _textEditor.OnContextMenuOpening(e);
            }
        } 

        ///  
        ///     Virtual method reporting that the keyboard is focused on this element 
        /// 
        protected override void OnGotKeyboardFocus(KeyboardFocusChangedEventArgs e) 
        {
            base.OnGotKeyboardFocus(e);

            if (e.Handled) 
            {
                return; 
            } 

            if (_textEditor != null) 
            {
                _textEditor.OnGotKeyboardFocus(e);
            }
        } 

        ///  
        ///     Virtual method reporting that the keyboard is no longer focusekeyboard is no longer focuseed 
        /// 
        protected override void OnLostKeyboardFocus(KeyboardFocusChangedEventArgs e) 
        {
            base.OnLostKeyboardFocus(e);

            if (e.Handled) 
            {
                return; 
            } 

            if (_textEditor != null) 
            {
                _textEditor.OnLostKeyboardFocus(e);
            }
        } 

        ///  
        ///     This method is invoked when the IsFocused property changes to false 
        /// 
        /// RoutedEventArgs 
        protected override void OnLostFocus(RoutedEventArgs e)
        {
            base.OnLostFocus(e);
 
            if (e.Handled)
            { 
                return; 
            }
 
            if (_textEditor != null)
            {
                _textEditor.OnLostFocus(e);
            } 
        }
 
        // Allocates the initial render scope for this control. 
        internal abstract FrameworkElement CreateRenderScope();
 
        /// 
        /// Handler for TextContainer.Changed event.  Raises the TextChanged event on UiScope.
        /// for editing controls.
        ///  
        /// 
        /// sender 
        ///  
        /// 
        /// event args 
        /// 
        internal virtual void OnTextContainerChanged(object sender, TextContainerChangedEventArgs e)
        {
            // If only properties on the text changed, don't fire a content change event. 
            // This can happen even in a plain text TextBox if we switch logical trees.
            if (!e.HasContentAddedOrRemoved && !e.HasLocalPropertyValueChange) 
            { 
                return;
            } 

            UndoManager undoManager = UndoManager.GetUndoManager(this);

            UndoAction undoAction; 
            if (undoManager != null) // Will be null for controls like PasswordBox that don't use undo.
            { 
                if (_textEditor.UndoState == UndoState.Redo) 
                {
                    undoAction = UndoAction.Redo; 
                }
                else if (_textEditor.UndoState == UndoState.Undo)
                {
                    undoAction = UndoAction.Undo; 
                }
                else if (undoManager.OpenedUnit == null) 
                { 
                    undoAction = UndoAction.Clear;
                } 
                else if (undoManager.LastReopenedUnit == undoManager.OpenedUnit)
                {
                    undoAction = UndoAction.Merge;
                } 
                else
                { 
                    undoAction = UndoAction.Create; 
                }
            } 
            else
            {
                undoAction = UndoAction.Create;
            } 

            // The undo stack hasn't yet been modified by this change, so CanUndo will not 
            // necessarily yield the correct result if queried during the TextChange event. 
            // Store the undo action in the uiScope, so CanUndo can
            // reference it to provide the correct result. 
            _pendingUndoAction = undoAction;
            try
            {
                OnTextChanged(new TextChangedEventArgs(TextChangedEvent, undoAction, new ReadOnlyCollection(e.Changes.Values))); 
            }
            finally 
            { 
                _pendingUndoAction = UndoAction.None;
            } 
        }

        #endregion Protected Methods
 
        //-----------------------------------------------------
        // 
        //  Internal Methods 
        //
        //------------------------------------------------------ 

        #region Internal Methods

        // Attaches this control to a new TextContainer. 
        internal void InitializeTextContainer(TextContainer textContainer)
        { 
            Invariant.Assert(textContainer != null); 
            Invariant.Assert(textContainer.TextSelection == null);
 
            // Uninitialize previous TextEditor
            if (_textContainer != null)
            {
                Invariant.Assert(_textEditor != null); 
                Invariant.Assert(_textEditor.TextContainer == _textContainer);
                Invariant.Assert(_textEditor.TextContainer.TextSelection == _textEditor.Selection); 
 
                // Detach existing editor from VisualTree
                DetachFromVisualTree(); 

                // Discard TextEditor - must release text container
                _textEditor.OnDetach();
            } 

            // Save text container 
            _textContainer = textContainer; 
            _textContainer.Changed += new TextContainerChangedEventHandler(OnTextContainerChanged);
 
            // Create a text editor, initialize undo manager for it, and link it to text container
            _textEditor = new TextEditor(_textContainer, this, true);
            _textEditor.Selection.Changed += new EventHandler(OnSelectionChangedInternal);
 
            // Init a default undo limit.
            UndoManager undoManager = UndoManager.GetUndoManager(this); 
            if (undoManager != null) 
            {
                undoManager.UndoLimit = this.UndoLimit; 
            }

            // Delay raising automation events until the automation subsystem is activated by a client.
            // ISSUE-2005/01/23-vsmirnov - Adding an event listener to AutomationProvider apparently 
            // causes memory leaks because TextBoxBase is never released. I comment it out for now just
            // to fix the build break (perf DRT failure). Need to find a right fix later. 
            // AutomationProvider.Activated += new AutomationActivatedEventHandler(OnAutomationActivated); 
        }
 
        /// 
        /// Returns a TextPosition matching the specified pixel coordinates.
        /// 
        ///  
        /// Pixel coordinate to hittest with.
        /// point is expected to be in the coordinate space of this TextBox. 
        ///  
        /// 
        /// If true, heuristics are applied to find the closest character 
        /// position to point, even if point does not intersect any character
        /// bounding box.
        /// 
        ///  
        /// A TextPosition and its orientation matching the specified pixel.
        /// May return null if snapToText is false and point does not fall 
        /// within any character bounding box. 
        /// 
        internal TextPointer GetTextPositionFromPointInternal(Point point, bool snapToText) 
        {
            TextPointer position;

            // Transform to content coordinates. 
            GeneralTransform transform = this.TransformToDescendant(this.RenderScope);
 
            if (transform != null) 
            {
                transform.TryTransform(point, out point); 
            }

            if (TextEditor.GetTextView(this.RenderScope).Validate(point))
            { 
                position = (TextPointer)TextEditor.GetTextView(this.RenderScope).GetTextPositionFromPoint(point, snapToText);
            } 
            else 
            {
                position = snapToText ? this.TextContainer.Start : null; 
            }

            return position;
        } 

        ///  
        /// Retrieves the height and offset, in pixels, of the edge of 
        /// the object/character represented by position.
        ///  
        /// 
        /// Position of an object/character.
        /// 
        ///  
        /// Receives the bounding box.
        ///  
        ///  
        /// Returns false if no layout is available.  In this case rect will be set empty.
        ///  
        /// 
        /// Coordinates of the return value are relative to this TextBox.
        ///
        /// Rect.Width is always 0. 
        ///
        /// If the content is empty, then this method returns the expected 
        /// height of a character, if placed at the specified position. 
        ///
        internal bool GetRectangleFromTextPosition(TextPointer position, out Rect rect) 
        {
            Point offset;

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

            // Validate layout information on TextView 
            if (TextEditor.GetTextView(this.RenderScope).Validate(position))
            {
                // Get the rect in local content coordinates.
                rect = TextEditor.GetTextView(this.RenderScope).GetRectangleFromTextPosition(position); 

                // Transform to RichTextBox control coordinates. 
                offset = new Point(0, 0); 
                GeneralTransform transform = this.TransformToDescendant(this.RenderScope);
                if (transform != null) 
                {
                    transform.TryTransform(offset, out offset);
                }
                rect.X -= offset.X; 
                rect.Y -= offset.Y;
            } 
            else 
            {
                rect = Rect.Empty; 
            }

            return rect != Rect.Empty;
        } 

        ///  
        /// Detaches the editor from old visual tree and attaches it to a new one 
        /// 
        internal virtual void AttachToVisualTree() 
        {
            DetachFromVisualTree();

            // Walk the visual tree to find our Text element 
            SetRenderScopeToContentHost();
 
            // Set properties on ScrollViewer 
            // Note that this.ScrollViewer will walk the tree from current TextEditor's render scope up to its ui scope.
            if (this.ScrollViewer != null) 
            {
                this.ScrollViewer.ScrollChanged += new ScrollChangedEventHandler(OnScrollChanged);

                // 
                SetValue(TextEditor.PageHeightProperty, this.ScrollViewer.ViewportHeight);
 
                // Need to make scroll viewer non-focusable, otherwise it will eat keyboard navigation from editor 
                this.ScrollViewer.Focusable = false;
 
                // Prevent mouse wheel scrolling from breaking when there's no more content in the direction of the scroll
                this.ScrollViewer.HandlesMouseWheelScrolling = false;

                if (this.ScrollViewer.Background == null) 
                {
                    // prevent hit-testing through padding 
                    this.ScrollViewer.Background = Brushes.Transparent; 
                }
 
                OnScrollViewerPropertyChanged(this, new DependencyPropertyChangedEventArgs(ScrollViewer.HorizontalScrollBarVisibilityProperty, null /* old value */, this.GetValue(HorizontalScrollBarVisibilityProperty)));
                OnScrollViewerPropertyChanged(this, new DependencyPropertyChangedEventArgs(ScrollViewer.VerticalScrollBarVisibilityProperty, null /* old value */, this.GetValue(VerticalScrollBarVisibilityProperty)));
                OnScrollViewerPropertyChanged(this, new DependencyPropertyChangedEventArgs(ScrollViewer.PaddingProperty, null /* old value */, this.GetValue(PaddingProperty)));
            } 
            else
            { 
                ClearValue(TextEditor.PageHeightProperty); 
            }
        } 

        // Do the work of line up.  Can be overridden by subclass to implement true line up.
        internal virtual void DoLineUp()
        { 
            if (this.ScrollViewer != null)
            { 
                this.ScrollViewer.LineUp(); 
            }
        } 

        // Do the work of line down.  Can be overridden by subclass to implement true line down.
        internal virtual void DoLineDown()
        { 
            if (this.ScrollViewer != null)
            { 
                this.ScrollViewer.LineDown(); 
            }
        } 

        /// 
        /// When RenderScope is FlowDocumentView, events can bypass our nested ScrollViewer.
        /// We want to make sure that ScrollViewer-- and any other elements in our style-- 
        /// always gets a `crack at mouse events.
        ///  
        internal override void AddToEventRouteCore(EventRoute route, RoutedEventArgs args) 
        {
            base.AddToEventRouteCore(route, args); 

            // Walk up the tree from the RenderScope to this, adding each element to the route
            Visual visual = this.RenderScope;
            while (visual != this && visual != null) 
            {
                if (visual is UIElement) 
                { 
                    ((UIElement)visual).AddToEventRoute(route, args);
                } 
                visual = VisualTreeHelper.GetParent(visual) as Visual;
            }
        }
 

        ///  
        /// Helper method to update the IsUndoEnabled flag within UndoManager 
        /// attached to the TextBox.
        ///  
        /// 
        /// New Value of IsUndoEnabled flag.
        /// 
        internal void ChangeUndoEnabled(bool value) 
        {
            // 
 

            if (this.TextSelectionInternal.ChangeBlockLevel > 0) 
            {
                throw new InvalidOperationException(SR.Get(SRID.TextBoxBase_CantSetIsUndoEnabledInsideChangeBlock));
            }
 
            UndoManager undoManager = UndoManager.GetUndoManager(this);
            if (undoManager != null) 
            { 

                if (!value && undoManager.IsEnabled) 
                {
                    undoManager.Clear();
                }
                undoManager.IsEnabled = value; 
            }
        } 
 
        /// 
        /// Helper method to update the UndoLimit in UndoManager 
        /// attached to the TextBox.
        /// 
        /// 
        /// New Value of UndoLimit. 
        /// 
        internal void ChangeUndoLimit(object value) 
        { 
            UndoManager undoManager = UndoManager.GetUndoManager(this);
            if (undoManager != null) 
            {
                if (undoManager.OpenedUnit != null)
                {
                    // 

                    throw new InvalidOperationException(SR.Get(SRID.TextBoxBase_CantSetIsUndoEnabledInsideChangeBlock)); 
                } 

                int limit; 

                if (value == DependencyProperty.UnsetValue)
                {
                    limit = UndoManager.UndoLimitDefaultValue; 
                }
                else 
                { 
                    limit = (int)value;
                } 

                undoManager.UndoLimit = limit;
            }
 
        }
 
        #endregion Internal Methods 

        //------------------------------------------------------ 
        //
        //  Internal Properties
        //
        //----------------------------------------------------- 

        #region Internal Properties 
 
        /// 
        /// Access to the ScrollViewer in textbox style 
        /// 
        internal ScrollViewer ScrollViewer
        {
            get 
            {
                if (_scrollViewer == null) 
                { 
                    if (_textEditor != null)
                    { 
                        // TextEditor's _Scroller property finds a ScrollViewer found
                        // by a tree walk from the editor's render scope within ui scope.
                        _scrollViewer = _textEditor._Scroller as ScrollViewer;
                    } 
                }
                return _scrollViewer; 
            } 
        }
 
        /// 
        /// Text Selection (readonly)
        /// 
        internal TextSelection TextSelectionInternal 
        {
            get 
            { 
                return (TextSelection)_textEditor.Selection;
            } 
        }

        /// 
        /// A TextContainer covering the TextBox's inner content. 
        /// Never returns null, throws SystemException if unavailable.
        ///  
        internal TextContainer TextContainer 
        {
            get 
            {
                return _textContainer;
            }
        } 

        ///  
        /// readonly access to internal content control 
        /// 
        internal FrameworkElement RenderScope 
        {
            get
            {
                return _renderScope; 
            }
        } 
 
        // Expose _pendingUndoAction for DrtEditing.exe, via reflection.
        internal UndoAction PendingUndoAction 
        {
            get
            {
                return _pendingUndoAction; 
            }
 
            set 
            {
                _pendingUndoAction = value; 
            }
        }

        // TextEditor attached to this control. 
        internal TextEditor TextEditor
        { 
            get 
            {
                return _textEditor; 
            }
        }

        // True if style has been applied to the control and 
        // ContentHostTemplateName was successfully found in it.
        internal bool IsContentHostAvailable 
        { 
            get
            { 
                return _textBoxContentHost != null;
            }
        }
 
        #endregion Internal Properties
 
        //------------------------------------------------------ 
        //
        //  Private Methods 
        //
        //-----------------------------------------------------

        #region Private Methods 

        ///  
        /// Clear our layout-specific data, and detach our current renderScope from our text editor. 
        /// 
        private void DetachFromVisualTree() 
        {
            if (_textEditor != null)
            {
                _textEditor.Selection.DetachFromVisualTree(); 
            }
 
            // Detach scroll handler from old scroll viewer. 
            // Note that this.ScrollViewer will walk the tree from current TextEditor's render scope up to its ui scope.
            if (this.ScrollViewer != null) 
            {
                this.ScrollViewer.ScrollChanged -= new ScrollChangedEventHandler(OnScrollChanged);
            }
 
            // Invalidate our cached copy of scroll viewer.
            _scrollViewer = null; 
 
            ClearContentHost();
        } 

        // Initializes a new render scope.
        private void InitializeRenderScope()
        { 
            if (_renderScope == null)
            { 
                return; 
            }
 
            // Map the TextContainer and TextView.
            ITextView textView = (ITextView)((IServiceProvider)_renderScope).GetService(typeof(ITextView));

            this.TextContainer.TextView = textView; 
            _textEditor.TextView = textView; //
 
            if (this.ScrollViewer != null) 
            {
                this.ScrollViewer.CanContentScroll = true; 
            }
        }

        // Uninitializes a render scope and clears this control's reference. 
        private void UninitializeRenderScope()
        { 
            // Clear TextView property in TextEditor 
            _textEditor.TextView = null;
 
            // Remove our content from the renderScope
            if (_renderScope is TextBoxView)
            {
                // Nothing to do. 
            }
            else if (_renderScope is FlowDocumentView) 
            { 
                if (((FlowDocumentView)_renderScope).Document != null)
                { 
                    ((FlowDocumentView)_renderScope).Document.Uninitialize();
                    ((FlowDocumentView)_renderScope).Document = null;
                }
            } 
            else
            { 
                Invariant.Assert(_renderScope == null, "_renderScope must be null here"); 
            }
        } 

        /// 
        /// Creates the default brush used for selection rendering.
        ///  
        private static Brush GetDefaultSelectionBrush()
        { 
            Brush selectionBrush = new SolidColorBrush(SystemColors.HighlightColor); 
            selectionBrush.Freeze();
            return selectionBrush; 
        }

        /// 
        /// Callback for PageHeight GetValue. 
        /// 
        ///  
        /// dependency object 
        /// 
        ///  
        /// 
        private static object OnPageHeightGetValue(DependencyObject d)
        {
            return ((TextBoxBase)d).ViewportHeight; 
        }
 
        ///  
        /// Finds an element in a style temaplte marked as ContentHostTemplateName
        /// where our render scope must be placed as a child. 
        /// 
        private void SetRenderScopeToContentHost()
        {
            FrameworkElement renderScope = CreateRenderScope(); 

            // Clear the content host from previous render scope (if any) 
            ClearContentHost(); 

            // Find ContentHostTemplateName in the style 
            _textBoxContentHost = GetTemplateChild(ContentHostTemplateName) as FrameworkElement;
            // Note that we allow ContentHostTemplateName to be optional.
            // This simplifies toolability of our control styling.
            // When the ContentHostTemplateName is not found or incorrect 
            // TextBox goes into disabled state, but not throw.
 
            // Add renderScope as a child of ContentHostTemplateName 
            _renderScope = renderScope;
            if (_textBoxContentHost is ScrollViewer) 
            {
                ScrollViewer scrollViewer = (ScrollViewer)_textBoxContentHost;

                if (scrollViewer.Content != null) 
                {
                    _renderScope = null; 
                    _textBoxContentHost = null; 
                    //
                    throw new NotSupportedException(SR.Get(SRID.TextBoxScrollViewerMarkedAsTextBoxContentMustHaveNoContent)); 
                }
                else
                {
                    scrollViewer.Content = _renderScope; // this may replace old render scope in case of upgrade scenario in TextBox 
                }
            } 
            else if (_textBoxContentHost is Decorator) 
            {
                Decorator decorator = (Decorator)_textBoxContentHost; 
                if (decorator.Child != null)
                {
                    _renderScope = null;
                    _textBoxContentHost = null; 
                    //
                    throw new NotSupportedException(SR.Get(SRID.TextBoxDecoratorMarkedAsTextBoxContentMustHaveNoContent)); 
                } 
                else
                { 
                    decorator.Child = _renderScope; // this may replace old render scope in case of upgrade scenario in TextBox
                }
            }
            else 
            {
                // When we implement TextContainer setting via TextView interface 
                // all text containing element will become allowed here. 
                _renderScope = null;
 
                // Explicitly not throwing an exception here when content host = null
                // -- designers need us to support no content scenarios
                if (_textBoxContentHost != null)
                { 
                    _textBoxContentHost = null;
                    // 
                    throw new NotSupportedException(SR.Get(SRID.TextBoxInvalidTextContainer)); 
                }
            } 

            // Attach render scope to TextEditor
            InitializeRenderScope();
        } 

        private void ClearContentHost() 
        { 
            // Detach render scope from TextEditor
            UninitializeRenderScope(); 

            // Render scope has been created by us,
            // so we need to extract if from visual tree.
            if (_textBoxContentHost is ScrollViewer) 
            {
                ((ScrollViewer)_textBoxContentHost).Content = null; 
            } 
            else if (_textBoxContentHost is Decorator)
            { 
                ((Decorator)_textBoxContentHost).Child = null;
            }
            else
            { 
                Invariant.Assert(_textBoxContentHost == null, "_textBoxContentHost must be null here");
            } 
 
            _textBoxContentHost = null;
        } 

        /// 
        /// PropertyChanged handler for IsReadOnlyCaretVisibleProperty.
        ///  
        private static void OnIsReadOnlyCaretVisiblePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        { 
            TextBoxBase textBox = (TextBoxBase)d; 
            textBox.TextSelectionInternal.UpdateCaretState(CaretScrollMethod.None);
            ((ITextSelection)textBox.TextSelectionInternal).RefreshCaret(); 
        }

        /// 
        /// Handler for ScrollViewer's OnScrollChanged event. 
        /// 
        internal virtual void OnScrollChanged(object sender, ScrollChangedEventArgs e) 
        { 
            //
            if (e.ViewportHeightChange != 0) 
            {
                SetValue(TextEditor.PageHeightProperty, e.ViewportHeight);
            }
        } 

        ///  
        /// TextSelection.Moved event listener. 
        /// 
        private void OnSelectionChangedInternal(object sender, EventArgs e) 
        {
#if OLD_AUTOMATION
            // It the automation subsystem is active, notify automation clients
            // about the selection change. 
            if (AutomationProvider.IsActive)
            { 
                RaiseSelectionChangedEvent(); 
            }
#endif 
            OnSelectionChanged(new RoutedEventArgs(SelectionChangedEvent));
        }

#if OLD_AUTOMATION 
        /// 
        /// A helper to raise AutomationEvents. 
        /// The reason this method is standalone with MethodImplOptions.NoInlining is to avoid 
        /// loading UIAutomation unless there's a client already present.
        ///  
        [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)]
        private void RaiseSelectionChangedEvent()
        {
            AutomationProvider.RaiseAutomationEvent(TextPatternIdentifiers.TextSelectionChangedEvent, this); 
        }
#endif 
        /// 
        // 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;
            } 
        } 

        ///  
        /// Callback for changed ScrollViewer properties, forwarding values from TextBoxBase to ScrollViewer.
        /// 
        /// 
        /// TextBoxBase on which the property is changed 
        /// 
        /// event args 
        internal static void OnScrollViewerPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
        {
            TextBoxBase textBox = d as TextBoxBase; 

            if (textBox != null && textBox.ScrollViewer != null)
            {
                object value = e.NewValue; 
                if (value == DependencyProperty.UnsetValue)
                { 
                    textBox.ScrollViewer.ClearValue(e.Property); 
                }
                else 
                {
                    textBox.ScrollViewer.SetValue(e.Property, value);
                }
            } 
        }
 
        // Callback for IsUndoEnabledProperty changes. 
        private static void OnIsUndoEnabledChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        { 
            TextBoxBase textBox = (TextBoxBase)d;
            textBox.ChangeUndoEnabled((bool)e.NewValue);
        }
 
        /// 
        ///  
        ///  
        private static bool UndoLimitValidateValue(object value)
        { 
            return ((int)value) >= -1;
        }

        // Callback for UndoLimitProperty changes. 
        private static void OnUndoLimitChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        { 
            TextBoxBase textBox = (TextBoxBase)d; 
            textBox.ChangeUndoLimit(e.NewValue);
        } 

        /// 
        /// Callback for changed InputMethodEnabled properties
        ///  
        /// 
        /// TextBoxBase on which the property is changed 
        ///  
        /// event args
        ///  
        ///    Critical:This code register command handlers for texteditor related events and commands (OnGotFocus)
        ///    TreatAsSafe: This just hooks up methods that are internal to this class
        /// 
        [SecurityCritical,SecurityTreatAsSafe] 
        private static void OnInputMethodEnabledPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        { 
            TextBoxBase textBox = (TextBoxBase)d; 

            if ((textBox.TextEditor != null) && (textBox.TextEditor.TextStore != null)) 
            {
                bool value = (bool)e.NewValue;
                if (value)
                { 
                    if (Keyboard.FocusedElement == textBox)
                    { 
                         // Call TextStore.OnGotFocus() to set up the focus dim correctly. 
                         textBox.TextEditor.TextStore.OnGotFocus();
                    } 
                }
            }
        }
 
        /// 
        /// PropertyChanged callback for a property that affects the selection or caret rendering. 
        ///  
        private static void UpdateCaretElement(DependencyObject d, DependencyPropertyChangedEventArgs e)
        { 
            TextBoxBase textBoxBase = (TextBoxBase)d;

            if (textBoxBase.TextSelectionInternal != null)
            { 
                CaretElement caretElement = textBoxBase.TextSelectionInternal.CaretElement;
                if (caretElement != null) 
                { 
                    if (e.Property == CaretBrushProperty)
                    { 
                        caretElement.UpdateCaretBrush(TextSelection.GetCaretBrush(textBoxBase.TextEditor));
                    }

                    caretElement.InvalidateVisual(); 
                }
            } 
        } 

        #endregion Private methods 

        //-----------------------------------------------------
        //
        //  Private Fields 
        //
        //----------------------------------------------------- 
 
        #region Private Fields
 
        private static DependencyObjectType _dType;

        // Text content owned by this TextBox.
        // 
        private TextContainer _textContainer;
 
        // Text editor 
        private TextEditor _textEditor;
 
        // An element marked as TextBoxContentto which we assign our _renderScope as a anonymous child.
        // In case when TextBoxContent is not an anonymouse child this member is null.
        private FrameworkElement _textBoxContentHost;
 
        // Encapsulated control that holds/implements our TextContainer.
        private FrameworkElement _renderScope; 
 
        // ScrollViewer
        private ScrollViewer _scrollViewer; 

        /// When TextEditor fires a TextChanged event, listeners may want to use the event to
        /// update their Undo/Redo UI.  But the undo stack hasn't yet been modified by the event,
        /// so querying that stack won't give us the information we need to report correctly. 
        /// TextBoxBase therefore caches the UndoAction here, so that CanUndo can reference it
        /// and make the right determination. 
        private UndoAction _pendingUndoAction; 

        // Part name used in the style. The class TemplatePartAttribute should use the same name 
        internal const string ContentHostTemplateName = "PART_ContentHost";

        #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