File: winforms\Managed\System\WinForms\TextBox.cs
Project: ndp\fx\src\System.Windows.Forms.csproj (System.Windows.Forms)
//------------------------------------------------------------------------------
// <copyright file="TextBox.cs" company="Microsoft">
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>                                                                
//------------------------------------------------------------------------------
 
/*
 */
namespace System.Windows.Forms {
    using System.Runtime.Remoting;
    using System.ComponentModel;
    using System.Diagnostics;
    using System;
    using System.Security.Permissions;
    using System.Windows.Forms;
    using System.ComponentModel.Design;    
    using System.Drawing;
    using Microsoft.Win32;
    using System.Reflection;
    using System.Text;
    using System.Runtime.InteropServices;
    using System.Collections.Specialized;
    using System.Drawing.Design;
    using System.Security;
    using System.Windows.Forms.VisualStyles;
    
    /// <include file='doc\TextBox.uex' path='docs/doc[@for="TextBox"]/*' />
    /// <devdoc>
    ///    <para>
    ///       Represents a Windows text box control.
    ///    </para>
    /// </devdoc>
 
 
    [
      ClassInterface(ClassInterfaceType.AutoDispatch),
      ComVisible(true),
      Designer("System.Windows.Forms.Design.TextBoxDesigner, " + AssemblyRef.SystemDesign),
      SRDescription(SR.DescriptionTextBox)
    ]
    public class TextBox : TextBoxBase {
    
        private static readonly object EVENT_TEXTALIGNCHANGED = new object();
    
        /// <devdoc>
        ///     Controls whether or not the edit box consumes/respects ENTER key
        ///     presses.  While this is typically desired by multiline edits, this
        ///     can interfere with normal key processing in a dialog.
        /// </devdoc>
        private bool acceptsReturn = false;
 
        /// <devdoc>
        ///     Indicates what the current special password character is.  This is 
        ///     displayed instead of any other text the user might enter.
        /// </devdoc>
        private char passwordChar = (char)0;
 
        private bool useSystemPasswordChar;
 
        /// <devdoc>
        ///     Controls whether or not the case of characters entered into the edit
        ///     box is forced to a specific case.
        /// </devdoc>
        private CharacterCasing characterCasing = System.Windows.Forms.CharacterCasing.Normal;
 
        /// <devdoc>
        ///     Controls which scrollbars appear by default.
        /// </devdoc>
        private ScrollBars scrollBars = System.Windows.Forms.ScrollBars.None;
 
        /// <devdoc>
        ///     Controls text alignment in the edit box.
        /// </devdoc>
        private HorizontalAlignment textAlign = HorizontalAlignment.Left;
        
        /// <devdoc>
        ///     True if the selection has been set by the user.  If the selection has
        ///     never been set and we get focus, we focus all the text in the control
        ///     so we mimic the Windows dialog manager.
        /// </devdoc>
        private bool selectionSet = false;
 
        /// <include file='doc\TextBox.uex' path='docs/doc[@for="TextBox.autoCompleteMode"]/*' />
        /// <devdoc>
        ///     This stores the value for the autocomplete mode which can be either
        ///     None, AutoSuggest, AutoAppend or AutoSuggestAppend.
        /// </devdoc>
        private AutoCompleteMode autoCompleteMode = AutoCompleteMode.None;
        
        /// <include file='doc\TextBox.uex' path='docs/doc[@for="TextBox.autoCompleteSource"]/*' />
        /// <devdoc>
        ///     This stores the value for the autoCompleteSource mode which can be one of the values
        ///     from AutoCompleteSource enum.
        /// </devdoc>
        private AutoCompleteSource autoCompleteSource = AutoCompleteSource.None;
 
        /// <include file='doc\TextBox.uex' path='docs/doc[@for="TextBox.autoCompleteCustomSource"]/*' />
        /// <devdoc>
        ///     This stores the custom StringCollection required for the autoCompleteSource when its set to CustomSource.
        /// </devdoc>
        private AutoCompleteStringCollection autoCompleteCustomSource;
        private bool fromHandleCreate = false;
        private StringSource stringSource = null;
 
        /// <include file='doc\TextBox.uex' path='docs/doc[@for="TextBox.TextBox"]/*' />
        public TextBox(){
        }
 
        
        /// <include file='doc\TextBox.uex' path='docs/doc[@for="TextBox.AcceptsReturn"]/*' />
        /// <devdoc>
        ///    <para>
        ///       Gets or sets a value indicating whether pressing ENTER
        ///       in a multiline <see cref='System.Windows.Forms.TextBox'/>
        ///       control creates a new line of text in the control or activates the default button
        ///       for the form.
        ///    </para>
        /// </devdoc>
        [
        SRCategory(SR.CatBehavior),
        DefaultValue(false),
        SRDescription(SR.TextBoxAcceptsReturnDescr)
        ]
        public bool AcceptsReturn {
            get {
                return acceptsReturn;
            }
 
            set {
                acceptsReturn = value;
            }
        }
 
 
        /// <include file='doc\TextBox.uex' path='docs/doc[@for="TextBox.AutoCompleteMode"]/*' />
        /// <devdoc>
        ///     This is the AutoCompleteMode which can be either
        ///     None, AutoSuggest, AutoAppend or AutoSuggestAppend. 
        ///     This property in conjunction with AutoCompleteSource enables the AutoComplete feature for TextBox.
        /// </devdoc>
        [
        DefaultValue(AutoCompleteMode.None),
        SRDescription(SR.TextBoxAutoCompleteModeDescr),
        Browsable(true), EditorBrowsable(EditorBrowsableState.Always)
        ]
        public AutoCompleteMode AutoCompleteMode {
            get {
                return autoCompleteMode;
            }
            set {
                if (!ClientUtils.IsEnumValid(value, (int)value, (int)AutoCompleteMode.None, (int)AutoCompleteMode.SuggestAppend)){
                    throw new InvalidEnumArgumentException("value", (int)value, typeof(AutoCompleteMode));
                }
                bool resetAutoComplete = false;
                if (autoCompleteMode != AutoCompleteMode.None && value == AutoCompleteMode.None) {
                    resetAutoComplete = true;
                }
                autoCompleteMode = value;
                SetAutoComplete(resetAutoComplete);
            }
        }
 
        /// <include file='doc\TextBox.uex' path='docs/doc[@for="TextBox.AutoCompleteSource"]/*' />
        /// <devdoc>
        ///     This is the AutoCompleteSource which can be one of the 
        ///     values from AutoCompleteSource enumeration. 
        ///     This property in conjunction with AutoCompleteMode enables the AutoComplete feature for TextBox.
        /// </devdoc>
        [
        DefaultValue(AutoCompleteSource.None),
        SRDescription(SR.TextBoxAutoCompleteSourceDescr),
        TypeConverterAttribute(typeof(TextBoxAutoCompleteSourceConverter)),
        Browsable(true), EditorBrowsable(EditorBrowsableState.Always)
        ]
        public AutoCompleteSource AutoCompleteSource {
            get {
                return autoCompleteSource;
            }
            set {
                // FxCop: Avoid usage of Enum.IsDefined - this looks like an enum that could grow
                if (!ClientUtils.IsEnumValid_NotSequential(value, 
                                             (int)value,
                                             (int)AutoCompleteSource.None, 
                                             (int)AutoCompleteSource.AllSystemSources,
                                             (int)AutoCompleteSource.AllUrl,
                                             (int)AutoCompleteSource.CustomSource,
                                             (int)AutoCompleteSource.FileSystem,
                                             (int)AutoCompleteSource.FileSystemDirectories,
                                             (int)AutoCompleteSource.HistoryList,
                                             (int)AutoCompleteSource.ListItems,
                                             (int)AutoCompleteSource.RecentlyUsedList)){   
                    throw new InvalidEnumArgumentException("value", (int)value, typeof(AutoCompleteSource));
                }
                if (value == AutoCompleteSource.ListItems) {
                    throw new NotSupportedException(SR.GetString(SR.TextBoxAutoCompleteSourceNoItems));
                }
 
                // VSWhidbey 466300
                if (value != AutoCompleteSource.None && value != AutoCompleteSource.CustomSource)
                {
                    FileIOPermission fiop = new FileIOPermission(PermissionState.Unrestricted);
                    fiop.AllFiles = FileIOPermissionAccess.PathDiscovery;
                    fiop.Demand();
                }
 
                autoCompleteSource = value;
                SetAutoComplete(false);
            }
        }
 
        /// <include file='doc\TextBox.uex' path='docs/doc[@for="TextBox.AutoCompleteCustomSource"]/*' />
        /// <devdoc>
        ///     This is the AutoCompleteCustomSource which is custom StringCollection used when the 
        ///     AutoCompleteSource is CustomSource. 
        /// </devdoc>
        [
        DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
        Localizable(true),
        SRDescription(SR.TextBoxAutoCompleteCustomSourceDescr),
        Editor("System.Windows.Forms.Design.ListControlStringCollectionEditor, " + AssemblyRef.SystemDesign, typeof(UITypeEditor)),
        Browsable(true), EditorBrowsable(EditorBrowsableState.Always)
        ]
        public AutoCompleteStringCollection AutoCompleteCustomSource {
            get {
                if (autoCompleteCustomSource == null) {
                    autoCompleteCustomSource = new AutoCompleteStringCollection();
                    autoCompleteCustomSource.CollectionChanged += new CollectionChangeEventHandler(this.OnAutoCompleteCustomSourceChanged);
                }
                return autoCompleteCustomSource;
            }
            set {
                if (autoCompleteCustomSource != value) {
                    if (autoCompleteCustomSource != null) {
                        autoCompleteCustomSource.CollectionChanged -= new CollectionChangeEventHandler(this.OnAutoCompleteCustomSourceChanged);
                    }
                    
                    autoCompleteCustomSource = value;
                    
                    if (value != null) {
                        autoCompleteCustomSource.CollectionChanged += new CollectionChangeEventHandler(this.OnAutoCompleteCustomSourceChanged);
                    }
                    SetAutoComplete(false);
                }
                
            }
        }
 
        /// <include file='doc\TextBox.uex' path='docs/doc[@for="TextBox.CharacterCasing"]/*' />
        /// <devdoc>
        ///    <para>
        ///       Gets or sets whether the TextBox control
        ///       modifies the case of characters as they are typed.
        ///    </para>
        /// </devdoc>
        [
        SRCategory(SR.CatBehavior),
        DefaultValue(CharacterCasing.Normal),
        SRDescription(SR.TextBoxCharacterCasingDescr)
        ]
        public CharacterCasing CharacterCasing {
            get {
                return characterCasing;
            }
            set {
                if (characterCasing != value) {
                    //verify that 'value' is a valid enum type...
                    //valid values are 0x0 to 0x2
                    if (!ClientUtils.IsEnumValid(value, (int)value, (int)CharacterCasing.Normal, (int)CharacterCasing.Lower)){
                        throw new InvalidEnumArgumentException("value", (int)value, typeof(CharacterCasing));
                    }
 
                    characterCasing = value;
                    RecreateHandle();
                }
            }
        }
 
        /// <include file='doc\TextBox.uex' path='docs/doc[@for="TextBox.Multiline"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        public override bool Multiline {
            get {
                return base.Multiline;
            }
            set {
                
                if (Multiline != value)
                {
                    base.Multiline = value;
                    if (value && AutoCompleteMode != AutoCompleteMode.None)
                    {
                        RecreateHandle();
                    }
                }
            }
        }
 
        /// <devdoc>
        ///     Determines if the control is in password protect mode.
        /// </devdoc>
        internal override bool PasswordProtect {
            get {
                return this.PasswordChar != '\0';
            }
        }
 
     
        /// <include file='doc\TextBox.uex' path='docs/doc[@for="TextBox.CreateParams"]/*' />
        /// <internalonly/>
        /// <devdoc>
        ///    <para>
        ///       Returns the parameters needed to create the handle. Inheriting classes
        ///       can override this to provide extra functionality. They should not,
        ///       however, forget to call base.getCreateParams() first to get the struct
        ///       filled up with the basic info.
        ///    </para>
        /// </devdoc>
        protected override CreateParams CreateParams {
            [SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.UnmanagedCode)]
            get {
                CreateParams cp = base.CreateParams;
                switch (characterCasing) {
                    case CharacterCasing.Lower:
                        cp.Style |= NativeMethods.ES_LOWERCASE;
                        break;
                    case CharacterCasing.Upper:
                        cp.Style |= NativeMethods.ES_UPPERCASE;
                        break;
                }
 
                // Translate for Rtl if necessary
                //
                HorizontalAlignment align = RtlTranslateHorizontal(textAlign);
                cp.ExStyle &= ~NativeMethods.WS_EX_RIGHT;   // WS_EX_RIGHT overrides the ES_XXXX alignment styles
                switch (align) {
                    case HorizontalAlignment.Left:
                        cp.Style |= NativeMethods.ES_LEFT;
                        break;
                    case HorizontalAlignment.Center:
                        cp.Style |= NativeMethods.ES_CENTER;
                        break;
                    case HorizontalAlignment.Right:
                        cp.Style |= NativeMethods.ES_RIGHT;
                        break;
                }
                
                if (Multiline) {
                    // vs 59731: Don't show horizontal scroll bars which won't do anything
                    if ((scrollBars & ScrollBars.Horizontal) == ScrollBars.Horizontal
                        && textAlign == HorizontalAlignment.Left
                        && !WordWrap) {
                        cp.Style |= NativeMethods.WS_HSCROLL;
                    }
                    if ((scrollBars & ScrollBars.Vertical) == ScrollBars.Vertical) {
                        cp.Style |= NativeMethods.WS_VSCROLL;
                    }
                }
 
                if (useSystemPasswordChar) {
                    cp.Style |= NativeMethods.ES_PASSWORD;
                }
                
                return cp;
            }
        }
 
        /// <include file='doc\TextBox.uex' path='docs/doc[@for="TextBox.PasswordChar"]/*' />
        /// <devdoc>
        ///    <para>
        ///       Gets or sets the character used to mask characters in a single-line text box
        ///       control used to enter passwords.
        ///    </para>
        /// </devdoc>
        [
        SRCategory(SR.CatBehavior),
        DefaultValue((char)0),
        Localizable(true),
        SRDescription(SR.TextBoxPasswordCharDescr),
        RefreshProperties(RefreshProperties.Repaint)
        ]
        public char PasswordChar {
            get {
                if (!IsHandleCreated) {
                    CreateHandle();
                }
                return (char)SendMessage(NativeMethods.EM_GETPASSWORDCHAR, 0, 0);
            }
            set {
                passwordChar = value;
                if (!useSystemPasswordChar) {
                    if (IsHandleCreated) {
                        if (PasswordChar != value) {
                            // Set the password mode.
                            SendMessage(NativeMethods.EM_SETPASSWORDCHAR, value, 0);
 
                            // Disable IME if setting the control to password mode.
                            VerifyImeRestrictedModeChanged();
 
                            ResetAutoComplete(false);
                            Invalidate();
                        }
                    }
                }
            }
        }
 
        /// <include file='doc\TextBox.uex' path='docs/doc[@for="TextBox.ScrollBars"]/*' />
        /// <devdoc>
        ///    <para>
        ///       Gets or sets which scroll bars should
        ///       appear in a multiline <see cref='System.Windows.Forms.TextBox'/>
        ///       control.
        ///    </para>
        /// </devdoc>
        [
        SRCategory(SR.CatAppearance),
        Localizable(true),
        DefaultValue(ScrollBars.None),
        SRDescription(SR.TextBoxScrollBarsDescr)
        ]
        public ScrollBars ScrollBars {
            get {
                return scrollBars;
            }
            set {
                if (scrollBars != value) {
                    //valid values are 0x0 to 0x3
                    if (!ClientUtils.IsEnumValid(value, (int)value, (int)ScrollBars.None, (int)ScrollBars.Both)){
                        throw new InvalidEnumArgumentException("value", (int)value, typeof(ScrollBars));
                    }
 
                    scrollBars = value;
                    RecreateHandle();
                }
            }
        }
 
        internal override Size GetPreferredSizeCore(Size proposedConstraints) {
            Size scrollBarPadding = Size.Empty;
 
            if(Multiline && !WordWrap && (ScrollBars & ScrollBars.Horizontal) != 0) {
                scrollBarPadding.Height += SystemInformation.GetHorizontalScrollBarHeightForDpi(deviceDpi);
            }
            if(Multiline && (ScrollBars & ScrollBars.Vertical) != 0) {
                scrollBarPadding.Width += SystemInformation.GetVerticalScrollBarWidthForDpi(deviceDpi);
            }
 
            // Subtract the scroll bar padding before measuring
            proposedConstraints -= scrollBarPadding;
            
            Size prefSize = base.GetPreferredSizeCore(proposedConstraints);
 
            return prefSize + scrollBarPadding;
        }
 
        /// <include file='doc\TextBox.uex' path='docs/doc[@for="TextBox.Text"]/*' />
        /// <devdoc>
        ///    <para>
        ///       Gets or sets
        ///       the current text in the text box.
        ///    </para>
        /// </devdoc>
        public override string Text {
            get {
                return base.Text;
            }
            set {
                base.Text = value;
                selectionSet = false;
            }
        }
 
        /// <include file='doc\TextBox.uex' path='docs/doc[@for="TextBox.TextAlign"]/*' />
        /// <devdoc>
        ///    <para>
        ///       Gets or sets how text is
        ///       aligned in a <see cref='System.Windows.Forms.TextBox'/>
        ///       control.
        ///       Note: This code is duplicated in MaskedTextBox for simplicity.
        ///    </para>
        /// </devdoc>
        [
        Localizable(true),
        SRCategory(SR.CatAppearance),
        DefaultValue(HorizontalAlignment.Left),
        SRDescription(SR.TextBoxTextAlignDescr)
        ]
        public HorizontalAlignment TextAlign {
            get {
                return textAlign;
            }
            set {
                if (textAlign != value) {
                    //verify that 'value' is a valid enum type...
 
                    //valid values are 0x0 to 0x2
                    if (!ClientUtils.IsEnumValid(value, (int)value, (int)HorizontalAlignment.Left, (int)HorizontalAlignment.Center)){
                        throw new InvalidEnumArgumentException("value", (int)value, typeof(HorizontalAlignment));
                    }
 
                    textAlign = value;
                    RecreateHandle();
                    OnTextAlignChanged(EventArgs.Empty);
                }
            }
        }
 
        /// <include file='doc\TextBox.uex' path='docs/doc[@for="TextBox.IsPasswordMode"]/*' />
        /// <devdoc>
        ///    <para>
        ///    Indicates if the text in the edit control should appear as
        ///    the default password character. This property has precedence
        ///    over the PasswordChar property.  Whenever the UseSystemPasswordChar
        ///    is set to true, the default system password character is used,
        ///    any character set into PasswordChar is ignored.
        ///    </para>
        /// </devdoc>
        [
        SRCategory(SR.CatBehavior),
        DefaultValue(false),
        SRDescription(SR.TextBoxUseSystemPasswordCharDescr),
        RefreshProperties(RefreshProperties.Repaint)
        ]
        public bool UseSystemPasswordChar {
            get {
                return useSystemPasswordChar;
            }
            set {
                if (value != useSystemPasswordChar) {
                    useSystemPasswordChar = value;
 
                    // RecreateHandle will update IME restricted mode.
                    RecreateHandle();
 
                    if (value) {
                        ResetAutoComplete(false);
                    }
                }
            }
        }
        
        /// <include file='doc\TextBox.uex' path='docs/doc[@for="TextBox.TextAlignChanged"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        [SRCategory(SR.CatPropertyChanged), SRDescription(SR.RadioButtonOnTextAlignChangedDescr)]
        public event EventHandler TextAlignChanged {
            add {
                Events.AddHandler(EVENT_TEXTALIGNCHANGED, value);
            }
 
            remove {
                Events.RemoveHandler(EVENT_TEXTALIGNCHANGED, value);
            }
        }
 
        /// <include file='doc\TabControl.uex' path='docs/doc[@for="TextBox.Dispose"]/*' />
        protected override void Dispose(bool disposing) {
            if (disposing) {
                // VSWhidbey 281668 - Reset this just in case, because the SHAutoComplete stuff
                // will subclass this guys wndproc (and nativewindow can't know about it).
                // so this will undo it, but on a dispose we'll be Destroying the window anyay.
                //
                ResetAutoComplete(true);
                if (autoCompleteCustomSource != null) {
                    autoCompleteCustomSource.CollectionChanged -= new CollectionChangeEventHandler(this.OnAutoCompleteCustomSourceChanged);
                }
                if (stringSource != null)
                {
                    stringSource.ReleaseAutoComplete();
                    stringSource = null;
                }
            }
            base.Dispose(disposing);
        }
       
        /// <include file='doc\TextBox.uex' path='docs/doc[@for="TextBox.IsInputKey"]/*' />
        /// <internalonly/>
        /// <devdoc>
        ///    <para>
        ///       Overridden to handle RETURN key.
        ///    </para>
        /// </devdoc>
        protected override bool IsInputKey(Keys keyData) {
            if (Multiline && (keyData & Keys.Alt) == 0) {
                switch (keyData & Keys.KeyCode) {
                    case Keys.Return:
                        return acceptsReturn;
                }
            }
            return base.IsInputKey(keyData);
        }
 
 
        private void OnAutoCompleteCustomSourceChanged(object sender, CollectionChangeEventArgs e) {
            if (AutoCompleteSource == AutoCompleteSource.CustomSource)
            {
                SetAutoComplete(true);
            }
        }
 
        /// <include file='doc\TextBox.uex' path='docs/doc[@for="TextBox.OnBackColorChanged"]/*' />
        protected override void OnBackColorChanged(EventArgs e) {
            base.OnBackColorChanged(e);
            // VSWhidbey 465708. Force repainting of the entire window frame
            if (Application.RenderWithVisualStyles && this.IsHandleCreated && this.BorderStyle == BorderStyle.Fixed3D) {
                SafeNativeMethods.RedrawWindow(new HandleRef(this, this.Handle), null, NativeMethods.NullHandleRef, NativeMethods.RDW_INVALIDATE | NativeMethods.RDW_FRAME);
            }
        }
 
        /// <include file='doc\TextBox.uex' path='docs/doc[@for="TextBox.OnFontChanged"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        protected override void OnFontChanged(EventArgs e) {
            base.OnFontChanged(e);
            if (this.AutoCompleteMode != AutoCompleteMode.None) {
                //we always will recreate the handle when autocomplete mode is on
                RecreateHandle();
            }
        }
 
        /// <include file='doc\TextBox.uex' path='docs/doc[@for="TextBox.OnGotFocus"]/*' />
        /// <internalonly/>
        /// <devdoc>
        ///    Overrideen to focus the text on first focus.
        /// </devdoc>
        protected override void OnGotFocus(EventArgs e) {
            base.OnGotFocus(e);
            if (!selectionSet) {
                // We get one shot at selecting when we first get focus.  If we don't
                // do it, we still want to act like the selection was set.
                selectionSet = true;
 
                // If the user didn't provide a selection, force one in.
                if (SelectionLength == 0 && Control.MouseButtons == MouseButtons.None) {
                    SelectAll();
                }
            }
        }
 
        /// <include file='doc\TextBox.uex' path='docs/doc[@for="TextBox.OnHandleCreated"]/*' />
        /// <internalonly/>
        /// <devdoc>
        ///    Overridden to update the newly created handle with the settings of the
        ///    PasswordChar properties.
        /// </devdoc>
        protected override void OnHandleCreated(EventArgs e) {
            base.OnHandleCreated(e);
            base.SetSelectionOnHandle();
 
            if (passwordChar != 0) {
                if (!useSystemPasswordChar) {
                    SendMessage(NativeMethods.EM_SETPASSWORDCHAR, passwordChar, 0);
                }
            }
 
            VerifyImeRestrictedModeChanged();
 
            if (AutoCompleteMode != AutoCompleteMode.None) {
                try
                {
                    fromHandleCreate = true;
                    SetAutoComplete(false);
                }
                finally
                {
                    fromHandleCreate = false;
                }
            }
        }
 
        protected override void OnHandleDestroyed(EventArgs e)
        {
            if (stringSource != null)
            {
                stringSource.ReleaseAutoComplete();
                stringSource = null;
            }
            base.OnHandleDestroyed(e);
        }
        
        /// <include file='doc\TextBox.uex' path='docs/doc[@for="TextBox.OnTextAlignChanged"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        protected virtual void OnTextAlignChanged(EventArgs e) {
            EventHandler eh = Events[EVENT_TEXTALIGNCHANGED] as EventHandler;
            if (eh != null) {
                 eh(this, e);
            }
        }
 
        /// <include file='doc\TextBox.uex' path='docs/doc[@for="TextBox.ProcessCmdKey"]/*' />
        /// <devdoc>
        /// Process a command key.
        /// Native "EDIT" control does not support "Select All" shorcut represented by Ctrl-A keys, when in multiline mode,
        /// and historically Microsoft TextBox did not support it either.
        /// We are adding support for this shortcut for application targeting 4.6.1 and newer and for applications targeting 4.0 and newer 
        /// versions of the .NET Framework if they opt into this feature by adding the following config switch to the 'runtime' section of the app.config file:
        ///   <runtime>
        ///       <AppContextSwitchOverrides value = "Switch.System.Windows.Forms.DoNotSupportSelectAllShortcutInMultilineTextBox=false" />
        ///   </ runtime>
        /// To opt out of this feature, when targeting 4.6.1 and newer, please set the above mentioned switch to true. 
        /// <para>
        ///  m - the current windows message
        /// keyData - bitmask containing one or more keys
        /// </para>
        /// </devdoc>
        [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
        protected override bool ProcessCmdKey(ref Message m, Keys keyData) {
            bool returnValue = base.ProcessCmdKey(ref m, keyData);
            if (!returnValue && this.Multiline && !LocalAppContextSwitches.DoNotSupportSelectAllShortcutInMultilineTextBox 
                && this.ShortcutsEnabled && (keyData == (Keys.Control | Keys.A))) {
                SelectAll();
                return true;
            }
 
            return returnValue;
        }
 
        /// <devdoc>
        ///     Replaces the portion of the text specified by startPos and length with the one passed in,
        ///     without resetting the undo buffer (if any).
        ///     This method is provided as an alternative to SelectedText which clears the undo buffer.
        ///     Observe that this method does not honor the MaxLength property as the parameter-less base's
        ///     Paste does, see VSW#487664 for more info.
        /// </devdoc>
        public void Paste(string text){
            base.SetSelectedTextInternal(text, false);
        }
     
        /// <devdoc>
        ///     Performs the actual select without doing arg checking.
        /// </devdoc>        
        internal override void SelectInternal(int start, int length, int textLen) {
            // If user set selection into text box, mark it so we don't
            // clobber it when we get focus.
            selectionSet = true;
            base.SelectInternal( start, length, textLen );
        }
 
        private string[] GetStringsForAutoComplete()
        {
            string[] strings = new string[AutoCompleteCustomSource.Count];
            for (int i = 0; i < AutoCompleteCustomSource.Count; i++) {
                strings[i] = AutoCompleteCustomSource[i];
            }
            return strings;
        }
 
 
 
        /// <include file='doc\TextBox.uex' path='docs/doc[@for="TextBox.SetAutoComplete"]/*' />
        /// <devdoc>
        ///     Sets the AutoComplete mode in TextBox.
        /// </devdoc>
        internal void SetAutoComplete(bool reset)
        {
            //Autocomplete Not Enabled for Password enabled and MultiLine Textboxes.
            if (Multiline || passwordChar != 0 || useSystemPasswordChar || AutoCompleteSource == AutoCompleteSource.None) {
                return;
            }
 
            if (AutoCompleteMode != AutoCompleteMode.None) {
                if (!fromHandleCreate)
                {
                    //RecreateHandle to avoid Leak.
                    // notice the use of member variable to avoid re-entrancy
                    AutoCompleteMode backUpMode = this.AutoCompleteMode;
                    autoCompleteMode = AutoCompleteMode.None;
                    RecreateHandle();
                    autoCompleteMode = backUpMode;
                }
                
                if (AutoCompleteSource == AutoCompleteSource.CustomSource) {
                    if (IsHandleCreated && AutoCompleteCustomSource != null) {
                        if (AutoCompleteCustomSource.Count == 0) {
                            ResetAutoComplete(true);
                        }
                        else {
                            if (stringSource == null)
                            {
                                stringSource = new StringSource(GetStringsForAutoComplete());
                                if (!stringSource.Bind(new HandleRef(this, Handle), (int)AutoCompleteMode))
                                {
                                   throw new ArgumentException(SR.GetString(SR.AutoCompleteFailure));
                                }
                            }
                            else
                            {
                                stringSource.RefreshList(GetStringsForAutoComplete());
                            }
                        }
                    }
        
                }
                else {
                    try {
                        if (IsHandleCreated) {
                            int mode = 0;
                            if (AutoCompleteMode == AutoCompleteMode.Suggest) {
                                mode |=  NativeMethods.AUTOSUGGEST | NativeMethods.AUTOAPPEND_OFF;
                            }
                            if (AutoCompleteMode == AutoCompleteMode.Append) {
                                mode |=  NativeMethods.AUTOAPPEND | NativeMethods.AUTOSUGGEST_OFF;
                            }
                            if (AutoCompleteMode == AutoCompleteMode.SuggestAppend) {
                                mode |=  NativeMethods.AUTOSUGGEST;
                                mode |=  NativeMethods.AUTOAPPEND;
                            }
                            int ret = SafeNativeMethods.SHAutoComplete(new HandleRef(this, Handle) , (int)AutoCompleteSource | mode);
                        }
                    }
                    catch (SecurityException) {
                        // If we don't have full trust, degrade gracefully. Allow the control to
                        // function without auto-complete. Allow the app to continue running.
                    }
                }
            }
            else if (reset) {
                ResetAutoComplete(true);
            }
        }
 
 
        // <include file='doc\TextBox.uex' path='docs/doc[@for="TextBox.ResetAutoComplete"]/*' />
        /// <devdoc>
        ///     Resets the AutoComplete mode in TextBox.
        /// </devdoc>
        private void ResetAutoComplete(bool force) {
            if ((AutoCompleteMode != AutoCompleteMode.None || force) && IsHandleCreated) {
                int mode = (int)AutoCompleteSource.AllSystemSources | NativeMethods.AUTOSUGGEST_OFF | NativeMethods.AUTOAPPEND_OFF;
                SafeNativeMethods.SHAutoComplete(new HandleRef(this, Handle) , mode);
            }
        }
 
        private void ResetAutoCompleteCustomSource() {
            AutoCompleteCustomSource = null;
        }
 
        private void WmPrint(ref Message m) {
            base.WndProc(ref m);
            if ((NativeMethods.PRF_NONCLIENT & (int)m.LParam) != 0 && Application.RenderWithVisualStyles && this.BorderStyle == BorderStyle.Fixed3D) {
                IntSecurity.UnmanagedCode.Assert();
                try {
                    using (Graphics g = Graphics.FromHdc(m.WParam)) {
                        Rectangle rect = new Rectangle(0, 0, this.Size.Width - 1, this.Size.Height - 1);
                        using (Pen pen = new Pen(VisualStyleInformation.TextControlBorder)) {
                            g.DrawRectangle(pen, rect);
                        }
                        rect.Inflate(-1, -1);
                        g.DrawRectangle(SystemPens.Window, rect);
                    }
                }
                finally {
                    CodeAccessPermission.RevertAssert();
                }
            }
        }
	
	//-------------------------------------------------------------------------------------------------
        
        /// <include file='doc\TextBox.uex' path='docs/doc[@for="TextBox.WndProc"]/*' />
        /// <internalonly/>
        /// <devdoc>
        ///    The edits window procedure.  Inheritng classes can override this
        ///    to add extra functionality, but should not forget to call
        ///    base.wndProc(m); to ensure the combo continues to function properly.
        /// </devdoc>
        [SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.UnmanagedCode)]
        protected override void WndProc(ref Message m) {
            switch (m.Msg) {
                // Work around a very obscure Windows issue. See ASURT 45255.
                case NativeMethods.WM_LBUTTONDOWN:
                    MouseButtons realState = MouseButtons;
                    bool wasValidationCancelled = ValidationCancelled;
                    FocusInternal();
                    if (realState == MouseButtons && 
                       (!ValidationCancelled || wasValidationCancelled)) {
                           base.WndProc(ref m);
                    }                    
                    break;
                //for readability ... so that we know whats happening ...
                // case WM_LBUTTONUP is included here eventhough it just calls the base.
                case NativeMethods.WM_LBUTTONUP:  
                    base.WndProc(ref m);
                    break;
                case NativeMethods.WM_PRINT:
                    WmPrint(ref m);
                    break;
                default:
                    base.WndProc(ref m);
                    break;
            }
            
        }
        
    }
}