TextBox.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / wpf / src / Framework / System / Windows / Controls / TextBox.cs / 1599981 / 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");
            } 

            int line;
            TextPointer position = this.TextContainer.CreatePointerAtOffset(charIndex, LogicalDirection.Forward);
 
            if (position.ValidateLayout())
            { 
                TextBoxView textboxView = (TextBoxView)this.RenderScope; 
                line = textboxView.GetLineIndexFromOffset(charIndex);
            } 
            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)
                { 
                    // We need to check for TextAlignmentProperty specifically since a local value change might require a render 
                    // update even though e.IsAValueChange is false (see TextBoxView.CalculatedTextAlignment).
                    if (e.IsAValueChange || e.IsASubPropertyChange || e.Property == TextBox.TextAlignmentProperty) 
                    {
                        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)
        { 
            try
            {
                // if there are re-entrant changes, only raise public events
                // after the outermost change completes 
                _changeEventNestingCount++;
 
                // Ignore property changes that originate from OnTextPropertyChange. 
                if (!_isInsideTextContentChange)
                { 
                    _isInsideTextContentChange = true;

                    // Use a DeferredTextReference instead of calculating the new
                    // value now for better performance.  Most of the time no 
                    // one cares what the new value is, and loading our content into a
                    // string can be extremely expensive. 
                    DeferredTextReference dtr = new DeferredTextReference(this.TextContainer); 
                    _newTextValue = dtr;
                    SetCurrentDeferredValue(TextProperty, dtr); 
                }
            }
            finally
            { 
                _changeEventNestingCount--;
                if (_changeEventNestingCount == 0) 
                { 
                    _isInsideTextContentChange = false;
                    _newTextValue = DependencyProperty.UnsetValue; 
                }
            }

 
            if (_changeEventNestingCount == 0)
            { 
                // Let base raise the public TextBoxBase.TextChanged event. 
                base.OnTextContainerChanged(sender, e);
            } 
        }

        // if the DeferredTextReference is resolved to a string during the previous
        // method, track that here 
        internal void OnDeferredTextReferenceResolved(DeferredTextReference dtr, string s)
        { 
            if (dtr == _newTextValue) 
            {
                _newTextValue = s; 
            }
        }

        ///  
        /// 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;
            bool inReentrantChange = false;
            int savedCaretIndex = 0; 

            if (textBox._isInsideTextContentChange) 
            { 
                // Ignore property changes that originate from OnTextContainerChanged,
                // unless they contain a different value (indicating that a 
                // re-entrant call changed the value)
                if (textBox._newTextValue != DependencyProperty.UnsetValue)
                {
                    // OnTextContainerChanged calls 
                    //      SetCurrentDeferredValue(TextProperty, deferredTextReference)
                    // Usually the DeferredTextReference will appear in the new entry 
                    if (textBox._newTextValue is DeferredTextReference) 
                    {
                        if (e.NewEntry.IsDeferredReference && 
                            e.NewEntry.IsCoercedWithCurrentValue &&
                            e.NewEntry.ModifiedValue.CoercedValue == textBox._newTextValue)
                        {
                            return; 
                        }
                    } 
                    // but if the Text property is data-bound, the deferred reference 
                    // gets converted to a real string;  during the conversion (in
                    // DeferredTextReference.GetValue), the TextBox updates _newTextValue 
                    // to be the string.
                    else if (e.NewEntry.IsExpression)
                    {
                        object newValue = e.NewEntry.IsCoercedWithCurrentValue 
                                            ? e.NewEntry.ModifiedValue.CoercedValue
                                            : e.NewEntry.ModifiedValue.ExpressionValue; 
                        if (newValue == textBox._newTextValue) 
                        {
                            return; 
                        }
                    }
                }
 
                // If we get this far, we're being called re-entrantly with a value
                // different from the one set by OnTextContainerChanged.  We should 
                // honor this new value. 
                inReentrantChange = true;
                savedCaretIndex = textBox.CaretIndex; 
            }

            // 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(savedCaretIndex, 0); 
                }
            } 
            finally 
            {
                // 


                if (!inReentrantChange)
                { 
                    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(); 
                if (undoManager != null)
                { 
                    if (undoManager.IsEnabled) 
                        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. 
            double lineHeight;

            if (TextOptions.GetTextFormattingMode(this) == TextFormattingMode.Ideal)
            { 
                lineHeight = fontFamily.LineSpacing * fontSize;
            } 
            else 
            {
                lineHeight = fontFamily.GetLineSpacingForDisplayMode(fontSize); 
            }

            return lineHeight;
        } 

 
        // 
        // 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; 
        private object _newTextValue = DependencyProperty.UnsetValue;
 
        // Flag used to indicate that Typography properties are not at default values
        private bool _isTypographySet;

        // depth of nested calls to OnTextContainerChanged. 
        private int _changeEventNestingCount;
 
        #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