TextBox.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Dotnetfx_Win7_3.5.1 / Dotnetfx_Win7_3.5.1 / 3.5.1 / DEVDIV / depot / DevDiv / releases / Orcas / NetFXw7 / wpf / src / Framework / System / Windows / Controls / TextBox.cs / 1 / TextBox.cs

                            //---------------------------------------------------------------------------- 
//
// File: TextBox.cs
//
// Copyright (C) Microsoft Corporation.  All rights reserved. 
//
// Description: The stock plain text editing control. 
// 
//---------------------------------------------------------------------------
 
namespace System.Windows.Controls
{
    using MS.Internal;
    using System.Threading; 
    using System.Collections; // IEnumerator
    using System.ComponentModel; // DefaultValue 
    using System.Globalization; 
    using System.Windows;
    using System.Windows.Media; 
    using System.Windows.Data; // Binding
    using System.Windows.Documents;
    using System.Windows.Automation.Peers;
    using System.Windows.Input; // CanExecuteRoutedEventArgs, ExecuteRoutedEventArgs 

    using System.Windows.Controls.Primitives; // TextBoxBase 
    using System.Windows.Navigation; 
    using System.Windows.Markup; // IAddChild, XamlDesignerSerializer, ContentPropertyAttribute
    using MS.Utility; 
    using MS.Internal.Text;
    using MS.Internal.Automation;   // TextAdaptor
    using MS.Internal.Documents;    // Undo
    using MS.Internal.Commands;     // CommandHelpers 

    ///  
    /// The stock text editing control. 
    /// 
    [Localizability(LocalizationCategory.Text)] 
    [ContentProperty("Text")]
    public class TextBox : TextBoxBase, IAddChild, ITextBoxViewHost
    {
        //----------------------------------------------------- 
        //
        //  Constructors 
        // 
        //-----------------------------------------------------
 
        #region Constructors

        /// 
        /// Static constructor for TextBox. 
        /// 
        static TextBox() 
        { 
            DefaultStyleKeyProperty.OverrideMetadata(typeof(TextBox), new FrameworkPropertyMetadata(typeof(TextBox)));
            _dType = DependencyObjectType.FromSystemTypeInternal(typeof(TextBox)); 

            // Add handlers for height properties so we can manage min/maxLines
            PropertyChangedCallback callback = new PropertyChangedCallback(OnMinMaxChanged);
 
            HeightProperty.OverrideMetadata(typeof(TextBox), new FrameworkPropertyMetadata(callback));
            MinHeightProperty.OverrideMetadata(typeof(TextBox), new FrameworkPropertyMetadata(callback)); 
            MaxHeightProperty.OverrideMetadata(typeof(TextBox), new FrameworkPropertyMetadata(callback)); 
            FontFamilyProperty.OverrideMetadata(typeof(TextBox), new FrameworkPropertyMetadata(callback));
            FontSizeProperty.OverrideMetadata(typeof(TextBox), new FrameworkPropertyMetadata(callback)); 

            // Registering typography properties metadata
            PropertyChangedCallback onTypographyChanged = new PropertyChangedCallback(OnTypographyChanged);
            DependencyProperty[] typographyProperties = Typography.TypographyPropertiesList; 
            for (int i = 0; i < typographyProperties.Length; i++)
            { 
                typographyProperties[i].OverrideMetadata(typeof(TextBox), new FrameworkPropertyMetadata(onTypographyChanged)); 
            }
 
            HorizontalScrollBarVisibilityProperty.OverrideMetadata(typeof(TextBox), new FrameworkPropertyMetadata(
             ScrollBarVisibility.Hidden,
             new PropertyChangedCallback(OnScrollViewerPropertyChanged), // PropertyChangedCallback
             new CoerceValueCallback(CoerceHorizontalScrollBarVisibility))); 

        } 
 
        /// 
        /// Constructor 
        /// 
        public TextBox() : 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(TextBox), /*acceptsRichContent:*/false, /*readOnly*/false, /*registerEventListeners*/false); 

            // Create TextContainer and TextEditor associated with it
            TextContainer container = new TextContainer(this, true /* plainTextOnly */);
            container.CollectTextChanges = true; 
            InitializeTextContainer(container);
 
            // TextBox only accepts plain text, so change TextEditor's default to that. 
            this.TextEditor.AcceptsRichContent = false;
        } 

        #endregion Constructors

        //------------------------------------------------------ 
        //
        //  Public Methods 
        // 
        //-----------------------------------------------------
 
        #region Public Methods

        // ------------------------------------------------------------
        // 
        // IAddChild interface
        // 
        // ------------------------------------------------------------ 

        /// 
        /// Called to Add the object as a Child.
        ///
        ///
        /// Object to add as a child 
        ///
        /// 
        /// This method will always throw InvalidOperationException because 
        /// the TextBox only accepts plain text.
        /// 
        void IAddChild.AddChild(Object value)
        {
            if (value == null)
            { 
                throw new ArgumentNullException("value");
            } 
 
            // TextBox only accepts plain text, via IAddChild.AddText.
            throw new InvalidOperationException(SR.Get(SRID.TextBoxInvalidChild, value.ToString())); 
        }

        ///
        /// Called when text appears under the tag in markup. 
        ///
        /// 
        /// Text to Add to the Object 
        ///
        void IAddChild.AddText(string text) 
        {
            if (text == null)
            {
                throw new ArgumentNullException("text"); 
            }
 
            this.TextContainer.End.InsertTextInRun(text); 
        }
 
        /// 
        /// Select the text in the given position and length.
        /// 
        public void Select(int start, int length) 
        {
            if (start < 0) 
            { 
                throw new ArgumentOutOfRangeException("start", SR.Get(SRID.ParameterCannotBeNegative));
            } 

            if (length < 0)
            {
                throw new ArgumentOutOfRangeException("length", SR.Get(SRID.ParameterCannotBeNegative)); 
            }
 
            // Identify new position for selection Start 
            int maxStart = TextContainer.SymbolCount;
            if (start > maxStart) 
            {
                start = maxStart;
            }
            TextPointer newStart = this.TextContainer.CreatePointerAtOffset(start, LogicalDirection.Forward); 

            // Normalize new start in some particular direction, to exclude ambiguity on surrogates bounndaries 
            // and to start counting length from appropriate position. 
            newStart = newStart.GetInsertionPosition(LogicalDirection.Forward);
 
            // Identify new position for selection End
            int maxLength = newStart.GetOffsetToPosition(TextContainer.End);
            if (length > maxLength)
            { 
                length = maxLength;
            } 
            TextPointer newEnd = new TextPointer(newStart, length, LogicalDirection.Forward); 

            // Normalize end in some particular direction to exclude ambiguity on surrogate boundaries 
            newEnd = newEnd.GetInsertionPosition(LogicalDirection.Forward);

            // Set new selection
            TextSelectionInternal.Select(newStart, newEnd); 
        }
 
        ///  
        /// Clear all the content in the TextBox control.
        ///  
        public void Clear()
        {
            using (this.TextSelectionInternal.DeclareChangeBlock())
            { 
                this.TextContainer.DeleteContentInternal((TextPointer)this.TextContainer.Start, (TextPointer)this.TextContainer.End);
                TextSelectionInternal.Select(this.TextContainer.Start, this.TextContainer.Start); 
            } 
        }
 
        /// 
        /// Return the 0-based character index of the given point.  If there is no character
        /// at that point and snapToText is false, return -1.
        ///  
        /// Point in TextBox coordinate space
        /// if true and there is no character at the given point, will return the nearest character 
        /// Character index at the given point, or -1 
        public int GetCharacterIndexFromPoint(Point point, bool snapToText)
        { 
            if (this.RenderScope == null)
            {
                return -1;
            } 

            TextPointer textPointer = GetTextPositionFromPointInternal(point, snapToText); 
 
            if (textPointer != null)
            { 
                // offset corresponds to insertion position
                int offset = textPointer.Offset;

                // return character index based on orientation of TextPointer 
                return (textPointer.LogicalDirection == LogicalDirection.Backward) ? offset - 1 : offset;
            } 
            else 
            {
                return -1; 
            }
        }

        ///  
        /// Return the 0-based character index of the first character of lineIndex.
        ///  
        /// 0-based index of the line for which we want the first character index 
        /// 0-based index of the first character of lineIndex, or -1 if no layout information is available.
        public int GetCharacterIndexFromLineIndex(int lineIndex) 
        {
            if (this.RenderScope == null)
            {
                return -1; 
            }
 
            if (lineIndex < 0 || lineIndex >= LineCount) 
            {
                throw new ArgumentOutOfRangeException("lineIndex"); 
            }

            TextPointer textPointer = GetStartPositionOfLine(lineIndex);
 
            // textPointer will be null if there is no layout available.
            return (textPointer == null) ? 0 : textPointer.Offset; 
        } 

        ///  
        /// Return the 0-based index of the line containing the given character index.
        /// 
        /// index of the character for which a line index is to be returned
        ///  
        /// 0-based index of the line containing the character at charIndex, or -1 if no
        /// layout information is available 
        ///  
        public int GetLineIndexFromCharacterIndex(int charIndex)
        { 
            if (this.RenderScope == null)
            {
                return -1;
            } 

            if (charIndex < 0 || charIndex > this.TextContainer.SymbolCount) 
            { 
                throw new ArgumentOutOfRangeException("charIndex");
            } 

            Rect rect;
            int line;
 
            TextPointer textPointer = this.TextContainer.CreatePointerAtOffset(charIndex, LogicalDirection.Forward);
            if (GetRectangleFromTextPositionInternal(textPointer, /*relativeToTextBox*/false, out rect)) 
            { 
                rect.Y += this.VerticalOffset;
                line = (int)((rect.Top + rect.Height / 2) / GetLineHeight()); 
            }
            else
            {
                line = -1; 
            }
 
            return line; 
        }
 
        /// 
        /// Return the number of characters in the given line.
        /// 
        /// 0-based line index 
        /// number of characters in the given line, or -1 if no layout information is available
        public int GetLineLength(int lineIndex) 
        { 
            if (this.RenderScope == null)
            { 
                return -1;
            }

            if (lineIndex < 0 || lineIndex >= LineCount) 
            {
                throw new ArgumentOutOfRangeException("lineIndex"); 
            } 

            TextPointer textPointerStart = GetStartPositionOfLine(lineIndex); 
            TextPointer textPointerEnd = GetEndPositionOfLine(lineIndex);
            int length;

            if (textPointerStart == null || textPointerEnd == null) 
            {
                // No layout available. 
                length = -1; 
            }
            else 
            {
                length = textPointerStart.GetOffsetToPosition(textPointerEnd);
            }
 
            return length;
        } 
 
        /// 
        /// Return the index of the first line that is currently visible in the TextBox. 
        /// 
        /// 0-based index of the first visible line, or -1 if no layout information is available
        public int GetFirstVisibleLineIndex()
        { 
            if (this.RenderScope == null)
            { 
                return -1; 
            }
 
            // Include an epsilon in the calculation below to account for floating
            // point rounding error.  Example: suppose we're looking for line 10.
            // Because of rounding error, we calculate line 9.9999, take the
            // Floor, and get the previous line. 
            const double epsilon = 0.0001;
            double lineHeight = GetLineHeight(); 
            return (int)Math.Floor((this.VerticalOffset / lineHeight) + epsilon); 
        }
 
        /// 
        /// Return the index of the last line that is currently visible in the TextBox.
        /// 
        /// 0-based index of the last visible line, or -1 if no layout information is available 
        public int GetLastVisibleLineIndex()
        { 
            double height; 

            if (this.RenderScope == null) 
            {
                return -1;
            }
 
            height = ((IScrollInfo)this.RenderScope).ExtentHeight;
 
            if (this.VerticalOffset + this.ViewportHeight >= height) 
            {
                return this.LineCount - 1; 
            }
            else
            {
                return (int)Math.Floor((this.VerticalOffset + this.ViewportHeight - 1) / GetLineHeight()); 
            }
        } 
 
        /// 
        /// Scroll the minimal amount necessary to bring the given line into full view. 
        /// 
        /// line to scroll into view
        public void ScrollToLine(int lineIndex)
        { 
            if (this.RenderScope == null)
            { 
                return; 
            }
 
            if (lineIndex < 0 || lineIndex >= LineCount)
            {
                throw new ArgumentOutOfRangeException("lineIndex");
            } 

            TextPointer textPointer = GetStartPositionOfLine(lineIndex); 
            Rect rect; 
            if (GetRectangleFromTextPositionInternal(textPointer, false, out rect))
            { 
                this.RenderScope.BringIntoView(rect);
            }
        }
 
        /// 
        /// Get the text displayed at the given line. 
        ///  
        /// 0-based index of the desired line
        /// String containing a copy of the text at the given line index, or null if no layout information 
        /// is available
        public String GetLineText(int lineIndex)
        {
            string text; 
            TextPointer startOfLine;
            TextPointer endOfLine; 
 
            if (this.RenderScope == null)
            { 
                return null; // sentinel value
            }

            if (lineIndex < 0 || lineIndex >= LineCount) 
            {
                throw new ArgumentOutOfRangeException("lineIndex"); 
            } 

            startOfLine = GetStartPositionOfLine(lineIndex); 
            endOfLine = GetEndPositionOfLine(lineIndex);

            // startOfLine/endOfLine will be null if no layout is available.
            if (startOfLine != null && endOfLine != null) 
            {
                text = TextRangeBase.GetTextInternal(startOfLine, endOfLine); 
            } 
            else
            { 
                text = this.Text;
            }

            return text; 
        }
 
        ///  
        /// Get the rectangle for the leading edge of the character at the given index.
        ///  
        /// index of the desired character
        /// leading edge rectangle of the given character, or Rect.Empty if no layout information is available.
        public Rect GetRectFromCharacterIndex(int charIndex)
        { 
            return GetRectFromCharacterIndex(charIndex, /*trailingEdge*/false);
        } 
 
        /// 
        /// Get the rectangle for an edge of the character at the given index. 
        /// 
        /// index of the desired character
        /// specifies an edge of the character bounding box
        /// leading or trailing edge rectangle of the given character, or Rect.Empty if no layout information is available. 
        public Rect GetRectFromCharacterIndex(int charIndex, bool trailingEdge)
        { 
            if (charIndex < 0 || charIndex > this.TextContainer.SymbolCount) 
            {
                throw new ArgumentOutOfRangeException("charIndex"); 
            }

            // Start by moving to an insertion position in backward direction.
            // This ensures that when the character at charIndex is part of a surrogate pair or multi-byte character, 
            // we handle leading/trailing edge correctly.
 
            TextPointer textPointer = TextContainer.CreatePointerAtOffset(charIndex, LogicalDirection.Backward); 
            textPointer = textPointer.GetInsertionPosition(LogicalDirection.Backward);
 
            if (trailingEdge && charIndex < this.TextContainer.SymbolCount)
            {
                // Get next insertion position
                textPointer = textPointer.GetNextInsertionPosition(LogicalDirection.Forward); 
                Invariant.Assert(textPointer != null);
 
                // Backward gravity for trailing edge 
                textPointer = textPointer.GetPositionAtOffset(0, LogicalDirection.Backward);
            } 
            else
            {
                // Forward gravity for leading edge
                textPointer = textPointer.GetPositionAtOffset(0, LogicalDirection.Forward); 
            }
 
            // NB: rect will be Rect.Empty if no layout is available. 
            Rect rect;
            GetRectangleFromTextPositionInternal(textPointer, /*relativeToTextBox*/true, out rect); 
            return rect;
        }

        ///  
        /// Returns the associated IndexedSpellingError at a specified character index.
        ///  
        ///  
        /// Index of text to query.
        ///  
        /// 
        /// The charIndex paramter specifies a character to query.
        /// If the specificed character is not part of a misspelled word (or if
        /// IsSpellCheckEnabled == false) then this method will return null. 
        /// 
        public SpellingError GetSpellingError(int charIndex) 
        { 
            if (charIndex < 0 || charIndex > this.TextContainer.SymbolCount)
            { 
                throw new ArgumentOutOfRangeException("charIndex");
            }

            TextPointer position = this.TextContainer.CreatePointerAtOffset(charIndex, LogicalDirection.Forward); 
            SpellingError spellingError = this.TextEditor.GetSpellingErrorAtPosition(position, LogicalDirection.Forward);
 
            if (spellingError == null && charIndex < this.TextContainer.SymbolCount - 1) 
            {
                position = this.TextContainer.CreatePointerAtOffset(charIndex + 1, LogicalDirection.Forward); 
                spellingError = this.TextEditor.GetSpellingErrorAtPosition(position, LogicalDirection.Backward);
            }

            return spellingError; 
        }
 
        ///  
        /// Returns the start index of the first character of a spelling error
        /// containing a specified char. 
        /// 
        /// 
        /// Index of the character to query.
        ///  
        /// 
        /// Start index of the spelling error containing a specified char, or -1 if 
        /// the char is not part of a spelling error. 
        /// 
        public int GetSpellingErrorStart(int charIndex) 
        {
            SpellingError spellingError = GetSpellingError(charIndex);

            return (spellingError == null) ? -1 : spellingError.Start.Offset; 
        }
 
        ///  
        /// Returns the length of the spelling error containing a specified char.
        ///  
        /// 
        /// Index of the character to query.
        /// 
        ///  
        /// Length of the spelling error containing a specified char, or 0 if
        /// the char is not part of a spelling error. 
        ///  
        public int GetSpellingErrorLength(int charIndex)
        { 
            SpellingError spellingError = GetSpellingError(charIndex);

            return (spellingError == null) ? 0 : spellingError.End.Offset - spellingError.Start.Offset;
        } 

        ///  
        /// Returns the index of the next character in a specificed direction 
        /// that is the start of a misspelled word.
        ///  
        /// 
        /// Index of text to query.
        /// 
        ///  
        /// Direction to query.
        ///  
        ///  
        /// The charIndex paramter specifies a character at which to start the query.
        /// When direction == LogicalDirection.Forward, the search includes the 
        /// spelling error containing charIndex (if any).
        /// When direction == LogicalDirection.Backward, the search does not
        /// include the error containing charIndex (if any).
        /// 
        /// If no misspelled word is encountered, the method returns -1.
        ///  
        public int GetNextSpellingErrorCharacterIndex(int charIndex, LogicalDirection direction) 
        {
            if (charIndex < 0 || charIndex > this.TextContainer.SymbolCount) 
            {
                throw new ArgumentOutOfRangeException("charIndex");
            }
 
            if (this.TextContainer.SymbolCount == 0)
            { 
                // Early out on an empty doc to keep logic simpler below. 
                return -1;
            } 

            ITextPointer position = this.TextContainer.CreatePointerAtOffset(charIndex, direction);

            position = this.TextEditor.GetNextSpellingErrorPosition(position, direction); 

            return (position == null) ? -1 : position.Offset; 
        } 

        #endregion Public Methods 

        //-----------------------------------------------------
        //
        //  Public Properties 
        //
        //------------------------------------------------------ 
 
        #region Public Properties
 
        /// 
        /// DependencyProperty for  property.
        /// 
        public static readonly DependencyProperty TextWrappingProperty = 
                TextBlock.TextWrappingProperty.AddOwner(
                        typeof(TextBox), 
                        new FrameworkPropertyMetadata( 
                                TextWrapping.NoWrap,
                                FrameworkPropertyMetadataOptions.AffectsMeasure, 
                                new PropertyChangedCallback(OnTextWrappingChanged)));

        /// 
        /// The TextWrapping property controls whether or not text wraps 
        /// when it reaches the flow edge of its containing block box.
        ///  
        public TextWrapping TextWrapping 
        {
            get 
            {
                return (TextWrapping)GetValue(TextWrappingProperty);
            }
            set 
            {
                SetValue(TextWrappingProperty, value); 
            } 
        }
 
        /// 
        /// Dependency ID for the MinLines property
        /// Default value: 1
        ///  
        public static readonly DependencyProperty MinLinesProperty =
                DependencyProperty.Register( 
                        "MinLines", // Property name 
                        typeof(int), // Property type
                        typeof(TextBox), // Property owner 
                        new FrameworkPropertyMetadata(
                                1,
                                FrameworkPropertyMetadataOptions.AffectsMeasure,
                                new PropertyChangedCallback(OnMinMaxChanged)), 
                        new ValidateValueCallback(MinLinesValidateValue));
 
        ///  
        /// Minimum number of lines to size to.
        ///  
        [DefaultValue(1)]
        public int MinLines
        {
            get { return (int) GetValue(MinLinesProperty); } 
            set { SetValue(MinLinesProperty, value); }
        } 
 
        /// 
        /// Dependency ID for the MaxLines property 
        /// Default value: MaxInt
        /// 
        public static readonly DependencyProperty MaxLinesProperty =
                DependencyProperty.Register( 
                        "MaxLines", // Property name
                        typeof(int), // Property type 
                        typeof(TextBox), // Property owner 
                        new FrameworkPropertyMetadata(
                                Int32.MaxValue, 
                                FrameworkPropertyMetadataOptions.AffectsMeasure,
                                new PropertyChangedCallback(OnMinMaxChanged)),
                        new ValidateValueCallback(MaxLinesValidateValue));
 
        /// 
        /// Minimum number of lines to size to. 
        ///  
        [DefaultValue(Int32.MaxValue)]
        public int MaxLines 
        {
            get { return (int) GetValue(MaxLinesProperty); }
            set { SetValue(MaxLinesProperty, value); }
        } 

        ///  
        /// The DependencyID for the Text property. 
        /// Default Value:      ""
        ///  
        public static readonly DependencyProperty TextProperty =
                DependencyProperty.Register(
                        "Text", // Property name
                        typeof(string), // Property type 
                        typeof(TextBox), // Property owner
                        new FrameworkPropertyMetadata( // Property metadata 
                                string.Empty, // default value 
                                FrameworkPropertyMetadataOptions.BindsTwoWayByDefault | // Flags
                                    FrameworkPropertyMetadataOptions.Journal, 
                                new PropertyChangedCallback(OnTextPropertyChanged),    // property changed callback
                                new CoerceValueCallback(CoerceText),
                                true, // IsAnimationProhibited
                                UpdateSourceTrigger.LostFocus   // DefaultUpdateSourceTrigger 
                                ));
 
        ///  
        /// Contents of the TextBox.
        ///  
        [DefaultValue("")]
        [Localizability(LocalizationCategory.Text)]
        public string Text
        { 
            get { return (string) GetValue(TextProperty); }
            set { SetValue(TextProperty, value); } 
        } 

        ///  
        /// The DependencyID for the CharacterCasing property.
        /// Controls whether or not input text is converted to upper or lower case
        /// Flags:              Can be used in style rules
        /// Default Value:      CharacterCasing.Normal 
        /// 
        public static readonly DependencyProperty CharacterCasingProperty = 
                DependencyProperty.Register( 
                        "CharacterCasing", // Property name
                        typeof(CharacterCasing), // Property type 
                        typeof(TextBox), // Property owner
                        new FrameworkPropertyMetadata(CharacterCasing.Normal /*default value*/),
                        new ValidateValueCallback(CharacterCasingValidateValue) /*validation callback*/);
 
        /// 
        /// Character casing of the TextBox 
        ///  
        public CharacterCasing CharacterCasing
        { 
            get { return (CharacterCasing) GetValue(CharacterCasingProperty); }
            set { SetValue(CharacterCasingProperty, value); }
        }
 
        /// 
        /// The limit number of characters that the textbox or other editable controls can contain. 
        /// if it is 0, means no-limitation. 
        /// User can set this value for some simple single line textbox to restrict the text number.
        /// RichTextBox doesn't have this limitation. 
        /// By default it is 0.
        /// 
        /// 
        /// When this property is set to zero, the maximum length of the text that can be entered 
        /// in the control is limited only by available memory. You can use this property to restrict
        /// the length of text entered in the control for values such as postal codes and telephone numbers. 
        /// You can also use this property to restrict the length of text entered when the data is to be entered 
        /// in a database.
        /// You can limit the text entered into the control to the maximum length of the corresponding field in the database. 
        /// Note:   In code, you can set the value of the Text property to a value that is larger than
        /// the value specified by the MaxLength property.
        /// This property only affects text entered into the control at runtime.
        ///  
        public static readonly DependencyProperty MaxLengthProperty =
                DependencyProperty.Register( 
                    "MaxLength", // Property name 
                    typeof(int), // Property type
                    typeof(TextBox), // Property owner 
                    new FrameworkPropertyMetadata(0), /*default value*/
                    new ValidateValueCallback(MaxLengthValidateValue));

 
        /// 
        /// Maximum number of characters the TextBox can accept 
        ///  
        [DefaultValue((int)0)]
        [Localizability(LocalizationCategory.None, Modifiability = Modifiability.Unmodifiable)] // cannot be modified by localizer 
        public int MaxLength
        {
            get { return (int) GetValue(MaxLengthProperty); }
            set { SetValue(MaxLengthProperty, value); } 
        }
 
        ///  
        /// DependencyProperty for  property.
        ///  
        public static readonly DependencyProperty TextAlignmentProperty = Block.TextAlignmentProperty.AddOwner(typeof(TextBox));

        /// 
        /// The TextAlignment property specifies horizontal alignment of the content. 
        /// 
        public TextAlignment TextAlignment 
        { 
            get
            { 
                return (TextAlignment)GetValue(TextAlignmentProperty);
            }
            set
            { 
                SetValue(TextAlignmentProperty, value);
            } 
        } 

        ///  
        /// Selected Text
        /// 
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public string SelectedText 
        {
            get 
            { 
                return TextSelectionInternal.Text;
            } 
            set
            {
                using (this.TextSelectionInternal.DeclareChangeBlock())
                { 
                    TextSelectionInternal.Text = value;
                } 
            } 
        }
 
        /// 
        /// Character number of the selected text
        /// 
        ///  
        /// Length is calculated as unicode count, so it counts
        /// eacn \r\n combination as 2 - even though it is actially 
        /// one caret position, and it would be illegal to insert 
        /// any characters between them or expect selection ends
        /// to stay between them. 
        /// Because of that after setting SelectionLength to some value
        /// it can be automatically corrected (by adding 1)
        /// if selection end happens to be between \r and \n.
        ///  
        [DefaultValue((int)0)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] 
        public int SelectionLength 
        {
            get 
            {
                return TextSelectionInternal.Start.GetOffsetToPosition(TextSelectionInternal.End);
            }
            set 
            {
                if (value < 0) 
                { 
                    throw new ArgumentOutOfRangeException("value", SR.Get(SRID.ParameterCannotBeNegative));
                } 

                // Identify new position for selection end
                int maxLength = TextSelectionInternal.Start.GetOffsetToPosition(TextContainer.End);
                if (value > maxLength) 
                {
                    value = maxLength; 
                } 
                TextPointer newEnd = new TextPointer(TextSelectionInternal.Start, value, LogicalDirection.Forward);
 
                // Normalize end in some particular direction to exclude ambiguity on surrogate boundaries
                newEnd = newEnd.GetInsertionPosition(LogicalDirection.Forward);

                // Set new selection 
                TextSelectionInternal.Select(TextSelectionInternal.Start, newEnd);
            } 
        } 

        ///  
        /// The start position of the selection.
        /// 
        /// 
        /// Index is calculated as unicode offset, so it counts 
        /// eacn \r\n combination as 2 - even though it is actially
        /// one caret position, and it would be illegal to insert 
        /// any characters between them or expect selection ends 
        /// to stay between them.
        /// Because of that after setting SelectionStart to some value 
        /// it can be automatically corrected (by adding 1)
        /// if it happens to be between \r and \n.
        /// 
        [DefaultValue((int)0)] 
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public int SelectionStart 
        { 
            get
            { 
                return this.TextSelectionInternal.Start.Offset;
            }
            set
            { 
                if (value < 0)
                { 
                    throw new ArgumentOutOfRangeException("value", SR.Get(SRID.ParameterCannotBeNegative)); 
                }
 
                // Store current length of the selection
                int selectionLength = TextSelectionInternal.Start.GetOffsetToPosition(TextSelectionInternal.End);

                // Identify new position for selection Start 
                int maxStart = TextContainer.SymbolCount;
                if (value > maxStart) 
                { 
                    value = maxStart;
                } 
                TextPointer newStart = TextContainer.CreatePointerAtOffset(value, LogicalDirection.Forward);

                // Normalize new start in some particular direction, to exclude ambiguity on surrogates bounndaries
                // and to start counting length from appropriate position. 
                newStart = newStart.GetInsertionPosition(LogicalDirection.Forward);
 
                // Identify new position for selection End 
                int maxLength = newStart.GetOffsetToPosition(TextContainer.End);
                if (selectionLength > maxLength) 
                {
                    selectionLength = maxLength;
                }
                TextPointer newEnd = new TextPointer(newStart, selectionLength, LogicalDirection.Forward); 

                // Normalize end in some particular direction to exclude ambiguity on surrogate boundaries 
                newEnd = newEnd.GetInsertionPosition(LogicalDirection.Forward); 

                // Set new selection 
                TextSelectionInternal.Select(newStart, newEnd);
            }
        }
 
        /// 
        /// Position of the caret. 
        ///  
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public int CaretIndex 
        {
            get
            {
                return SelectionStart; 
            }
 
            set 
            {
                Select(value, 0); 
            }
        }

        ///  
        /// Number of lines in the TextBox.
        ///  
        /// number of lines in the TextBox, or -1 if no layout information is available 
        /// 
        /// If Wrap == true, changing the width of the TextBox may change this value. 
        /// The value returned is the number of lines in the entire TextBox, regardless of how many are
        /// currently in view.
        /// 
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] 
        public int LineCount
        { 
            get 
            {
                if (this.RenderScope == null) 
                {
                    return -1;
                }
 
                return GetLineIndexFromCharacterIndex(this.TextContainer.SymbolCount) + 1;
            } 
        } 

        ///  
        /// DependencyProperty for the TextDecorations property.
        /// 
        public static readonly DependencyProperty TextDecorationsProperty =
                Inline.TextDecorationsProperty.AddOwner( 
                        typeof(TextBox),
                        new FrameworkPropertyMetadata( 
                            new FreezableDefaultValueFactory(TextDecorationCollection.Empty), 
                            FrameworkPropertyMetadataOptions.AffectsRender));
 
        /// 
        /// Property used to apply decorations such as underline to content.
        /// 
        public TextDecorationCollection TextDecorations 
        {
            get { return (TextDecorationCollection)GetValue(TextDecorationsProperty); } 
            set { SetValue(TextDecorationsProperty, value); } 
        }
 

        /// 
        /// Access to all text typography properties.
        ///  
        public Typography Typography
        { 
            get 
            {
                return new Typography(this); 
            }
        }

        #endregion Public Properties 

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

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

        /// 
        /// 
        /// 
        protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e) 
        {
            //  always call base.OnPropertyChanged, otherwise Property Engine will not work. 
            base.OnPropertyChanged(e);

            if (this.RenderScope != null)
            { 
                FrameworkPropertyMetadata fmetadata = e.Property.GetMetadata(typeof(TextBox)) as FrameworkPropertyMetadata;
                if (fmetadata != null) 
                { 
                    if (e.IsAValueChange || e.IsASubPropertyChange)
                    { 
                        if (fmetadata.AffectsMeasure || fmetadata.AffectsArrange ||
                            fmetadata.AffectsParentMeasure || fmetadata.AffectsParentArrange ||
                            e.Property == Control.HorizontalContentAlignmentProperty || e.Property == Control.VerticalContentAlignmentProperty)
                        { 
                            ((TextBoxView)this.RenderScope).Remeasure();
                        } 
                        else if (fmetadata.AffectsRender && 
                                (e.IsAValueChange || !fmetadata.SubPropertiesDoNotAffectRender))
                        { 
                            ((TextBoxView)this.RenderScope).Rerender();
                        }

                        if (Speller.IsSpellerAffectingProperty(e.Property) && 
                            this.TextEditor.Speller != null)
                        { 
                            this.TextEditor.Speller.ResetErrors(); 
                        }
                    } 
                }
            }

            TextBoxAutomationPeer peer = UIElementAutomationPeer.FromElement(this) as TextBoxAutomationPeer; 
            if (peer != null)
            { 
                if (e.Property == TextProperty) 
                {
                    peer.RaiseValuePropertyChangedEvent((string)e.OldValue, (string)e.NewValue); 
                }

                if (e.Property == IsReadOnlyProperty)
                { 
                    peer.RaiseIsReadOnlyPropertyChangedEvent((bool)e.OldValue, (bool)e.NewValue);
                } 
            } 
        }
 
        /// 
        /// Returns enumerator to logical children.
        /// 
        protected internal override IEnumerator LogicalChildren 
        {
            get 
            { 
                //
 

                return new RangeContentEnumerator((TextPointer)this.TextContainer.Start, (TextPointer)this.TextContainer.End);
            }
        } 

        ///  
        /// Measurement override. Implement your size-to-content logic here. 
        /// 
        ///  
        /// Sizing constraint.
        /// 
        protected override Size MeasureOverride(Size constraint)
        { 
            if (MinLines > 1 && MaxLines < MinLines)
            { 
                throw new Exception(SR.Get(SRID.TextBoxMinMaxLinesMismatch)); 
            }
 
            Size size = base.MeasureOverride(constraint);

            if (_minmaxChanged)
            { 
                // If there is a scrollViewer, we'll listen to the ScrollChanged event and
                // handle min/maxLines there. 
                if (this.ScrollViewer == null) 
                {
                    SetRenderScopeMinMaxHeight(); 
                }
                else
                {
                    SetScrollViewerMinMaxHeight(); 
                }
                _minmaxChanged = false; 
            } 

            return size; 
        }

        // Called every time after Wrap property gets new value
        internal void OnTextWrappingChanged() 
        {
            CoerceValue(HorizontalScrollBarVisibilityProperty); 
        } 

        // Allocates the initial render scope for this control. 
        internal override FrameworkElement CreateRenderScope()
        {
            return new TextBoxView(this);
        } 

        #endregion Protected Methods 
 
        //-----------------------------------------------------
        // 
        //  Internal Methods
        //
        //------------------------------------------------------
 
        #region Internal Methods
 
        ///  
        /// Detaches the editor from old visual tree and attaches it to a new one
        ///  
        internal override void AttachToVisualTree()
        {
            base.AttachToVisualTree();
 
            if (this.RenderScope == null)
            { 
                return; 
            }
 
            // Set TextWrapping property for the new renderScope
            OnTextWrappingChanged();

            // We need to recalculate our min/max story. 
            _minmaxChanged = true;
        } 
 
        /// 
        ///     Gives a string representation of this object. 
        /// 
        internal override string GetPlainText()
        {
            return this.Text; 
        }
 
        /// 
        // 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;
            } 
        } 

        ///  
        /// Scroll content by one line to the top.
        /// 
        internal override void DoLineUp()
        { 
            if (this.ScrollViewer != null)
            { 
                ScrollViewer.ScrollToVerticalOffset(VerticalOffset - GetLineHeight()); 
            }
        } 

        /// 
        /// Scroll content by one line to the bottom.
        ///  
        internal override void DoLineDown()
        { 
            if (this.ScrollViewer != null) 
            {
                ScrollViewer.ScrollToVerticalOffset(VerticalOffset + GetLineHeight()); 
            }
        }

        ///  
        /// Handler for TextContainer.Changed event.
        ///  
        internal override void OnTextContainerChanged(object sender, TextContainerChangedEventArgs e) 
        {
            // Ignore property changes that originate from OnTextPropertyChange. 
            if (!_isInsideTextContentChange)
            {
                _isInsideTextContentChange = true;
                try 
                {
                    // Use a DeferredTextReference instead of calculating the new 
                    // value now for better performance.  Most of the time no 
                    // one cares what the new is, and loading our content into a
                    // string can be extremely expensive. 
                    SetDeferredValue(TextProperty, new DeferredTextReference(this.TextContainer));
                }
                finally
                { 
                    _isInsideTextContentChange = false;
                } 
            } 

            // Let base raise the public TextBoxBase.TextChanged event. 
            base.OnTextContainerChanged(sender, e);
        }

        ///  
        /// Handler for ScrollViewer's OnScrollChanged event.
        ///  
        internal override void OnScrollChanged(object sender, ScrollChangedEventArgs e) 
        {
            base.OnScrollChanged(sender, e); 

            if (e.ViewportHeightChange != 0)
            {
                SetScrollViewerMinMaxHeight(); 
            }
        } 
 
        //
        //  This property 
        //  1. Finds the correct initial size for the _effectiveValues store on the current DependencyObject
        //  2. This is a performance optimization
        //
        internal override int EffectiveValuesInitialSize 
        {
            get { return 42; } 
        } 

        #endregion Internal methods 

        //-----------------------------------------------------
        //
        //  Internal Properties 
        //
        //------------------------------------------------------ 
 
        #region Internal Properties
 
        /// 
        /// Text Selection (readonly)
        /// 
        internal TextSelection Selection 
        {
            get 
            { 
                return (TextSelection)TextSelectionInternal;
            } 
        }

        /// 
        /// TextPointer where the TextBox's text begins (readonly) 
        /// 
        internal TextPointer StartPosition 
        { 
            get
            { 
                return (TextPointer)this.TextContainer.Start;
            }
        }
 
        /// 
        /// TextPointer where the TextBox's text ends (readonly) 
        ///  
        internal TextPointer EndPosition
        { 
            get
            {
                return (TextPointer)this.TextContainer.End;
            } 
        }
 
        ///  
        /// IsTypographyDefaultValue
        ///  
        internal bool IsTypographyDefaultValue
        {
            get
            { 
                return !_isTypographySet;
            } 
        } 

        // ITextContainer holding the Control content. 
        ITextContainer ITextBoxViewHost.TextContainer
        {
            get
            { 
                return this.TextContainer;
            } 
        } 

        // Set true when typography property values are all default values. 
        bool ITextBoxViewHost.IsTypographyDefaultValue
        {
            get
            { 
                return this.IsTypographyDefaultValue;
            } 
        } 

        #endregion Internal Properties 

        //------------------------------------------------------
        //
        //  Private Methods 
        //
        //----------------------------------------------------- 
 
        #region Private Methods
 
        // Returns false if no layout is available.
        private bool GetRectangleFromTextPositionInternal(TextPointer position, bool relativeToTextBox, out Rect rect)
        {
            if (this.RenderScope == null) 
            {
                rect = Rect.Empty; 
                return false; 
            }
 
            if (position.ValidateLayout())
            {
                rect = TextPointerBase.GetCharacterRect(position, position.LogicalDirection, relativeToTextBox);
            } 
            else
            { 
                rect = Rect.Empty; 
            }
 
            return rect != Rect.Empty;
        }

        // Returns null if no layout is available. 
        private TextPointer GetStartPositionOfLine(int lineIndex)
        { 
            if (this.RenderScope == null) 
            {
                return null; 
            }

            Point point = new Point();
 
            // all lines in TextBox are the same height, so get the line height and multiply...
            double lineHeight = GetLineHeight(); 
            point.Y = lineHeight * lineIndex + (lineHeight / 2) - VerticalOffset;  // use a point in the middle of the line, to be safe 
            point.X = -HorizontalOffset;
 
            TextPointer textPointer;

            if (TextEditor.GetTextView(this.RenderScope).Validate(point))
            { 
                textPointer = (TextPointer)TextEditor.GetTextView(this.RenderScope).GetTextPositionFromPoint(point, /* snap to text */ true);
                textPointer = (TextPointer)TextEditor.GetTextView(this.RenderScope).GetLineRange(textPointer).Start.CreatePointer(textPointer.LogicalDirection); 
            } 
            else
            { 
                textPointer = null;
            }

            return textPointer; 
        }
 
        private TextPointer GetEndPositionOfLine(int lineIndex) 
        {
            if (this.RenderScope == null) 
            {
                return null;
            }
 
            // all lines in TextBox are the same height, so get the line height and multiply...
            Point point = new Point(); 
 
            double lineHeight = GetLineHeight();
            point.Y = lineHeight * lineIndex + (lineHeight / 2) - VerticalOffset;  // use a point in the middle of the line, to be safe 
            point.X = 0;

            TextPointer textPointer;
 
            if (TextEditor.GetTextView(this.RenderScope).Validate(point))
            { 
                textPointer = (TextPointer)TextEditor.GetTextView(this.RenderScope).GetTextPositionFromPoint(point, /* snap to text */ true); 
                textPointer = (TextPointer)TextEditor.GetTextView(this.RenderScope).GetLineRange(textPointer).End.CreatePointer(textPointer.LogicalDirection);
 
                // Hit testing ignores line breaks, so the position returned will be between the last visible character
                // and the line break, if any.  We want the position AFTER the line break.
                if (TextPointerBase.IsNextToPlainLineBreak(textPointer, LogicalDirection.Forward))
                { 
                    textPointer.MoveToNextInsertionPosition(LogicalDirection.Forward);
                } 
            } 
            else
            { 
                textPointer = null;
            }

            return textPointer; 
        }
 
        private static object CoerceHorizontalScrollBarVisibility(DependencyObject d, object value) 
        {
            TextBox textBox = d as TextBox; 

            if (textBox != null && (textBox.TextWrapping == TextWrapping.Wrap || textBox.TextWrapping == TextWrapping.WrapWithOverflow))
            {
                return ScrollBarVisibility.Disabled; 
            }
            return value; 
        } 

        ///  
        /// 
        /// 
        private static bool MaxLengthValidateValue(object value)
        { 
            return ((int)value) >= 0;
        } 
 
        /// 
        ///  
        /// 
        private static bool CharacterCasingValidateValue(object value)
        {
            return (CharacterCasing.Normal <= (CharacterCasing)value && (CharacterCasing)value <= CharacterCasing.Upper); 
        }
 
        ///  
        /// 
        ///  
        private static bool MinLinesValidateValue(object value)
        {
            return ((int)value > 0);
        } 

        ///  
        ///  
        /// 
        private static bool MaxLinesValidateValue(object value) 
        {
            return ((int)value > 0);
        }
 
        /// 
        /// Callback for changes to the MinLines and MaxLines property 
        ///  
        private static void OnMinMaxChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        { 
            TextBox textBox = (TextBox)d;

            textBox._minmaxChanged = true;
        } 

        ///  
        /// Callback for changes to the Text property 
        /// 
        private static void OnTextPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
        {
            TextBox textBox = (TextBox)d;

            if (textBox._isInsideTextContentChange) 
            {
                // Ignore property changes that originate from OnTextContainerChanged. 
                return; 
            }
 
            // CoerceText will have already converted null -> String.Empty,
            // but our default CoerceValueCallback could be overridden by a
            // derived class.  So check again here.
            string newText = (string)e.NewValue; 
            if (newText == null)
            { 
                newText = String.Empty; 
            }
 
            textBox._isInsideTextContentChange = true;
            try
            {
                using (textBox.TextSelectionInternal.DeclareChangeBlock()) 
                {
                    // Update the text content with new TextProperty value. 
                    textBox.TextContainer.DeleteContentInternal((TextPointer)textBox.TextContainer.Start, (TextPointer)textBox.TextContainer.End); 
                    textBox.TextContainer.End.InsertTextInRun(newText);
                    // Collapse selection to the beginning of a text box 
                    textBox.Select(0, 0);
                }
            }
            finally 
            {
                // 
 

                textBox._isInsideTextContentChange = false; 
            }

            // We need to clear undo stack in case when the value comes from
            // databinding or some other expression. 
            if (textBox.HasExpression(textBox.LookupEntry(TextBox.TextProperty.GlobalIndex), TextBox.TextProperty))
            { 
                UndoManager undoManager = textBox.TextEditor._GetUndoManager(); 
                undoManager.Clear();
            } 
        }

        /// 
        /// Callback for changes to the TextWrapping property 
        /// 
        private static void OnTextWrappingChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
        { 
            if (d is TextBox)
            { 
                ((TextBox)d).OnTextWrappingChanged();
            }
        }
 
        /// 
        /// Update the value of ScrollViewer.MinHeight/MaxHeight 
        ///  
        private void SetScrollViewerMinMaxHeight()
        { 
            if (this.RenderScope == null)
            {
                return;
            } 

            if (ReadLocalValue(HeightProperty) != DependencyProperty.UnsetValue || 
                ReadLocalValue(MaxHeightProperty) != DependencyProperty.UnsetValue || 
                ReadLocalValue(MinHeightProperty) != DependencyProperty.UnsetValue)
            { 
                // scrub ScrollViewer's min/max height if any height values are set on TextBox
                this.ScrollViewer.ClearValue(MinHeightProperty);
                this.ScrollViewer.ClearValue(MaxHeightProperty);
                return; 
            }
 
            double chrome = this.ScrollViewer.ActualHeight - ViewportHeight; 
            double lineHeight = GetLineHeight();
            double value = chrome + (lineHeight * MinLines); 

            if (MinLines > 1 && this.ScrollViewer.MinHeight != value)
            {
                this.ScrollViewer.MinHeight = value; 
            }
 
            value = chrome + (lineHeight * MaxLines); 

            if (MaxLines < Int32.MaxValue && this.ScrollViewer.MaxHeight != value) 
            {
                this.ScrollViewer.MaxHeight = value;
            }
        } 

 
        ///  
        /// Update the value of RenderScope.MinHeight/MaxHeight
        ///  
        private void SetRenderScopeMinMaxHeight()
        {
            if (this.RenderScope == null)
            { 
                return;
            } 
 
            if (ReadLocalValue(HeightProperty) != DependencyProperty.UnsetValue ||
                ReadLocalValue(MaxHeightProperty) != DependencyProperty.UnsetValue || 
                ReadLocalValue(MinHeightProperty) != DependencyProperty.UnsetValue)
            {
                RenderScope.ClearValue(MinHeightProperty);
                RenderScope.ClearValue(MaxHeightProperty); 
            }
            else 
            { 
                double lineHeight = GetLineHeight();
                double value = lineHeight * MinLines; 

                if (MinLines > 1 && RenderScope.MinHeight != value)
                {
                    RenderScope.MinHeight = value; 
                }
 
                value = lineHeight * MaxLines; 

                if (MaxLines < Int32.MaxValue && RenderScope.MaxHeight != value) 
                {
                    RenderScope.MaxHeight = value;
                }
            } 
        }
 
        // 
        // Called by MeasureOverride to get the height of one line of text in the current font.
        // 
        private double GetLineHeight()
        {
            // change Text height based on line size
            FontFamily fontFamily = (FontFamily)this.GetValue(FontFamilyProperty); 
            double fontSize = (double)this.GetValue(TextElement.FontSizeProperty);
 
            // If Ps Task 25254 is completed (not likely in V1), LineStackingStrategy 
            // won't be constant and we'll need to call some sort of CalcLineAdvance method.
            return fontFamily.LineSpacing * fontSize; 
        }


        // 
        // Only serialize Text when not using the XamlTextHostSerializer
        // 
        ///  
        /// This method is used by TypeDescriptor to determine if this property should
        /// be serialized. 
        /// 
        [EditorBrowsable(EditorBrowsableState.Never)]
        public bool ShouldSerializeText(XamlDesignerSerializationManager manager)
        { 
            return manager.XmlWriter == null;
        } 
 
        //
        // Callback for command system to verify that the LineUp / LineDown commands should be enabled. 
        // ScrollViewer always returns true, so we follow suit.
        //
        private static void OnQueryScrollCommand(object target, CanExecuteRoutedEventArgs args)
        { 
            args.CanExecute = true;
        } 
 
        // Callback from the property system, after a new value is set to the TextProperty.
        // Note we cannot assume value is a string here -- it may be a DeferredTextReference. 
        private static object CoerceText(DependencyObject d, object value)
        {
            if (value == null)
            { 
                return String.Empty;
            } 
 
            return value;
        } 

        //  typography properties changed, no cache for this, just reset the flag
        private static void OnTypographyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        { 
            TextBox textbox = (TextBox)d;
 
            textbox._isTypographySet = true; 
        }
 
        #endregion Private methods

        //------------------------------------------------------
        // 
        //  Private Fields
        // 
        //----------------------------------------------------- 

        #region Private Fields 

        private static DependencyObjectType _dType;

        // 

        // This flag is set when the MinLines or MaxLines properties are invalidated, and 
        // checked in MeasureOverride.  When true, MeasureOverride calls SetMinMaxHeight to 
        // make sure the change in min/max height happens immediately.
        private bool _minmaxChanged; 

        // Flag used to prevent reentrancy between nested
        // OnTextPropertyChanged/OnTextContainerChanged callbacks.
        private bool _isInsideTextContentChange; 

        // Flag used to indicate that Typography properties are not at default values 
        private bool _isTypographySet; 

        #endregion Private Fields 
    }
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
//---------------------------------------------------------------------------- 
//
// File: TextBox.cs
//
// Copyright (C) Microsoft Corporation.  All rights reserved. 
//
// Description: The stock plain text editing control. 
// 
//---------------------------------------------------------------------------
 
namespace System.Windows.Controls
{
    using MS.Internal;
    using System.Threading; 
    using System.Collections; // IEnumerator
    using System.ComponentModel; // DefaultValue 
    using System.Globalization; 
    using System.Windows;
    using System.Windows.Media; 
    using System.Windows.Data; // Binding
    using System.Windows.Documents;
    using System.Windows.Automation.Peers;
    using System.Windows.Input; // CanExecuteRoutedEventArgs, ExecuteRoutedEventArgs 

    using System.Windows.Controls.Primitives; // TextBoxBase 
    using System.Windows.Navigation; 
    using System.Windows.Markup; // IAddChild, XamlDesignerSerializer, ContentPropertyAttribute
    using MS.Utility; 
    using MS.Internal.Text;
    using MS.Internal.Automation;   // TextAdaptor
    using MS.Internal.Documents;    // Undo
    using MS.Internal.Commands;     // CommandHelpers 

    ///  
    /// The stock text editing control. 
    /// 
    [Localizability(LocalizationCategory.Text)] 
    [ContentProperty("Text")]
    public class TextBox : TextBoxBase, IAddChild, ITextBoxViewHost
    {
        //----------------------------------------------------- 
        //
        //  Constructors 
        // 
        //-----------------------------------------------------
 
        #region Constructors

        /// 
        /// Static constructor for TextBox. 
        /// 
        static TextBox() 
        { 
            DefaultStyleKeyProperty.OverrideMetadata(typeof(TextBox), new FrameworkPropertyMetadata(typeof(TextBox)));
            _dType = DependencyObjectType.FromSystemTypeInternal(typeof(TextBox)); 

            // Add handlers for height properties so we can manage min/maxLines
            PropertyChangedCallback callback = new PropertyChangedCallback(OnMinMaxChanged);
 
            HeightProperty.OverrideMetadata(typeof(TextBox), new FrameworkPropertyMetadata(callback));
            MinHeightProperty.OverrideMetadata(typeof(TextBox), new FrameworkPropertyMetadata(callback)); 
            MaxHeightProperty.OverrideMetadata(typeof(TextBox), new FrameworkPropertyMetadata(callback)); 
            FontFamilyProperty.OverrideMetadata(typeof(TextBox), new FrameworkPropertyMetadata(callback));
            FontSizeProperty.OverrideMetadata(typeof(TextBox), new FrameworkPropertyMetadata(callback)); 

            // Registering typography properties metadata
            PropertyChangedCallback onTypographyChanged = new PropertyChangedCallback(OnTypographyChanged);
            DependencyProperty[] typographyProperties = Typography.TypographyPropertiesList; 
            for (int i = 0; i < typographyProperties.Length; i++)
            { 
                typographyProperties[i].OverrideMetadata(typeof(TextBox), new FrameworkPropertyMetadata(onTypographyChanged)); 
            }
 
            HorizontalScrollBarVisibilityProperty.OverrideMetadata(typeof(TextBox), new FrameworkPropertyMetadata(
             ScrollBarVisibility.Hidden,
             new PropertyChangedCallback(OnScrollViewerPropertyChanged), // PropertyChangedCallback
             new CoerceValueCallback(CoerceHorizontalScrollBarVisibility))); 

        } 
 
        /// 
        /// Constructor 
        /// 
        public TextBox() : 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(TextBox), /*acceptsRichContent:*/false, /*readOnly*/false, /*registerEventListeners*/false); 

            // Create TextContainer and TextEditor associated with it
            TextContainer container = new TextContainer(this, true /* plainTextOnly */);
            container.CollectTextChanges = true; 
            InitializeTextContainer(container);
 
            // TextBox only accepts plain text, so change TextEditor's default to that. 
            this.TextEditor.AcceptsRichContent = false;
        } 

        #endregion Constructors

        //------------------------------------------------------ 
        //
        //  Public Methods 
        // 
        //-----------------------------------------------------
 
        #region Public Methods

        // ------------------------------------------------------------
        // 
        // IAddChild interface
        // 
        // ------------------------------------------------------------ 

        /// 
        /// Called to Add the object as a Child.
        ///
        ///
        /// Object to add as a child 
        ///
        /// 
        /// This method will always throw InvalidOperationException because 
        /// the TextBox only accepts plain text.
        /// 
        void IAddChild.AddChild(Object value)
        {
            if (value == null)
            { 
                throw new ArgumentNullException("value");
            } 
 
            // TextBox only accepts plain text, via IAddChild.AddText.
            throw new InvalidOperationException(SR.Get(SRID.TextBoxInvalidChild, value.ToString())); 
        }

        ///
        /// Called when text appears under the tag in markup. 
        ///
        /// 
        /// Text to Add to the Object 
        ///
        void IAddChild.AddText(string text) 
        {
            if (text == null)
            {
                throw new ArgumentNullException("text"); 
            }
 
            this.TextContainer.End.InsertTextInRun(text); 
        }
 
        /// 
        /// Select the text in the given position and length.
        /// 
        public void Select(int start, int length) 
        {
            if (start < 0) 
            { 
                throw new ArgumentOutOfRangeException("start", SR.Get(SRID.ParameterCannotBeNegative));
            } 

            if (length < 0)
            {
                throw new ArgumentOutOfRangeException("length", SR.Get(SRID.ParameterCannotBeNegative)); 
            }
 
            // Identify new position for selection Start 
            int maxStart = TextContainer.SymbolCount;
            if (start > maxStart) 
            {
                start = maxStart;
            }
            TextPointer newStart = this.TextContainer.CreatePointerAtOffset(start, LogicalDirection.Forward); 

            // Normalize new start in some particular direction, to exclude ambiguity on surrogates bounndaries 
            // and to start counting length from appropriate position. 
            newStart = newStart.GetInsertionPosition(LogicalDirection.Forward);
 
            // Identify new position for selection End
            int maxLength = newStart.GetOffsetToPosition(TextContainer.End);
            if (length > maxLength)
            { 
                length = maxLength;
            } 
            TextPointer newEnd = new TextPointer(newStart, length, LogicalDirection.Forward); 

            // Normalize end in some particular direction to exclude ambiguity on surrogate boundaries 
            newEnd = newEnd.GetInsertionPosition(LogicalDirection.Forward);

            // Set new selection
            TextSelectionInternal.Select(newStart, newEnd); 
        }
 
        ///  
        /// Clear all the content in the TextBox control.
        ///  
        public void Clear()
        {
            using (this.TextSelectionInternal.DeclareChangeBlock())
            { 
                this.TextContainer.DeleteContentInternal((TextPointer)this.TextContainer.Start, (TextPointer)this.TextContainer.End);
                TextSelectionInternal.Select(this.TextContainer.Start, this.TextContainer.Start); 
            } 
        }
 
        /// 
        /// Return the 0-based character index of the given point.  If there is no character
        /// at that point and snapToText is false, return -1.
        ///  
        /// Point in TextBox coordinate space
        /// if true and there is no character at the given point, will return the nearest character 
        /// Character index at the given point, or -1 
        public int GetCharacterIndexFromPoint(Point point, bool snapToText)
        { 
            if (this.RenderScope == null)
            {
                return -1;
            } 

            TextPointer textPointer = GetTextPositionFromPointInternal(point, snapToText); 
 
            if (textPointer != null)
            { 
                // offset corresponds to insertion position
                int offset = textPointer.Offset;

                // return character index based on orientation of TextPointer 
                return (textPointer.LogicalDirection == LogicalDirection.Backward) ? offset - 1 : offset;
            } 
            else 
            {
                return -1; 
            }
        }

        ///  
        /// Return the 0-based character index of the first character of lineIndex.
        ///  
        /// 0-based index of the line for which we want the first character index 
        /// 0-based index of the first character of lineIndex, or -1 if no layout information is available.
        public int GetCharacterIndexFromLineIndex(int lineIndex) 
        {
            if (this.RenderScope == null)
            {
                return -1; 
            }
 
            if (lineIndex < 0 || lineIndex >= LineCount) 
            {
                throw new ArgumentOutOfRangeException("lineIndex"); 
            }

            TextPointer textPointer = GetStartPositionOfLine(lineIndex);
 
            // textPointer will be null if there is no layout available.
            return (textPointer == null) ? 0 : textPointer.Offset; 
        } 

        ///  
        /// Return the 0-based index of the line containing the given character index.
        /// 
        /// index of the character for which a line index is to be returned
        ///  
        /// 0-based index of the line containing the character at charIndex, or -1 if no
        /// layout information is available 
        ///  
        public int GetLineIndexFromCharacterIndex(int charIndex)
        { 
            if (this.RenderScope == null)
            {
                return -1;
            } 

            if (charIndex < 0 || charIndex > this.TextContainer.SymbolCount) 
            { 
                throw new ArgumentOutOfRangeException("charIndex");
            } 

            Rect rect;
            int line;
 
            TextPointer textPointer = this.TextContainer.CreatePointerAtOffset(charIndex, LogicalDirection.Forward);
            if (GetRectangleFromTextPositionInternal(textPointer, /*relativeToTextBox*/false, out rect)) 
            { 
                rect.Y += this.VerticalOffset;
                line = (int)((rect.Top + rect.Height / 2) / GetLineHeight()); 
            }
            else
            {
                line = -1; 
            }
 
            return line; 
        }
 
        /// 
        /// Return the number of characters in the given line.
        /// 
        /// 0-based line index 
        /// number of characters in the given line, or -1 if no layout information is available
        public int GetLineLength(int lineIndex) 
        { 
            if (this.RenderScope == null)
            { 
                return -1;
            }

            if (lineIndex < 0 || lineIndex >= LineCount) 
            {
                throw new ArgumentOutOfRangeException("lineIndex"); 
            } 

            TextPointer textPointerStart = GetStartPositionOfLine(lineIndex); 
            TextPointer textPointerEnd = GetEndPositionOfLine(lineIndex);
            int length;

            if (textPointerStart == null || textPointerEnd == null) 
            {
                // No layout available. 
                length = -1; 
            }
            else 
            {
                length = textPointerStart.GetOffsetToPosition(textPointerEnd);
            }
 
            return length;
        } 
 
        /// 
        /// Return the index of the first line that is currently visible in the TextBox. 
        /// 
        /// 0-based index of the first visible line, or -1 if no layout information is available
        public int GetFirstVisibleLineIndex()
        { 
            if (this.RenderScope == null)
            { 
                return -1; 
            }
 
            // Include an epsilon in the calculation below to account for floating
            // point rounding error.  Example: suppose we're looking for line 10.
            // Because of rounding error, we calculate line 9.9999, take the
            // Floor, and get the previous line. 
            const double epsilon = 0.0001;
            double lineHeight = GetLineHeight(); 
            return (int)Math.Floor((this.VerticalOffset / lineHeight) + epsilon); 
        }
 
        /// 
        /// Return the index of the last line that is currently visible in the TextBox.
        /// 
        /// 0-based index of the last visible line, or -1 if no layout information is available 
        public int GetLastVisibleLineIndex()
        { 
            double height; 

            if (this.RenderScope == null) 
            {
                return -1;
            }
 
            height = ((IScrollInfo)this.RenderScope).ExtentHeight;
 
            if (this.VerticalOffset + this.ViewportHeight >= height) 
            {
                return this.LineCount - 1; 
            }
            else
            {
                return (int)Math.Floor((this.VerticalOffset + this.ViewportHeight - 1) / GetLineHeight()); 
            }
        } 
 
        /// 
        /// Scroll the minimal amount necessary to bring the given line into full view. 
        /// 
        /// line to scroll into view
        public void ScrollToLine(int lineIndex)
        { 
            if (this.RenderScope == null)
            { 
                return; 
            }
 
            if (lineIndex < 0 || lineIndex >= LineCount)
            {
                throw new ArgumentOutOfRangeException("lineIndex");
            } 

            TextPointer textPointer = GetStartPositionOfLine(lineIndex); 
            Rect rect; 
            if (GetRectangleFromTextPositionInternal(textPointer, false, out rect))
            { 
                this.RenderScope.BringIntoView(rect);
            }
        }
 
        /// 
        /// Get the text displayed at the given line. 
        ///  
        /// 0-based index of the desired line
        /// String containing a copy of the text at the given line index, or null if no layout information 
        /// is available
        public String GetLineText(int lineIndex)
        {
            string text; 
            TextPointer startOfLine;
            TextPointer endOfLine; 
 
            if (this.RenderScope == null)
            { 
                return null; // sentinel value
            }

            if (lineIndex < 0 || lineIndex >= LineCount) 
            {
                throw new ArgumentOutOfRangeException("lineIndex"); 
            } 

            startOfLine = GetStartPositionOfLine(lineIndex); 
            endOfLine = GetEndPositionOfLine(lineIndex);

            // startOfLine/endOfLine will be null if no layout is available.
            if (startOfLine != null && endOfLine != null) 
            {
                text = TextRangeBase.GetTextInternal(startOfLine, endOfLine); 
            } 
            else
            { 
                text = this.Text;
            }

            return text; 
        }
 
        ///  
        /// Get the rectangle for the leading edge of the character at the given index.
        ///  
        /// index of the desired character
        /// leading edge rectangle of the given character, or Rect.Empty if no layout information is available.
        public Rect GetRectFromCharacterIndex(int charIndex)
        { 
            return GetRectFromCharacterIndex(charIndex, /*trailingEdge*/false);
        } 
 
        /// 
        /// Get the rectangle for an edge of the character at the given index. 
        /// 
        /// index of the desired character
        /// specifies an edge of the character bounding box
        /// leading or trailing edge rectangle of the given character, or Rect.Empty if no layout information is available. 
        public Rect GetRectFromCharacterIndex(int charIndex, bool trailingEdge)
        { 
            if (charIndex < 0 || charIndex > this.TextContainer.SymbolCount) 
            {
                throw new ArgumentOutOfRangeException("charIndex"); 
            }

            // Start by moving to an insertion position in backward direction.
            // This ensures that when the character at charIndex is part of a surrogate pair or multi-byte character, 
            // we handle leading/trailing edge correctly.
 
            TextPointer textPointer = TextContainer.CreatePointerAtOffset(charIndex, LogicalDirection.Backward); 
            textPointer = textPointer.GetInsertionPosition(LogicalDirection.Backward);
 
            if (trailingEdge && charIndex < this.TextContainer.SymbolCount)
            {
                // Get next insertion position
                textPointer = textPointer.GetNextInsertionPosition(LogicalDirection.Forward); 
                Invariant.Assert(textPointer != null);
 
                // Backward gravity for trailing edge 
                textPointer = textPointer.GetPositionAtOffset(0, LogicalDirection.Backward);
            } 
            else
            {
                // Forward gravity for leading edge
                textPointer = textPointer.GetPositionAtOffset(0, LogicalDirection.Forward); 
            }
 
            // NB: rect will be Rect.Empty if no layout is available. 
            Rect rect;
            GetRectangleFromTextPositionInternal(textPointer, /*relativeToTextBox*/true, out rect); 
            return rect;
        }

        ///  
        /// Returns the associated IndexedSpellingError at a specified character index.
        ///  
        ///  
        /// Index of text to query.
        ///  
        /// 
        /// The charIndex paramter specifies a character to query.
        /// If the specificed character is not part of a misspelled word (or if
        /// IsSpellCheckEnabled == false) then this method will return null. 
        /// 
        public SpellingError GetSpellingError(int charIndex) 
        { 
            if (charIndex < 0 || charIndex > this.TextContainer.SymbolCount)
            { 
                throw new ArgumentOutOfRangeException("charIndex");
            }

            TextPointer position = this.TextContainer.CreatePointerAtOffset(charIndex, LogicalDirection.Forward); 
            SpellingError spellingError = this.TextEditor.GetSpellingErrorAtPosition(position, LogicalDirection.Forward);
 
            if (spellingError == null && charIndex < this.TextContainer.SymbolCount - 1) 
            {
                position = this.TextContainer.CreatePointerAtOffset(charIndex + 1, LogicalDirection.Forward); 
                spellingError = this.TextEditor.GetSpellingErrorAtPosition(position, LogicalDirection.Backward);
            }

            return spellingError; 
        }
 
        ///  
        /// Returns the start index of the first character of a spelling error
        /// containing a specified char. 
        /// 
        /// 
        /// Index of the character to query.
        ///  
        /// 
        /// Start index of the spelling error containing a specified char, or -1 if 
        /// the char is not part of a spelling error. 
        /// 
        public int GetSpellingErrorStart(int charIndex) 
        {
            SpellingError spellingError = GetSpellingError(charIndex);

            return (spellingError == null) ? -1 : spellingError.Start.Offset; 
        }
 
        ///  
        /// Returns the length of the spelling error containing a specified char.
        ///  
        /// 
        /// Index of the character to query.
        /// 
        ///  
        /// Length of the spelling error containing a specified char, or 0 if
        /// the char is not part of a spelling error. 
        ///  
        public int GetSpellingErrorLength(int charIndex)
        { 
            SpellingError spellingError = GetSpellingError(charIndex);

            return (spellingError == null) ? 0 : spellingError.End.Offset - spellingError.Start.Offset;
        } 

        ///  
        /// Returns the index of the next character in a specificed direction 
        /// that is the start of a misspelled word.
        ///  
        /// 
        /// Index of text to query.
        /// 
        ///  
        /// Direction to query.
        ///  
        ///  
        /// The charIndex paramter specifies a character at which to start the query.
        /// When direction == LogicalDirection.Forward, the search includes the 
        /// spelling error containing charIndex (if any).
        /// When direction == LogicalDirection.Backward, the search does not
        /// include the error containing charIndex (if any).
        /// 
        /// If no misspelled word is encountered, the method returns -1.
        ///  
        public int GetNextSpellingErrorCharacterIndex(int charIndex, LogicalDirection direction) 
        {
            if (charIndex < 0 || charIndex > this.TextContainer.SymbolCount) 
            {
                throw new ArgumentOutOfRangeException("charIndex");
            }
 
            if (this.TextContainer.SymbolCount == 0)
            { 
                // Early out on an empty doc to keep logic simpler below. 
                return -1;
            } 

            ITextPointer position = this.TextContainer.CreatePointerAtOffset(charIndex, direction);

            position = this.TextEditor.GetNextSpellingErrorPosition(position, direction); 

            return (position == null) ? -1 : position.Offset; 
        } 

        #endregion Public Methods 

        //-----------------------------------------------------
        //
        //  Public Properties 
        //
        //------------------------------------------------------ 
 
        #region Public Properties
 
        /// 
        /// DependencyProperty for  property.
        /// 
        public static readonly DependencyProperty TextWrappingProperty = 
                TextBlock.TextWrappingProperty.AddOwner(
                        typeof(TextBox), 
                        new FrameworkPropertyMetadata( 
                                TextWrapping.NoWrap,
                                FrameworkPropertyMetadataOptions.AffectsMeasure, 
                                new PropertyChangedCallback(OnTextWrappingChanged)));

        /// 
        /// The TextWrapping property controls whether or not text wraps 
        /// when it reaches the flow edge of its containing block box.
        ///  
        public TextWrapping TextWrapping 
        {
            get 
            {
                return (TextWrapping)GetValue(TextWrappingProperty);
            }
            set 
            {
                SetValue(TextWrappingProperty, value); 
            } 
        }
 
        /// 
        /// Dependency ID for the MinLines property
        /// Default value: 1
        ///  
        public static readonly DependencyProperty MinLinesProperty =
                DependencyProperty.Register( 
                        "MinLines", // Property name 
                        typeof(int), // Property type
                        typeof(TextBox), // Property owner 
                        new FrameworkPropertyMetadata(
                                1,
                                FrameworkPropertyMetadataOptions.AffectsMeasure,
                                new PropertyChangedCallback(OnMinMaxChanged)), 
                        new ValidateValueCallback(MinLinesValidateValue));
 
        ///  
        /// Minimum number of lines to size to.
        ///  
        [DefaultValue(1)]
        public int MinLines
        {
            get { return (int) GetValue(MinLinesProperty); } 
            set { SetValue(MinLinesProperty, value); }
        } 
 
        /// 
        /// Dependency ID for the MaxLines property 
        /// Default value: MaxInt
        /// 
        public static readonly DependencyProperty MaxLinesProperty =
                DependencyProperty.Register( 
                        "MaxLines", // Property name
                        typeof(int), // Property type 
                        typeof(TextBox), // Property owner 
                        new FrameworkPropertyMetadata(
                                Int32.MaxValue, 
                                FrameworkPropertyMetadataOptions.AffectsMeasure,
                                new PropertyChangedCallback(OnMinMaxChanged)),
                        new ValidateValueCallback(MaxLinesValidateValue));
 
        /// 
        /// Minimum number of lines to size to. 
        ///  
        [DefaultValue(Int32.MaxValue)]
        public int MaxLines 
        {
            get { return (int) GetValue(MaxLinesProperty); }
            set { SetValue(MaxLinesProperty, value); }
        } 

        ///  
        /// The DependencyID for the Text property. 
        /// Default Value:      ""
        ///  
        public static readonly DependencyProperty TextProperty =
                DependencyProperty.Register(
                        "Text", // Property name
                        typeof(string), // Property type 
                        typeof(TextBox), // Property owner
                        new FrameworkPropertyMetadata( // Property metadata 
                                string.Empty, // default value 
                                FrameworkPropertyMetadataOptions.BindsTwoWayByDefault | // Flags
                                    FrameworkPropertyMetadataOptions.Journal, 
                                new PropertyChangedCallback(OnTextPropertyChanged),    // property changed callback
                                new CoerceValueCallback(CoerceText),
                                true, // IsAnimationProhibited
                                UpdateSourceTrigger.LostFocus   // DefaultUpdateSourceTrigger 
                                ));
 
        ///  
        /// Contents of the TextBox.
        ///  
        [DefaultValue("")]
        [Localizability(LocalizationCategory.Text)]
        public string Text
        { 
            get { return (string) GetValue(TextProperty); }
            set { SetValue(TextProperty, value); } 
        } 

        ///  
        /// The DependencyID for the CharacterCasing property.
        /// Controls whether or not input text is converted to upper or lower case
        /// Flags:              Can be used in style rules
        /// Default Value:      CharacterCasing.Normal 
        /// 
        public static readonly DependencyProperty CharacterCasingProperty = 
                DependencyProperty.Register( 
                        "CharacterCasing", // Property name
                        typeof(CharacterCasing), // Property type 
                        typeof(TextBox), // Property owner
                        new FrameworkPropertyMetadata(CharacterCasing.Normal /*default value*/),
                        new ValidateValueCallback(CharacterCasingValidateValue) /*validation callback*/);
 
        /// 
        /// Character casing of the TextBox 
        ///  
        public CharacterCasing CharacterCasing
        { 
            get { return (CharacterCasing) GetValue(CharacterCasingProperty); }
            set { SetValue(CharacterCasingProperty, value); }
        }
 
        /// 
        /// The limit number of characters that the textbox or other editable controls can contain. 
        /// if it is 0, means no-limitation. 
        /// User can set this value for some simple single line textbox to restrict the text number.
        /// RichTextBox doesn't have this limitation. 
        /// By default it is 0.
        /// 
        /// 
        /// When this property is set to zero, the maximum length of the text that can be entered 
        /// in the control is limited only by available memory. You can use this property to restrict
        /// the length of text entered in the control for values such as postal codes and telephone numbers. 
        /// You can also use this property to restrict the length of text entered when the data is to be entered 
        /// in a database.
        /// You can limit the text entered into the control to the maximum length of the corresponding field in the database. 
        /// Note:   In code, you can set the value of the Text property to a value that is larger than
        /// the value specified by the MaxLength property.
        /// This property only affects text entered into the control at runtime.
        ///  
        public static readonly DependencyProperty MaxLengthProperty =
                DependencyProperty.Register( 
                    "MaxLength", // Property name 
                    typeof(int), // Property type
                    typeof(TextBox), // Property owner 
                    new FrameworkPropertyMetadata(0), /*default value*/
                    new ValidateValueCallback(MaxLengthValidateValue));

 
        /// 
        /// Maximum number of characters the TextBox can accept 
        ///  
        [DefaultValue((int)0)]
        [Localizability(LocalizationCategory.None, Modifiability = Modifiability.Unmodifiable)] // cannot be modified by localizer 
        public int MaxLength
        {
            get { return (int) GetValue(MaxLengthProperty); }
            set { SetValue(MaxLengthProperty, value); } 
        }
 
        ///  
        /// DependencyProperty for  property.
        ///  
        public static readonly DependencyProperty TextAlignmentProperty = Block.TextAlignmentProperty.AddOwner(typeof(TextBox));

        /// 
        /// The TextAlignment property specifies horizontal alignment of the content. 
        /// 
        public TextAlignment TextAlignment 
        { 
            get
            { 
                return (TextAlignment)GetValue(TextAlignmentProperty);
            }
            set
            { 
                SetValue(TextAlignmentProperty, value);
            } 
        } 

        ///  
        /// Selected Text
        /// 
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public string SelectedText 
        {
            get 
            { 
                return TextSelectionInternal.Text;
            } 
            set
            {
                using (this.TextSelectionInternal.DeclareChangeBlock())
                { 
                    TextSelectionInternal.Text = value;
                } 
            } 
        }
 
        /// 
        /// Character number of the selected text
        /// 
        ///  
        /// Length is calculated as unicode count, so it counts
        /// eacn \r\n combination as 2 - even though it is actially 
        /// one caret position, and it would be illegal to insert 
        /// any characters between them or expect selection ends
        /// to stay between them. 
        /// Because of that after setting SelectionLength to some value
        /// it can be automatically corrected (by adding 1)
        /// if selection end happens to be between \r and \n.
        ///  
        [DefaultValue((int)0)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] 
        public int SelectionLength 
        {
            get 
            {
                return TextSelectionInternal.Start.GetOffsetToPosition(TextSelectionInternal.End);
            }
            set 
            {
                if (value < 0) 
                { 
                    throw new ArgumentOutOfRangeException("value", SR.Get(SRID.ParameterCannotBeNegative));
                } 

                // Identify new position for selection end
                int maxLength = TextSelectionInternal.Start.GetOffsetToPosition(TextContainer.End);
                if (value > maxLength) 
                {
                    value = maxLength; 
                } 
                TextPointer newEnd = new TextPointer(TextSelectionInternal.Start, value, LogicalDirection.Forward);
 
                // Normalize end in some particular direction to exclude ambiguity on surrogate boundaries
                newEnd = newEnd.GetInsertionPosition(LogicalDirection.Forward);

                // Set new selection 
                TextSelectionInternal.Select(TextSelectionInternal.Start, newEnd);
            } 
        } 

        ///  
        /// The start position of the selection.
        /// 
        /// 
        /// Index is calculated as unicode offset, so it counts 
        /// eacn \r\n combination as 2 - even though it is actially
        /// one caret position, and it would be illegal to insert 
        /// any characters between them or expect selection ends 
        /// to stay between them.
        /// Because of that after setting SelectionStart to some value 
        /// it can be automatically corrected (by adding 1)
        /// if it happens to be between \r and \n.
        /// 
        [DefaultValue((int)0)] 
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public int SelectionStart 
        { 
            get
            { 
                return this.TextSelectionInternal.Start.Offset;
            }
            set
            { 
                if (value < 0)
                { 
                    throw new ArgumentOutOfRangeException("value", SR.Get(SRID.ParameterCannotBeNegative)); 
                }
 
                // Store current length of the selection
                int selectionLength = TextSelectionInternal.Start.GetOffsetToPosition(TextSelectionInternal.End);

                // Identify new position for selection Start 
                int maxStart = TextContainer.SymbolCount;
                if (value > maxStart) 
                { 
                    value = maxStart;
                } 
                TextPointer newStart = TextContainer.CreatePointerAtOffset(value, LogicalDirection.Forward);

                // Normalize new start in some particular direction, to exclude ambiguity on surrogates bounndaries
                // and to start counting length from appropriate position. 
                newStart = newStart.GetInsertionPosition(LogicalDirection.Forward);
 
                // Identify new position for selection End 
                int maxLength = newStart.GetOffsetToPosition(TextContainer.End);
                if (selectionLength > maxLength) 
                {
                    selectionLength = maxLength;
                }
                TextPointer newEnd = new TextPointer(newStart, selectionLength, LogicalDirection.Forward); 

                // Normalize end in some particular direction to exclude ambiguity on surrogate boundaries 
                newEnd = newEnd.GetInsertionPosition(LogicalDirection.Forward); 

                // Set new selection 
                TextSelectionInternal.Select(newStart, newEnd);
            }
        }
 
        /// 
        /// Position of the caret. 
        ///  
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public int CaretIndex 
        {
            get
            {
                return SelectionStart; 
            }
 
            set 
            {
                Select(value, 0); 
            }
        }

        ///  
        /// Number of lines in the TextBox.
        ///  
        /// number of lines in the TextBox, or -1 if no layout information is available 
        /// 
        /// If Wrap == true, changing the width of the TextBox may change this value. 
        /// The value returned is the number of lines in the entire TextBox, regardless of how many are
        /// currently in view.
        /// 
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] 
        public int LineCount
        { 
            get 
            {
                if (this.RenderScope == null) 
                {
                    return -1;
                }
 
                return GetLineIndexFromCharacterIndex(this.TextContainer.SymbolCount) + 1;
            } 
        } 

        ///  
        /// DependencyProperty for the TextDecorations property.
        /// 
        public static readonly DependencyProperty TextDecorationsProperty =
                Inline.TextDecorationsProperty.AddOwner( 
                        typeof(TextBox),
                        new FrameworkPropertyMetadata( 
                            new FreezableDefaultValueFactory(TextDecorationCollection.Empty), 
                            FrameworkPropertyMetadataOptions.AffectsRender));
 
        /// 
        /// Property used to apply decorations such as underline to content.
        /// 
        public TextDecorationCollection TextDecorations 
        {
            get { return (TextDecorationCollection)GetValue(TextDecorationsProperty); } 
            set { SetValue(TextDecorationsProperty, value); } 
        }
 

        /// 
        /// Access to all text typography properties.
        ///  
        public Typography Typography
        { 
            get 
            {
                return new Typography(this); 
            }
        }

        #endregion Public Properties 

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

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

        /// 
        /// 
        /// 
        protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e) 
        {
            //  always call base.OnPropertyChanged, otherwise Property Engine will not work. 
            base.OnPropertyChanged(e);

            if (this.RenderScope != null)
            { 
                FrameworkPropertyMetadata fmetadata = e.Property.GetMetadata(typeof(TextBox)) as FrameworkPropertyMetadata;
                if (fmetadata != null) 
                { 
                    if (e.IsAValueChange || e.IsASubPropertyChange)
                    { 
                        if (fmetadata.AffectsMeasure || fmetadata.AffectsArrange ||
                            fmetadata.AffectsParentMeasure || fmetadata.AffectsParentArrange ||
                            e.Property == Control.HorizontalContentAlignmentProperty || e.Property == Control.VerticalContentAlignmentProperty)
                        { 
                            ((TextBoxView)this.RenderScope).Remeasure();
                        } 
                        else if (fmetadata.AffectsRender && 
                                (e.IsAValueChange || !fmetadata.SubPropertiesDoNotAffectRender))
                        { 
                            ((TextBoxView)this.RenderScope).Rerender();
                        }

                        if (Speller.IsSpellerAffectingProperty(e.Property) && 
                            this.TextEditor.Speller != null)
                        { 
                            this.TextEditor.Speller.ResetErrors(); 
                        }
                    } 
                }
            }

            TextBoxAutomationPeer peer = UIElementAutomationPeer.FromElement(this) as TextBoxAutomationPeer; 
            if (peer != null)
            { 
                if (e.Property == TextProperty) 
                {
                    peer.RaiseValuePropertyChangedEvent((string)e.OldValue, (string)e.NewValue); 
                }

                if (e.Property == IsReadOnlyProperty)
                { 
                    peer.RaiseIsReadOnlyPropertyChangedEvent((bool)e.OldValue, (bool)e.NewValue);
                } 
            } 
        }
 
        /// 
        /// Returns enumerator to logical children.
        /// 
        protected internal override IEnumerator LogicalChildren 
        {
            get 
            { 
                //
 

                return new RangeContentEnumerator((TextPointer)this.TextContainer.Start, (TextPointer)this.TextContainer.End);
            }
        } 

        ///  
        /// Measurement override. Implement your size-to-content logic here. 
        /// 
        ///  
        /// Sizing constraint.
        /// 
        protected override Size MeasureOverride(Size constraint)
        { 
            if (MinLines > 1 && MaxLines < MinLines)
            { 
                throw new Exception(SR.Get(SRID.TextBoxMinMaxLinesMismatch)); 
            }
 
            Size size = base.MeasureOverride(constraint);

            if (_minmaxChanged)
            { 
                // If there is a scrollViewer, we'll listen to the ScrollChanged event and
                // handle min/maxLines there. 
                if (this.ScrollViewer == null) 
                {
                    SetRenderScopeMinMaxHeight(); 
                }
                else
                {
                    SetScrollViewerMinMaxHeight(); 
                }
                _minmaxChanged = false; 
            } 

            return size; 
        }

        // Called every time after Wrap property gets new value
        internal void OnTextWrappingChanged() 
        {
            CoerceValue(HorizontalScrollBarVisibilityProperty); 
        } 

        // Allocates the initial render scope for this control. 
        internal override FrameworkElement CreateRenderScope()
        {
            return new TextBoxView(this);
        } 

        #endregion Protected Methods 
 
        //-----------------------------------------------------
        // 
        //  Internal Methods
        //
        //------------------------------------------------------
 
        #region Internal Methods
 
        ///  
        /// Detaches the editor from old visual tree and attaches it to a new one
        ///  
        internal override void AttachToVisualTree()
        {
            base.AttachToVisualTree();
 
            if (this.RenderScope == null)
            { 
                return; 
            }
 
            // Set TextWrapping property for the new renderScope
            OnTextWrappingChanged();

            // We need to recalculate our min/max story. 
            _minmaxChanged = true;
        } 
 
        /// 
        ///     Gives a string representation of this object. 
        /// 
        internal override string GetPlainText()
        {
            return this.Text; 
        }
 
        /// 
        // 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;
            } 
        } 

        ///  
        /// Scroll content by one line to the top.
        /// 
        internal override void DoLineUp()
        { 
            if (this.ScrollViewer != null)
            { 
                ScrollViewer.ScrollToVerticalOffset(VerticalOffset - GetLineHeight()); 
            }
        } 

        /// 
        /// Scroll content by one line to the bottom.
        ///  
        internal override void DoLineDown()
        { 
            if (this.ScrollViewer != null) 
            {
                ScrollViewer.ScrollToVerticalOffset(VerticalOffset + GetLineHeight()); 
            }
        }

        ///  
        /// Handler for TextContainer.Changed event.
        ///  
        internal override void OnTextContainerChanged(object sender, TextContainerChangedEventArgs e) 
        {
            // Ignore property changes that originate from OnTextPropertyChange. 
            if (!_isInsideTextContentChange)
            {
                _isInsideTextContentChange = true;
                try 
                {
                    // Use a DeferredTextReference instead of calculating the new 
                    // value now for better performance.  Most of the time no 
                    // one cares what the new is, and loading our content into a
                    // string can be extremely expensive. 
                    SetDeferredValue(TextProperty, new DeferredTextReference(this.TextContainer));
                }
                finally
                { 
                    _isInsideTextContentChange = false;
                } 
            } 

            // Let base raise the public TextBoxBase.TextChanged event. 
            base.OnTextContainerChanged(sender, e);
        }

        ///  
        /// Handler for ScrollViewer's OnScrollChanged event.
        ///  
        internal override void OnScrollChanged(object sender, ScrollChangedEventArgs e) 
        {
            base.OnScrollChanged(sender, e); 

            if (e.ViewportHeightChange != 0)
            {
                SetScrollViewerMinMaxHeight(); 
            }
        } 
 
        //
        //  This property 
        //  1. Finds the correct initial size for the _effectiveValues store on the current DependencyObject
        //  2. This is a performance optimization
        //
        internal override int EffectiveValuesInitialSize 
        {
            get { return 42; } 
        } 

        #endregion Internal methods 

        //-----------------------------------------------------
        //
        //  Internal Properties 
        //
        //------------------------------------------------------ 
 
        #region Internal Properties
 
        /// 
        /// Text Selection (readonly)
        /// 
        internal TextSelection Selection 
        {
            get 
            { 
                return (TextSelection)TextSelectionInternal;
            } 
        }

        /// 
        /// TextPointer where the TextBox's text begins (readonly) 
        /// 
        internal TextPointer StartPosition 
        { 
            get
            { 
                return (TextPointer)this.TextContainer.Start;
            }
        }
 
        /// 
        /// TextPointer where the TextBox's text ends (readonly) 
        ///  
        internal TextPointer EndPosition
        { 
            get
            {
                return (TextPointer)this.TextContainer.End;
            } 
        }
 
        ///  
        /// IsTypographyDefaultValue
        ///  
        internal bool IsTypographyDefaultValue
        {
            get
            { 
                return !_isTypographySet;
            } 
        } 

        // ITextContainer holding the Control content. 
        ITextContainer ITextBoxViewHost.TextContainer
        {
            get
            { 
                return this.TextContainer;
            } 
        } 

        // Set true when typography property values are all default values. 
        bool ITextBoxViewHost.IsTypographyDefaultValue
        {
            get
            { 
                return this.IsTypographyDefaultValue;
            } 
        } 

        #endregion Internal Properties 

        //------------------------------------------------------
        //
        //  Private Methods 
        //
        //----------------------------------------------------- 
 
        #region Private Methods
 
        // Returns false if no layout is available.
        private bool GetRectangleFromTextPositionInternal(TextPointer position, bool relativeToTextBox, out Rect rect)
        {
            if (this.RenderScope == null) 
            {
                rect = Rect.Empty; 
                return false; 
            }
 
            if (position.ValidateLayout())
            {
                rect = TextPointerBase.GetCharacterRect(position, position.LogicalDirection, relativeToTextBox);
            } 
            else
            { 
                rect = Rect.Empty; 
            }
 
            return rect != Rect.Empty;
        }

        // Returns null if no layout is available. 
        private TextPointer GetStartPositionOfLine(int lineIndex)
        { 
            if (this.RenderScope == null) 
            {
                return null; 
            }

            Point point = new Point();
 
            // all lines in TextBox are the same height, so get the line height and multiply...
            double lineHeight = GetLineHeight(); 
            point.Y = lineHeight * lineIndex + (lineHeight / 2) - VerticalOffset;  // use a point in the middle of the line, to be safe 
            point.X = -HorizontalOffset;
 
            TextPointer textPointer;

            if (TextEditor.GetTextView(this.RenderScope).Validate(point))
            { 
                textPointer = (TextPointer)TextEditor.GetTextView(this.RenderScope).GetTextPositionFromPoint(point, /* snap to text */ true);
                textPointer = (TextPointer)TextEditor.GetTextView(this.RenderScope).GetLineRange(textPointer).Start.CreatePointer(textPointer.LogicalDirection); 
            } 
            else
            { 
                textPointer = null;
            }

            return textPointer; 
        }
 
        private TextPointer GetEndPositionOfLine(int lineIndex) 
        {
            if (this.RenderScope == null) 
            {
                return null;
            }
 
            // all lines in TextBox are the same height, so get the line height and multiply...
            Point point = new Point(); 
 
            double lineHeight = GetLineHeight();
            point.Y = lineHeight * lineIndex + (lineHeight / 2) - VerticalOffset;  // use a point in the middle of the line, to be safe 
            point.X = 0;

            TextPointer textPointer;
 
            if (TextEditor.GetTextView(this.RenderScope).Validate(point))
            { 
                textPointer = (TextPointer)TextEditor.GetTextView(this.RenderScope).GetTextPositionFromPoint(point, /* snap to text */ true); 
                textPointer = (TextPointer)TextEditor.GetTextView(this.RenderScope).GetLineRange(textPointer).End.CreatePointer(textPointer.LogicalDirection);
 
                // Hit testing ignores line breaks, so the position returned will be between the last visible character
                // and the line break, if any.  We want the position AFTER the line break.
                if (TextPointerBase.IsNextToPlainLineBreak(textPointer, LogicalDirection.Forward))
                { 
                    textPointer.MoveToNextInsertionPosition(LogicalDirection.Forward);
                } 
            } 
            else
            { 
                textPointer = null;
            }

            return textPointer; 
        }
 
        private static object CoerceHorizontalScrollBarVisibility(DependencyObject d, object value) 
        {
            TextBox textBox = d as TextBox; 

            if (textBox != null && (textBox.TextWrapping == TextWrapping.Wrap || textBox.TextWrapping == TextWrapping.WrapWithOverflow))
            {
                return ScrollBarVisibility.Disabled; 
            }
            return value; 
        } 

        ///  
        /// 
        /// 
        private static bool MaxLengthValidateValue(object value)
        { 
            return ((int)value) >= 0;
        } 
 
        /// 
        ///  
        /// 
        private static bool CharacterCasingValidateValue(object value)
        {
            return (CharacterCasing.Normal <= (CharacterCasing)value && (CharacterCasing)value <= CharacterCasing.Upper); 
        }
 
        ///  
        /// 
        ///  
        private static bool MinLinesValidateValue(object value)
        {
            return ((int)value > 0);
        } 

        ///  
        ///  
        /// 
        private static bool MaxLinesValidateValue(object value) 
        {
            return ((int)value > 0);
        }
 
        /// 
        /// Callback for changes to the MinLines and MaxLines property 
        ///  
        private static void OnMinMaxChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        { 
            TextBox textBox = (TextBox)d;

            textBox._minmaxChanged = true;
        } 

        ///  
        /// Callback for changes to the Text property 
        /// 
        private static void OnTextPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
        {
            TextBox textBox = (TextBox)d;

            if (textBox._isInsideTextContentChange) 
            {
                // Ignore property changes that originate from OnTextContainerChanged. 
                return; 
            }
 
            // CoerceText will have already converted null -> String.Empty,
            // but our default CoerceValueCallback could be overridden by a
            // derived class.  So check again here.
            string newText = (string)e.NewValue; 
            if (newText == null)
            { 
                newText = String.Empty; 
            }
 
            textBox._isInsideTextContentChange = true;
            try
            {
                using (textBox.TextSelectionInternal.DeclareChangeBlock()) 
                {
                    // Update the text content with new TextProperty value. 
                    textBox.TextContainer.DeleteContentInternal((TextPointer)textBox.TextContainer.Start, (TextPointer)textBox.TextContainer.End); 
                    textBox.TextContainer.End.InsertTextInRun(newText);
                    // Collapse selection to the beginning of a text box 
                    textBox.Select(0, 0);
                }
            }
            finally 
            {
                // 
 

                textBox._isInsideTextContentChange = false; 
            }

            // We need to clear undo stack in case when the value comes from
            // databinding or some other expression. 
            if (textBox.HasExpression(textBox.LookupEntry(TextBox.TextProperty.GlobalIndex), TextBox.TextProperty))
            { 
                UndoManager undoManager = textBox.TextEditor._GetUndoManager(); 
                undoManager.Clear();
            } 
        }

        /// 
        /// Callback for changes to the TextWrapping property 
        /// 
        private static void OnTextWrappingChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
        { 
            if (d is TextBox)
            { 
                ((TextBox)d).OnTextWrappingChanged();
            }
        }
 
        /// 
        /// Update the value of ScrollViewer.MinHeight/MaxHeight 
        ///  
        private void SetScrollViewerMinMaxHeight()
        { 
            if (this.RenderScope == null)
            {
                return;
            } 

            if (ReadLocalValue(HeightProperty) != DependencyProperty.UnsetValue || 
                ReadLocalValue(MaxHeightProperty) != DependencyProperty.UnsetValue || 
                ReadLocalValue(MinHeightProperty) != DependencyProperty.UnsetValue)
            { 
                // scrub ScrollViewer's min/max height if any height values are set on TextBox
                this.ScrollViewer.ClearValue(MinHeightProperty);
                this.ScrollViewer.ClearValue(MaxHeightProperty);
                return; 
            }
 
            double chrome = this.ScrollViewer.ActualHeight - ViewportHeight; 
            double lineHeight = GetLineHeight();
            double value = chrome + (lineHeight * MinLines); 

            if (MinLines > 1 && this.ScrollViewer.MinHeight != value)
            {
                this.ScrollViewer.MinHeight = value; 
            }
 
            value = chrome + (lineHeight * MaxLines); 

            if (MaxLines < Int32.MaxValue && this.ScrollViewer.MaxHeight != value) 
            {
                this.ScrollViewer.MaxHeight = value;
            }
        } 

 
        ///  
        /// Update the value of RenderScope.MinHeight/MaxHeight
        ///  
        private void SetRenderScopeMinMaxHeight()
        {
            if (this.RenderScope == null)
            { 
                return;
            } 
 
            if (ReadLocalValue(HeightProperty) != DependencyProperty.UnsetValue ||
                ReadLocalValue(MaxHeightProperty) != DependencyProperty.UnsetValue || 
                ReadLocalValue(MinHeightProperty) != DependencyProperty.UnsetValue)
            {
                RenderScope.ClearValue(MinHeightProperty);
                RenderScope.ClearValue(MaxHeightProperty); 
            }
            else 
            { 
                double lineHeight = GetLineHeight();
                double value = lineHeight * MinLines; 

                if (MinLines > 1 && RenderScope.MinHeight != value)
                {
                    RenderScope.MinHeight = value; 
                }
 
                value = lineHeight * MaxLines; 

                if (MaxLines < Int32.MaxValue && RenderScope.MaxHeight != value) 
                {
                    RenderScope.MaxHeight = value;
                }
            } 
        }
 
        // 
        // Called by MeasureOverride to get the height of one line of text in the current font.
        // 
        private double GetLineHeight()
        {
            // change Text height based on line size
            FontFamily fontFamily = (FontFamily)this.GetValue(FontFamilyProperty); 
            double fontSize = (double)this.GetValue(TextElement.FontSizeProperty);
 
            // If Ps Task 25254 is completed (not likely in V1), LineStackingStrategy 
            // won't be constant and we'll need to call some sort of CalcLineAdvance method.
            return fontFamily.LineSpacing * fontSize; 
        }


        // 
        // Only serialize Text when not using the XamlTextHostSerializer
        // 
        ///  
        /// This method is used by TypeDescriptor to determine if this property should
        /// be serialized. 
        /// 
        [EditorBrowsable(EditorBrowsableState.Never)]
        public bool ShouldSerializeText(XamlDesignerSerializationManager manager)
        { 
            return manager.XmlWriter == null;
        } 
 
        //
        // Callback for command system to verify that the LineUp / LineDown commands should be enabled. 
        // ScrollViewer always returns true, so we follow suit.
        //
        private static void OnQueryScrollCommand(object target, CanExecuteRoutedEventArgs args)
        { 
            args.CanExecute = true;
        } 
 
        // Callback from the property system, after a new value is set to the TextProperty.
        // Note we cannot assume value is a string here -- it may be a DeferredTextReference. 
        private static object CoerceText(DependencyObject d, object value)
        {
            if (value == null)
            { 
                return String.Empty;
            } 
 
            return value;
        } 

        //  typography properties changed, no cache for this, just reset the flag
        private static void OnTypographyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        { 
            TextBox textbox = (TextBox)d;
 
            textbox._isTypographySet = true; 
        }
 
        #endregion Private methods

        //------------------------------------------------------
        // 
        //  Private Fields
        // 
        //----------------------------------------------------- 

        #region Private Fields 

        private static DependencyObjectType _dType;

        // 

        // This flag is set when the MinLines or MaxLines properties are invalidated, and 
        // checked in MeasureOverride.  When true, MeasureOverride calls SetMinMaxHeight to 
        // make sure the change in min/max height happens immediately.
        private bool _minmaxChanged; 

        // Flag used to prevent reentrancy between nested
        // OnTextPropertyChanged/OnTextContainerChanged callbacks.
        private bool _isInsideTextContentChange; 

        // Flag used to indicate that Typography properties are not at default values 
        private bool _isTypographySet; 

        #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