File: System\Windows\Controls\PasswordBox.cs
Web Access
Project: src\src\Microsoft.DotNet.Wpf\src\PresentationFramework\PresentationFramework.csproj (PresentationFramework)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
 
//
// Description: The stock password control.
//
 
using System.ComponentModel;
using System.Security;
using System.Windows.Media;
using System.Windows.Documents;
using System.Windows.Automation.Peers;
using System.Windows.Input;
using System.Windows.Navigation;
using MS.Internal;
using MS.Internal.KnownBoxes;
using MS.Internal.Telemetry.PresentationFramework;
using System.Windows.Controls.Primitives;
 
#pragma warning disable 1634, 1691  // suppressing PreSharp warnings
 
namespace System.Windows.Controls
{
    /// <summary>
    /// The stock password control.
    /// </summary>
#if OLD_AUTOMATION
    [Automation(AccessibilityControlType = "Edit")]
#endif
    [TemplatePart(Name = "PART_ContentHost", Type = typeof(FrameworkElement))]
    public sealed class PasswordBox : Control, ITextBoxViewHost
#if OLD_AUTOMATION
        , IAutomationPatternProvider, IAutomationPropertyProvider
#endif
    {
        //------------------------------------------------------
        //
        //  Constructors
        //
        //------------------------------------------------------
 
        #region Constructors
 
        /// <summary>
        /// Static constructor for PasswordBox.
        /// </summary>
        static PasswordBox()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(PasswordBox), new FrameworkPropertyMetadata(typeof(PasswordBox)));
            _dType = DependencyObjectType.FromSystemTypeInternal(typeof(PasswordBox));
 
            // PasswordBox properties
            // ------------------
            PasswordCharProperty.OverrideMetadata(typeof(PasswordBox),
                    new FrameworkPropertyMetadata(new PropertyChangedCallback(OnPasswordCharChanged)));
 
            // Declare listener for Padding property
            Control.PaddingProperty.OverrideMetadata(typeof(PasswordBox),
                new FrameworkPropertyMetadata(new PropertyChangedCallback(OnPaddingChanged)));
 
            // Prevent journaling
            NavigationService.NavigationServiceProperty.OverrideMetadata(typeof(PasswordBox), new FrameworkPropertyMetadata(new PropertyChangedCallback(OnParentNavigationServiceChanged)));
 
            InputMethod.IsInputMethodEnabledProperty.OverrideMetadata(typeof(PasswordBox),
                    new FrameworkPropertyMetadata(
                            BooleanBoxes.FalseBox,
                            FrameworkPropertyMetadataOptions.Inherits,
                            null,
                            // replace this Coerce callback with a
                            // ValidateValue callback when we support VVC on override metadata
                            new CoerceValueCallback(ForceToFalse)));
 
            // VSM
            IsEnabledProperty.OverrideMetadata(typeof(PasswordBox), new UIPropertyMetadata(new PropertyChangedCallback(OnVisualStatePropertyChanged)));
            IsMouseOverPropertyKey.OverrideMetadata(typeof(PasswordBox), new UIPropertyMetadata(new PropertyChangedCallback(OnVisualStatePropertyChanged)));
 
            TextBoxBase.SelectionBrushProperty.OverrideMetadata(typeof(PasswordBox),
                new FrameworkPropertyMetadata(new PropertyChangedCallback(UpdateCaretElement)));
            TextBoxBase.SelectionTextBrushProperty.OverrideMetadata(typeof(PasswordBox),
                new FrameworkPropertyMetadata(new PropertyChangedCallback(UpdateCaretElement)));
            TextBoxBase.SelectionOpacityProperty.OverrideMetadata(typeof(PasswordBox), 
                new FrameworkPropertyMetadata(new PropertyChangedCallback(UpdateCaretElement)));
            TextBoxBase.CaretBrushProperty.OverrideMetadata(typeof(PasswordBox),
                new FrameworkPropertyMetadata(new PropertyChangedCallback(UpdateCaretElement)));
 
            ControlsTraceLogger.AddControl(TelemetryControls.PasswordBox);
        }
 
        /// <summary>
        /// Constructor.
        /// </summary>
        public PasswordBox() : base()
        {
            Initialize();
        }
 
        #endregion Constructors
 
        //------------------------------------------------------
        //
        //  Public Methods
        //
        //------------------------------------------------------
 
        #region Public Methods
 
        /// <summary>
        /// Replaces the current selection in the passwordbox with the contents
        /// of the Clipboard
        /// </summary>
        public void Paste()
        {
            RoutedCommand command = ApplicationCommands.Paste;
            command.Execute(null, this);
        }
 
        /// <summary>
        /// Select all text in the PasswordBox
        /// </summary>
        public void SelectAll()
        {
            Selection.Select(TextContainer.Start, TextContainer.End);
        }
 
        /// <summary>
        /// Clear all the content in the PasswordBox control.
        /// </summary>
        public void Clear()
        {
            this.Password = String.Empty;
        }
 
        #endregion Public Methods
 
        //------------------------------------------------------
        //
        //  Public Properties
        //
        //------------------------------------------------------
 
        #region Public Properties
 
        /// <summary>
        /// Contents of the PasswordBox.
        /// </summary>
        /// <remarks>
        /// Use the SecurePassword property in place of this one when possible.
        /// Doing so reduces the risk of revealing content that should be kept secret.
        /// </remarks>
        [DefaultValue("")]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public string Password
        {
            get
            {
                string password;
 
                using (SecureString securePassword = this.SecurePassword)
                {
                    IntPtr ptr = System.Runtime.InteropServices.Marshal.SecureStringToBSTR(securePassword);
 
                    try
                    {
                        unsafe
                        {
                            password = new string((char*)ptr);
                        }
                    }
                    finally
                    {
                        System.Runtime.InteropServices.Marshal.ZeroFreeBSTR(ptr);
                    }
                }
 
                return password;
            }
 
            set
            {
                if (value == null)
                {
                    value = String.Empty;
                }
 
                using (SecureString securePassword = new SecureString())
                {
                    #pragma warning suppress 6506 // value is set to String.Empty if it was null.
                    for (int i = 0; i < value.Length; i++)
                    {
                        securePassword.AppendChar(value[i]);
                    }
 
                    SetSecurePassword(securePassword);
                }
            }
        }
 
        /// <summary>
        /// Contents of the PasswordBox.
        /// </summary>
        /// <remarks>
        /// Reading the Password always returns a copy which may be safely
        /// Disposed.
        ///
        /// Setting the value always stores a copy of the supplied value.
        /// </remarks>
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public SecureString SecurePassword
        {
            get
            {
                return this.TextContainer.GetPasswordCopy();
            }
        }
 
        /// <summary>
        /// The DependencyID for the PasswordChar property.
        /// Default Value:     '*'
        /// </summary>
        public static readonly DependencyProperty PasswordCharProperty =
                DependencyProperty.RegisterAttached(
                        "PasswordChar", // Property name
                        typeof(char), // Property type
                        typeof(PasswordBox), // Property owner
                        new FrameworkPropertyMetadata('*')); // Flags
 
        /// <summary>
        /// Character to display instead of the actual password.
        /// </summary>
        public char PasswordChar
        {
            get { return (char) GetValue(PasswordCharProperty); }
            set { SetValue(PasswordCharProperty, value); }
        }
 
        /// <summary>
        /// The limit number of characters that the PasswordBox or other editable controls can contain.
        /// if it is 0, means no-limitation.
        /// User can set this value for some simple single line PasswordBox to restrict the text number.
        /// By default it is 0.
        /// </summary>
        /// <remarks>
        /// 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.
        /// </remarks>
        public static readonly DependencyProperty MaxLengthProperty =
                TextBox.MaxLengthProperty.AddOwner(typeof(PasswordBox));
 
 
        /// <summary>
        /// Maximum number of characters the PasswordBox can accept
        /// </summary>
        [DefaultValue((int)0)]
        public int MaxLength
        {
            get { return (int) GetValue(MaxLengthProperty); }
            set { SetValue(MaxLengthProperty, value); }
        }
 
        /// <summary>
        /// <see cref="TextBoxBase.SelectionBrushProperty"/>
        /// </summary>
        public static readonly DependencyProperty SelectionBrushProperty = 
            TextBoxBase.SelectionBrushProperty.AddOwner(typeof(PasswordBox));
 
        /// <summary>
        /// <see cref="TextBoxBase.SelectionBrushProperty" />
        /// </summary>
        public Brush SelectionBrush
        {
            get { return (Brush)GetValue(SelectionBrushProperty); }
            set { SetValue(SelectionBrushProperty, value); }
        }
 
        /// <summary>
        /// <see cref="TextBoxBase.SelectionTextBrushProperty"/>
        /// </summary>
        public static readonly DependencyProperty SelectionTextBrushProperty =
            TextBoxBase.SelectionTextBrushProperty.AddOwner(typeof(PasswordBox));
 
        /// <summary>
        /// <see cref="TextBoxBase.SelectionTextBrushProperty"/>
        /// </summary>
        public Brush SelectionTextBrush
        {
            get { return (Brush)GetValue(SelectionTextBrushProperty); }
            set { SetValue(SelectionTextBrushProperty, value); }
        }
 
        /// <summary>
        /// <see cref="TextBoxBase.SelectionOpacityProperty"/>
        /// </summary>
        public static readonly DependencyProperty SelectionOpacityProperty =
            TextBoxBase.SelectionOpacityProperty.AddOwner(typeof(PasswordBox));
 
        /// <summary>
        /// <see cref="TextBoxBase.SelectionOpacityProperty"/>
        /// </summary>
        public double SelectionOpacity
        {
            get { return (double)GetValue(SelectionOpacityProperty); }
            set { SetValue(SelectionOpacityProperty, value); }
        }
 
        /// <summary>
        /// <see cref="TextBoxBase.CaretBrushProperty"/>
        /// </summary>
        public static readonly DependencyProperty CaretBrushProperty =
            TextBoxBase.CaretBrushProperty.AddOwner(typeof(PasswordBox));
 
        /// <summary>
        /// <see cref="CaretBrushProperty" />
        /// </summary>
        public Brush CaretBrush
        {
            get { return (Brush)GetValue(CaretBrushProperty); }
            set { SetValue(CaretBrushProperty, value); }
        }
 
        /// <summary>
        /// <see cref="TextBoxBase.IsSelectionActiveProperty"/>
        /// </summary>
        public static readonly DependencyProperty IsSelectionActiveProperty =
            TextBoxBase.IsSelectionActiveProperty.AddOwner(typeof(PasswordBox));
 
        /// <summary>
        /// <see cref="TextBoxBase.IsSelectionActive"/>
        /// </summary>
        public bool IsSelectionActive
        {
            get { return (bool)GetValue(IsSelectionActiveProperty); }
        }
 
        /// <summary>
        /// <see cref="TextBoxBase.IsInactiveSelectionHighlightEnabledProperty"/>
        /// </summary>
        public static readonly DependencyProperty IsInactiveSelectionHighlightEnabledProperty =
            TextBoxBase.IsInactiveSelectionHighlightEnabledProperty.AddOwner(typeof(PasswordBox));
 
        /// <summary>
        /// <see cref="TextBoxBase.IsInactiveSelectionHighlightEnabled"/>
        /// </summary>
        public bool IsInactiveSelectionHighlightEnabled
        {
            get { return (bool)GetValue(IsInactiveSelectionHighlightEnabledProperty); }
            set { SetValue(IsInactiveSelectionHighlightEnabledProperty, value); }
        }
 
        #endregion Public Properties
 
        //------------------------------------------------------
        //
        //  Public Events
        //
        //------------------------------------------------------
 
        #region Public Events
 
        /// <summary>
        /// Event for "Text has changed"
        /// </summary>
        /// <remarks>
        /// Unlike most RoutedEvents on Controls, PasswordChangedEvent does not
        /// have a matching protected virtual OnPasswordChanged method --
        /// because PasswordBox is sealed.
        /// </remarks>
        public static readonly RoutedEvent PasswordChangedEvent = EventManager.RegisterRoutedEvent(
            "PasswordChanged", // Event name
            RoutingStrategy.Bubble, //
            typeof(RoutedEventHandler), //
            typeof(PasswordBox)); //
 
        /// <summary>
        /// Event fired from this text box when its inner content
        /// has been changed.
        /// </summary>
        /// <remarks>
        /// It is redirected from inner TextContainer.Changed event.
        /// </remarks>
        public event RoutedEventHandler PasswordChanged
        {
            add
            {
                AddHandler(PasswordChangedEvent, value);
            }
 
            remove
            {
                RemoveHandler(PasswordChangedEvent, value);
            }
        }
 
        #endregion Public Events
 
        //------------------------------------------------------
        //
        //  Protected Methods
        //
        //------------------------------------------------------
 
        #region Protected Methods
     
        internal override void ChangeVisualState(bool useTransitions)
        {
            if (!IsEnabled)
            {
                VisualStates.GoToState(this, useTransitions, VisualStates.StateDisabled, VisualStates.StateNormal);
            }
            else if (IsMouseOver)
            {
                VisualStates.GoToState(this, useTransitions, VisualStates.StateMouseOver, VisualStates.StateNormal);
            }
            else
            {
                VisualStateManager.GoToState(this, VisualStates.StateNormal, useTransitions);
            }
 
            if (IsKeyboardFocused)
            {
                VisualStates.GoToState(this, useTransitions, VisualStates.StateFocused, VisualStates.StateUnfocused);
            }
            else
            {
                VisualStateManager.GoToState(this, VisualStates.StateUnfocused, useTransitions);
            }
 
            base.ChangeVisualState(useTransitions);
        }
 
        /// <summary>
        /// Creates AutomationPeer (<see cref="UIElement.OnCreateAutomationPeer"/>)
        /// </summary>
        protected override AutomationPeer OnCreateAutomationPeer()
        {
            return new PasswordBoxAutomationPeer(this);
        }
 
        /// <summary>
        /// Called when the Template's tree has been generated
        /// </summary>
        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();
            AttachToVisualTree();
        }
 
        /// <summary>
        /// Template has changed
        /// </summary>
        /// <param name="oldTemplate">
        /// </param>
        /// <param name="newTemplate">
        /// </param>
        protected override void OnTemplateChanged(ControlTemplate oldTemplate, ControlTemplate newTemplate)
        {
            base.OnTemplateChanged(oldTemplate, newTemplate);
 
            if (oldTemplate!=null && newTemplate!= null && oldTemplate.VisualTree != newTemplate.VisualTree)
            {
                DetachFromVisualTree();
            }
        }
 
        ///
        /// <see cref="FrameworkElement.OnPropertyChanged"/>
        ///
        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(PasswordBox)) as FrameworkPropertyMetadata;
                if (fmetadata != null)
                {
                    if (e.IsAValueChange || e.IsASubPropertyChange)
                    {
                        if (fmetadata.AffectsMeasure || fmetadata.AffectsArrange ||
                            fmetadata.AffectsParentMeasure || fmetadata.AffectsParentArrange ||
                            e.Property == Control.HorizontalContentAlignmentProperty || e.Property == Control.VerticalContentAlignmentProperty)
                        {
                            ((TextBoxView)this.RenderScope).Remeasure();
                        }
                        else if (fmetadata.AffectsRender &&
                                (e.IsAValueChange || !fmetadata.SubPropertiesDoNotAffectRender))
                        {
                            ((TextBoxView)this.RenderScope).Rerender();
                        }
                    }
                }
            }
        }
 
        /// <summary>
        ///     Virtual method reporting a key was pressed
        /// </summary>
        protected override void OnKeyDown(KeyEventArgs e)
        {
            base.OnKeyDown(e);
 
            if (e.Handled)
            {
                return;
            }
 
            _textEditor.OnKeyDown(e);
        }
 
        /// <summary>
        ///     Virtual method reporting a key was released
        /// </summary>
        protected override void OnKeyUp(KeyEventArgs e)
        {
            base.OnKeyUp(e);
 
            if (e.Handled)
            {
                return;
            }
 
            _textEditor.OnKeyUp(e);
        }
 
        /// <summary>
        ///     Virtual method reporting text composition
        /// </summary>
        protected override void OnTextInput(TextCompositionEventArgs e)
        {
            base.OnTextInput(e);
 
            if (e.Handled)
            {
                return;
            }
 
            _textEditor.OnTextInput(e);
        }
 
        /// <summary>
        ///     Virtual method reporting the mouse button was pressed
        /// </summary>
        protected override void OnMouseDown(MouseButtonEventArgs e)
        {
            base.OnMouseDown(e);
 
            if (e.Handled)
            {
                return;
            }
 
            _textEditor.OnMouseDown(e);
        }
 
        /// <summary>
        ///     Virtual method reporting a mouse move
        /// </summary>
        protected override void OnMouseMove(MouseEventArgs e)
        {
            base.OnMouseMove(e);
 
            if (e.Handled)
            {
                return;
            }
 
            _textEditor.OnMouseMove(e);
        }
 
        /// <summary>
        ///     Virtual method reporting the mouse button was released
        /// </summary>
        protected override void OnMouseUp(MouseButtonEventArgs e)
        {
            base.OnMouseUp(e);
 
            if (e.Handled)
            {
                return;
            }
 
            _textEditor.OnMouseUp(e);
        }
 
        /// <summary>
        ///     Virtual method reporting the cursor to display was requested
        /// </summary>
        protected override void OnQueryCursor(QueryCursorEventArgs e)
        {
            base.OnQueryCursor(e);
 
            if (e.Handled)
            {
                return;
            }
 
            _textEditor.OnQueryCursor(e);
        }
 
        /// <summary>
        ///     Virtual method reporting the query continue drag is going to happen
        /// </summary>
        protected override void OnQueryContinueDrag(QueryContinueDragEventArgs e)
        {
            base.OnQueryContinueDrag(e);
 
            if (e.Handled)
            {
                return;
            }
 
            _textEditor.OnQueryContinueDrag(e);
        }
 
        /// <summary>
        ///     Virtual method reporting the give feedback is going to happen
        /// </summary>
        protected override void OnGiveFeedback(GiveFeedbackEventArgs e)
        {
            base.OnGiveFeedback(e);
 
            if (e.Handled)
            {
                return;
            }
 
            _textEditor.OnGiveFeedback(e);
        }
 
        /// <summary>
        ///     Virtual method reporting the drag enter is going to happen
        /// </summary>
        protected override void OnDragEnter(DragEventArgs e)
        {
            base.OnDragEnter(e);
 
            if (e.Handled)
            {
                return;
            }
 
            _textEditor.OnDragEnter(e);
        }
 
        /// <summary>
        ///     Virtual method reporting the drag over is going to happen
        /// </summary>
        protected override void OnDragOver(DragEventArgs e)
        {
            base.OnDragOver(e);
 
            if (e.Handled)
            {
                return;
            }
 
            _textEditor.OnDragOver(e);
        }
 
        /// <summary>
        ///     Virtual method reporting the drag leave is going to happen
        /// </summary>
        protected override void OnDragLeave(DragEventArgs e)
        {
            base.OnDragLeave(e);
 
            if (e.Handled)
            {
                return;
            }
 
            _textEditor.OnDragLeave(e);
        }
 
        /// <summary>
        ///     Virtual method reporting the drag enter is going to happen
        /// </summary>
        protected override void OnDrop(DragEventArgs e)
        {
            base.OnDrop(e);
 
            if (e.Handled)
            {
                return;
            }
 
            _textEditor.OnDrop(e);
        }
 
        /// <summary>
        ///     Called when ContextMenuOpening is raised on this element.
        /// </summary>
        /// <param name="e">Event arguments</param>
        protected override void OnContextMenuOpening(ContextMenuEventArgs e)
        {
            base.OnContextMenuOpening(e);
 
            if (e.Handled)
            {
                return;
            }
 
            _textEditor.OnContextMenuOpening(e);
        }
 
        /// <summary>
        ///     Virtual method reporting that the keyboard is focused on this element
        /// </summary>
        protected override void OnGotKeyboardFocus(KeyboardFocusChangedEventArgs e)
        {
            base.OnGotKeyboardFocus(e);
 
            if (e.Handled)
            {
                return;
            }
 
            _textEditor.OnGotKeyboardFocus(e);
        }
 
        /// <summary>
        ///     Virtual method reporting that the keyboard is no longer focusekeyboard is no longer focuseed
        /// </summary>
        protected override void OnLostKeyboardFocus(KeyboardFocusChangedEventArgs e)
        {
            base.OnLostKeyboardFocus(e);
 
            if (e.Handled)
            {
                return;
            }
 
            _textEditor.OnLostKeyboardFocus(e);
        }
 
        /// <summary>
        ///     This method is invoked when the IsFocused property changes to false
        /// </summary>
        /// <param name="e">RoutedEventArgs</param>
        protected override void OnLostFocus(RoutedEventArgs e)
        {
            base.OnLostFocus(e);
 
            if (e.Handled)
            {
                return;
            }
 
            _textEditor.OnLostFocus(e);
        }
 
        #endregion Protected Methods
 
        //------------------------------------------------------
        //
        //  Internal Properties
        //
        //------------------------------------------------------
 
        #region Internal Properties
 
        // A TextContainer covering the PasswordBox's inner content.
        internal PasswordTextContainer TextContainer
        {
            get
            {
                return _textContainer;
            }
        }
 
        /// <summary>
        /// readonly access to internal content control
        /// </summary>
        internal FrameworkElement RenderScope
        {
            get
            {
                return _renderScope;
            }
        }
 
        internal ScrollViewer ScrollViewer
        {
            get
            {
                if (_scrollViewer == null)
                {
                    if (_textEditor != null)
                    {
                        _scrollViewer = _textEditor._Scroller as ScrollViewer;
                    }
                }
                return _scrollViewer;
            }
        }
 
        // 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 true;
            }
        }
 
        #endregion Internal Properties
 
        //------------------------------------------------------
        //
        //  Private Methods
        //
        //------------------------------------------------------
 
        #region Private Methods
 
        // Worker for the ctors, initializes a new PasswordBox instance.
        private void Initialize()
        {
            // 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(PasswordBox), /*acceptsRichContent:*/false, /*readOnly*/false, /*registerEventListeners*/false);
 
            // Create TextContainer
            InitializeTextContainer(new PasswordTextContainer(this));
 
            // PasswordBox only accepts plain text, so change TextEditor's default to that.
            _textEditor.AcceptsRichContent = false;
 
            // PasswordBox does not accepts tabs.
            _textEditor.AcceptsTab = false;
        }
 
        // Attaches this control to a new TextContainer.
        private void InitializeTextContainer(PasswordTextContainer textContainer)
        {
            Invariant.Assert(textContainer != null);
 
            // Uninitialize previous TextEditor
            if (_textContainer != null)
            {
                Invariant.Assert(_textEditor != null);
                Invariant.Assert(_textEditor.TextContainer == _textContainer);
 
                // Detach existing editor from VisualTree
                DetachFromVisualTree();
 
                // Discard TextEditor - must release text container
                _textEditor.OnDetach();
            }
 
            // Save text container
            _textContainer = textContainer;
 
            // Use static class handler
            ((ITextContainer)_textContainer).Changed += new TextContainerChangedEventHandler(OnTextContainerChanged);
 
            // Create a text editor, initialize undo manager for it, and link it to text container
            _textEditor = new TextEditor(_textContainer, this, true);
        }
 
        // Disable IME input unconditionally.  We really can't support
        // IMEs in this control, because PasswordTextContainer doesn't
        // round-trip content, which breaks the cicero contract.
        // Additionally, from a UI standpoint, we don't want to break
        // user expectations by allowing IME input.  IMEs do cool things
        // like learn from user corrections, so the same keystroke sequence
        // might produce different text over time.
        private static object ForceToFalse(DependencyObject d, object value)
        {
            return BooleanBoxes.FalseBox;
        }
 
        /// <summary>
        /// Callback for changes to the PasswordChar property.
        /// </summary>
        private static void OnPasswordCharChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            PasswordBox passwordBox = (PasswordBox)d;
 
            // Force a layout refresh to display the new char.
            if (passwordBox._renderScope != null)
            {
                passwordBox._renderScope.InvalidateMeasure();
            }
        }
 
        /// <summary>
        /// Handler for text array change notifications.
        /// </summary>
        /// <param name="sender">
        /// sender
        /// </param>
        /// <param name="e">
        /// event args
        /// </param>
        private void OnTextContainerChanged(object sender, TextContainerChangedEventArgs e)
        {
            // If only properties on the text changed, don't fire a content change event.
            // This can happen even in a plain text TextBox if we switch logical trees.
            if (!e.HasContentAddedOrRemoved)
            {
                return;
            }
 
            RaiseEvent(new RoutedEventArgs(PasswordChangedEvent));
        }
 
        /// <summary>
        /// Walk the visual tree until we find a Text control with IsPasswordBoxContent == true
        /// and a ScrollViewer
        /// </summary>
        private void SetRenderScopeToContentHost(TextBoxView renderScope)
        {
            // Clear the content host from previous render scope (if any)
            ClearContentHost();
 
            // Find ContentHostTemplateName in the style
            _passwordBoxContentHost = GetTemplateChild(ContentHostTemplateName) as FrameworkElement;
 
            // Note that we allow ContentHostTemplateName to be optional.
            // This simplifies toolability of our control styling.
            // When the ContentHostTemplateName is not found or incorrect
            // PasswordBox goes into disabled state, but does not throw.
 
            // Add renderScope as a child of ContentHostTemplateName
            _renderScope = renderScope;
            if (_passwordBoxContentHost is ScrollViewer)
            {
                ScrollViewer scrollViewer = (ScrollViewer)_passwordBoxContentHost;
                if (scrollViewer.Content != null)
                {
                    throw new NotSupportedException(SR.TextBoxScrollViewerMarkedAsTextBoxContentMustHaveNoContent);
                }
                else
                {
                    scrollViewer.Content = _renderScope;
                }
            }
            else if (_passwordBoxContentHost is Decorator)
            {
                Decorator decorator = (Decorator)_passwordBoxContentHost;
                if (decorator.Child != null)
                {
                    throw new NotSupportedException(SR.TextBoxDecoratorMarkedAsTextBoxContentMustHaveNoContent);
                }
                else
                {
                    decorator.Child = _renderScope; // this may replace old render scope in case of upgrade scenario in TextBox
                }
            }
            else
            {
                // When we implement TextContainer setting via TextView interface
                // all text containing element will become allowed here.
                _renderScope = null;
 
                // Explicitly not throwing an exception here when content host = null
                // -- designers need us to support no content scenarios
                if (_passwordBoxContentHost != null)
                {
                    _passwordBoxContentHost = null;
                    //  Remove the exception
                    throw new NotSupportedException(SR.PasswordBoxInvalidTextContainer);
                }
            }
 
            // Attach render scope to TextEditor
            InitializeRenderScope();
 
            FrameworkElement element = _renderScope;
            while (element != this && element != null)  // checking both just to be safe
            {
                if (element is Border)
                {
                    _border = (Border)element;
                }
                element = element.Parent as FrameworkElement;
            }
        }
 
        private void ClearContentHost()
        {
            // Detach render scope from TextEditor
            UninitializeRenderScope();
 
            // Render scope has been created by us,
            // so we need to extract if from visual tree.
            if (_passwordBoxContentHost is ScrollViewer)
            {
                ((ScrollViewer)_passwordBoxContentHost).Content = null;
            }
            else if (_passwordBoxContentHost is Decorator)
            {
                ((Decorator)_passwordBoxContentHost).Child = null;
            }
            else
            {
                Invariant.Assert(_passwordBoxContentHost == null, "_passwordBoxContentHost must be null here");
            }
 
            _passwordBoxContentHost = null;
        }
 
        // Initializes a new render scope.
        private void InitializeRenderScope()
        {
            if (_renderScope == null)
            {
                return;
            }
 
            // Attach the renderScope to TextEditor as its ITextView member.
            ITextView textview = TextEditor.GetTextView(_renderScope);
            _textEditor.TextView = textview;
            this.TextContainer.TextView = textview;
 
            if (this.ScrollViewer != null)
            {
                this.ScrollViewer.CanContentScroll = true;
            }
        }
 
        // Uninitializes a render scope and clears this control's reference.
        private void UninitializeRenderScope()
        {
            // Clear TextView property in TextEditor
            _textEditor.TextView = null;
        }
 
        // Resets the selection to the start of the content.
        // Called after non-TOM changes to the content, like
        // set_Text
        private void ResetSelection()
        {
            Select(0, 0);
 
            if (this.ScrollViewer != null)
            {
                this.ScrollViewer.ScrollToHome();
            }
        }
 
        /// <summary>
        /// Select the text in the given position and length.
        /// </summary>
        private void Select(int start, int length)
        {
            ITextPointer selectionStart;
            ITextPointer selectionEnd;
 
            //             VerifyAccess();
            ArgumentOutOfRangeException.ThrowIfNegative(start);
            ArgumentOutOfRangeException.ThrowIfNegative(length);
 
            // Identify new selection start position
            selectionStart = this.TextContainer.Start.CreatePointer();
            while (start-- > 0 && selectionStart.MoveToNextInsertionPosition(LogicalDirection.Forward))
            {
            }
 
            // Identify new selection end position
            selectionEnd = selectionStart.CreatePointer();
            while (length-- > 0 && selectionEnd.MoveToNextInsertionPosition(LogicalDirection.Forward))
            {
            }
 
            Selection.Select(selectionStart, selectionEnd);
        }
 
        /// <summary>
        /// Callback for TextBox.Padding property setting
        /// </summary>
        /// <param name="d">
        /// TextBoxBase on which the property is changed
        /// </param>
        /// <param name="e">event args</param>
        private static void OnPaddingChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            PasswordBox passwordBox = (PasswordBox)d;
 
            if (passwordBox.ScrollViewer != null)
            {
                // translate this change into inner property set on ScrollViewer
                object padding = passwordBox.GetValue(Control.PaddingProperty);
                if (padding is Thickness)
                {
                    passwordBox.ScrollViewer.Padding = (Thickness)padding;
                }
                else
                {
                    passwordBox.ScrollViewer.ClearValue(Control.PaddingProperty);
                }
            }
        }
 
        // Set up listener for Navigating event
        private static void OnParentNavigationServiceChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
        {
            PasswordBox passwordBox = (PasswordBox)o;
            NavigationService navService = NavigationService.GetNavigationService(o);
            if (passwordBox._navigationService != null)
            {
                passwordBox._navigationService.Navigating -= new NavigatingCancelEventHandler(passwordBox.OnNavigating);
            }
            if (navService != null)
            {
                navService.Navigating += new NavigatingCancelEventHandler(passwordBox.OnNavigating);
                passwordBox._navigationService = navService;
            }
            else
            {
                passwordBox._navigationService = null;
            }
        }
 
        // Clear password on navigation to prevent journaling.
        private void OnNavigating(Object sender, NavigatingCancelEventArgs e)
        {
            this.Password = String.Empty;
        }
 
        /// <summary>
        /// Detaches the editor from old visual tree and attaches it to a new one
        /// </summary>
        private void AttachToVisualTree()
        {
            DetachFromVisualTree();
 
            // Walk the visual tree to find our Text element
            SetRenderScopeToContentHost(new TextBoxView(this));
 
            // Attach scroll handler to the new scroll viewer
            // Note that this.ScrollViewer will walk the tree from current TextEditor's render scope up to its ui scope.
            if (this.ScrollViewer != null)
            {
                this.ScrollViewer.HorizontalScrollBarVisibility = ScrollBarVisibility.Hidden;
                this.ScrollViewer.VerticalScrollBarVisibility = ScrollBarVisibility.Disabled;
                this.ScrollViewer.Focusable = false;
 
                if (this.ScrollViewer.Background == null)
                {
                    // prevent hit-testing through padding
                    this.ScrollViewer.Background = Brushes.Transparent;
                }
                OnPaddingChanged(this, new DependencyPropertyChangedEventArgs());
            }
 
            // Set border properties
            if (_border != null)
            {
                _border.Style = null;
            }
        }
 
        /// <summary>
        /// Clear our layout-specific data, and detach our current renderScope from our text editor.
        /// </summary>
        private void DetachFromVisualTree()
        {
            if (_textEditor != null)
            {
                _textEditor.Selection.DetachFromVisualTree();
            }
 
            // Invalidate our cached copy of scroll viewer.
            _scrollViewer = null;
            _border = null;
 
            ClearContentHost();
        }
 
        /// <summary>
        /// Sets the content of the control.
        /// </summary>
        private void SetSecurePassword(SecureString value)
        {
            this.TextContainer.BeginChange();
            try
            {
                this.TextContainer.SetPassword(value);
                this.ResetSelection();
            }
            finally
            {
                this.TextContainer.EndChange();
            }
        }
 
        /// <summary>
        /// PropertyChanged callback for a property that affects the selection or caret rendering.
        /// </summary>
        private static void UpdateCaretElement(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            PasswordBox passwordBox = (PasswordBox)d;
 
            if (passwordBox.Selection != null)
            {
                CaretElement caretElement = passwordBox.Selection.CaretElement;
                if (caretElement != null)
                {
                    if (e.Property == CaretBrushProperty)
                    {
                        caretElement.UpdateCaretBrush(TextSelection.GetCaretBrush(passwordBox.Selection.TextEditor));
                    }
 
                    caretElement.InvalidateVisual();
                }
 
                
                // If the TextBox is rendering its own selection we need to invalidate arrange here
                // in order to ensure the selection is updated.
                var textBoxView = passwordBox?.RenderScope as TextBoxView;
 
                if ((textBoxView as ITextView)?.RendersOwnSelection == true)
                {
                    textBoxView.InvalidateArrange();
                }
            }
        }
 
        #endregion Private methods
 
        //------------------------------------------------------
        //
        //  Private Properties
        //
        //------------------------------------------------------
 
        #region Private Properties
 
        /// <summary>
        /// Text Selection (readonly)
        /// </summary>
        private ITextSelection Selection
        {
            get
            {
                return _textEditor.Selection;
            }
        }
 
 
        #endregion Private Properties
 
        //------------------------------------------------------
        //
        //  Private Fields
        //
        //------------------------------------------------------
 
        #region Private Fields
 
        // TextEditor working in this control instance
        private TextEditor _textEditor;
 
        // Backing store for the control's content.
        private PasswordTextContainer _textContainer;
 
        // Encapsulated control that renders our TextContainer.
        private TextBoxView _renderScope;
 
        // ScrollViewer
        private ScrollViewer _scrollViewer;
 
        // Border
        private Border _border;
 
        // An element marked as ContentHostTemplateName which we assign our _renderScope as a child.
        private FrameworkElement _passwordBoxContentHost;
 
        // Default size for the control.
        private const int _defaultWidth = 100;
        private const int _defaultHeight = 20;
 
        // Part name used in the style. The class TemplatePartAttribute should use the same name
        private const string ContentHostTemplateName = "PART_ContentHost";
 
        #endregion Private Fields
 
        #region DTypeThemeStyleKey
 
        // 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; }
        }
 
        private static DependencyObjectType _dType;
 
        private NavigationService _navigationService;
        #endregion DTypeThemeStyleKey
    }
}