How to automatically select all text on focus in WPF TextBox?

0 votes
asked Mar 18, 2009 by sergey-aldoukhov

If I call SelectAll from a GotFocus event handler, it doesn't work with the mouse - the selection disappears as soon as mouse is released.

EDIT: People are liking Donnelle's answer, I'll try to explain why I did not like it as much as the accepted answer.

  • It is more complex, while the accepted answer does the same thing in a simpler way.
  • The usability of accepted answer is better. When you click in the middle of the text, text gets unselected when you release the mouse allowing you to start editing instantly, and if you still want to select all, just press the button again and this time it will not unselect on release. Following Donelle's recipe, if I click in the middle of text, I have to click second time to be able to edit. If I click somewhere within the text versus outside of the text, this most probably means I want to start editing instead of overwriting everything.

26 Answers

0 votes
answered Jan 12, 2009 by sergey-aldoukhov

Here are the Blend behaviors implementing the answer solution for your convenience:

One for attaching to a single TextBox:

public class SelectAllTextOnFocusBehavior : Behavior<TextBox>
{
    protected override void OnAttached()
    {
        base.OnAttached();
        AssociatedObject.GotKeyboardFocus += AssociatedObjectGotKeyboardFocus;
        AssociatedObject.GotMouseCapture += AssociatedObjectGotMouseCapture;
        AssociatedObject.PreviewMouseLeftButtonDown += AssociatedObjectPreviewMouseLeftButtonDown;
    }

    protected override void OnDetaching()
    {
        base.OnDetaching();
        AssociatedObject.GotKeyboardFocus -= AssociatedObjectGotKeyboardFocus;
        AssociatedObject.GotMouseCapture -= AssociatedObjectGotMouseCapture;
        AssociatedObject.PreviewMouseLeftButtonDown -= AssociatedObjectPreviewMouseLeftButtonDown;
    }

    private void AssociatedObjectGotKeyboardFocus(object sender,
        System.Windows.Input.KeyboardFocusChangedEventArgs e)
    {
        AssociatedObject.SelectAll();
    }

    private void AssociatedObjectGotMouseCapture(object sender,
        System.Windows.Input.MouseEventArgs e)
    {
        AssociatedObject.SelectAll();   
    }

    private void AssociatedObjectPreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
        if(!AssociatedObject.IsKeyboardFocusWithin)
        {
            AssociatedObject.Focus();
            e.Handled = true;
        }
    }
}

And one for attaching to the root of a container containing multiple TextBox'es:

public class SelectAllTextOnFocusMultiBehavior : Behavior<UIElement>
{
    protected override void OnAttached()
    {
        base.OnAttached();
        AssociatedObject.GotKeyboardFocus += HandleKeyboardFocus;
        AssociatedObject.GotMouseCapture += HandleMouseCapture;
    }

    protected override void OnDetaching()
    {
        base.OnDetaching();
        AssociatedObject.GotKeyboardFocus -= HandleKeyboardFocus;
        AssociatedObject.GotMouseCapture -= HandleMouseCapture;
    }

    private static void HandleKeyboardFocus(object sender,
        System.Windows.Input.KeyboardFocusChangedEventArgs e)
    {
        var txt = e.NewFocus as TextBox;
        if (txt != null)
            txt.SelectAll();
    }

    private static void HandleMouseCapture(object sender,
        System.Windows.Input.MouseEventArgs e)
    {
        var txt = e.OriginalSource as TextBox;
        if (txt != null)
            txt.SelectAll();
    }
}
0 votes
answered Mar 19, 2009 by gcores

Don't know why it loses the selection in the GotFocus event.

But one solution is to do the selection on the GotKeyboardFocus and the GotMouseCapture events. That way it will always work.

0 votes
answered Mar 19, 2009 by donnelle

We have it so the first click selects all, and another click goes to cursor (our application is designed for use on tablets with pens).

You might find it useful.

public class ClickSelectTextBox : TextBox
{
    public ClickSelectTextBox()
    {
        AddHandler(PreviewMouseLeftButtonDownEvent, 
          new MouseButtonEventHandler(SelectivelyIgnoreMouseButton), true);
        AddHandler(GotKeyboardFocusEvent, 
          new RoutedEventHandler(SelectAllText), true);
        AddHandler(MouseDoubleClickEvent, 
          new RoutedEventHandler(SelectAllText), true);
    }

    private static void SelectivelyIgnoreMouseButton(object sender, 
                                                     MouseButtonEventArgs e)
    {
        // Find the TextBox
        DependencyObject parent = e.OriginalSource as UIElement;
        while (parent != null && !(parent is TextBox))
            parent = VisualTreeHelper.GetParent(parent);

        if (parent != null)
        {
            var textBox = (TextBox)parent;
            if (!textBox.IsKeyboardFocusWithin)
            {
                // If the text box is not yet focussed, give it the focus and
                // stop further processing of this click event.
                textBox.Focus();
                e.Handled = true;
            }
        }
    }

    private static void SelectAllText(object sender, RoutedEventArgs e)
    {
        var textBox = e.OriginalSource as TextBox;
        if (textBox != null)
            textBox.SelectAll();
    }
}
0 votes
answered Jan 20, 2010 by nils

This is rather old, but I'll display my answer anyway.
I have chosen part of Donnelle's answer (skipped the double-click) for I think this creates the least astonishment in the users. However, like gcores I dislike the need to create a derived class. But I also don't like gcores "on Startup..." method. And I need this on a "generally but not always"-basis.

I have Implemented this as an attached dependency Property so I can set SelectTextOnFocus.Active=True in xaml. I find this way the most pleasing.

namespace foo.styles.behaviour
{
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Input;
    using System.Windows.Media;

    public class SelectTextOnFocus : DependencyObject
    {
        public static readonly DependencyProperty ActiveProperty = DependencyProperty.RegisterAttached(
            "Active",
            typeof(bool),
            typeof(SelectTextOnFocus),
            new PropertyMetadata(false, ActivePropertyChanged));

        private static void ActivePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (d is TextBox)
            {
                TextBox textBox = d as TextBox;
                if ((e.NewValue as bool?).GetValueOrDefault(false))
                {
                    textBox.GotKeyboardFocus += OnKeyboardFocusSelectText;
                    textBox.PreviewMouseLeftButtonDown += OnMouseLeftButtonDown;
                }
                else
                {
                    textBox.GotKeyboardFocus -= OnKeyboardFocusSelectText;
                    textBox.PreviewMouseLeftButtonDown -= OnMouseLeftButtonDown;
                }
            }
        }

        private static void OnMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            DependencyObject dependencyObject = GetParentFromVisualTree(e.OriginalSource);

            if (dependencyObject == null)
            {
                return;
            }

            var textBox = (TextBox)dependencyObject;
            if (!textBox.IsKeyboardFocusWithin)
            {
                textBox.Focus();
                e.Handled = true;
            }
        }

        private static DependencyObject GetParentFromVisualTree(object source)
        {
            DependencyObject parent = source as UIElement;
            while (parent != null && !(parent is TextBox))
            {
                parent = VisualTreeHelper.GetParent(parent);
            }

            return parent;
        }

        private static void OnKeyboardFocusSelectText(object sender, KeyboardFocusChangedEventArgs e)
        {
            TextBox textBox = e.OriginalSource as TextBox;
            if (textBox != null)
            {
                textBox.SelectAll();
            }
        }

        [AttachedPropertyBrowsableForChildrenAttribute(IncludeDescendants = false)]
        [AttachedPropertyBrowsableForType(typeof(TextBox))]
        public static bool GetActive(DependencyObject @object)
        {
            return (bool) @object.GetValue(ActiveProperty);
        }

        public static void SetActive(DependencyObject @object, bool value)
        {
            @object.SetValue(ActiveProperty, value);
        }
    }
}

For my "general but not always"-feature I set this Property to True in a (global) TextBox-Style. This way "selecting the Text" is always "on", but I am able to disable it on a per-Textbox-basis.

0 votes
answered Jan 27, 2010 by kristof-verbiest

I've found none of the answers presented here mimic a standard Windows textbox. For instance, try to click in the white space between the last character of the textbox and the right side of the textbox. Most of the solutions here will always select the whole content, which makes it very difficult to append text to a textbox.

The answer that I present here behaves better in this respect. It is a behavior (so it requires the System.Windows.Interactivity assembly from the Blend SDK). It could be rewritten using attached properties as well.

public sealed class SelectAllTextOnFocusBehavior : Behavior<TextBox>
{
    protected override void OnAttached()
    {
        base.OnAttached();
        AssociatedObject.PreviewMouseLeftButtonDown += AssociatedObject_PreviewMouseLeftButtonDown;
    }

    protected override void OnDetaching()
    {
        base.OnDetaching();
        AssociatedObject.PreviewMouseLeftButtonDown -= AssociatedObject_PreviewMouseLeftButtonDown;
    }

    void AssociatedObject_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
        // Find the textbox
        DependencyObject parent = e.OriginalSource as UIElement;
        while (parent != null && !(parent is TextBox))
            parent = VisualTreeHelper.GetParent(parent);

        var textBox = parent as TextBox;
        Debug.Assert(textBox != null);

        if (textBox.IsFocused) return;

        textBox.SelectAll();
        Keyboard.Focus(textBox);
        e.Handled = true;
    }
}

This is based on code I've found here.

0 votes
answered Jan 28, 2010 by ehsan-zargar-ershadi

I have tested all of them but only the following worked out:

        protected override void OnStartup(StartupEventArgs e) 
        {
            EventManager.RegisterClassHandler(typeof(TextBox), UIElement.PreviewMouseLeftButtonDownEvent,
           new MouseButtonEventHandler(SelectivelyHandleMouseButton), true);
            EventManager.RegisterClassHandler(typeof(TextBox), UIElement.GotKeyboardFocusEvent,
              new RoutedEventHandler(SelectAllText), true);
            EventManager.RegisterClassHandler(typeof(TextBox), UIElement.GotFocusEvent,
              new RoutedEventHandler(GotFocus), true);          
        }

        private static void SelectivelyHandleMouseButton(object sender, MouseButtonEventArgs e)
        {
            var textbox = (sender as TextBox);
            if (textbox != null)
            {
                int hc = textbox.GetHashCode();
                if (hc == LastHashCode)
                {
                    if (e.OriginalSource.GetType().Name == "TextBoxView")
                    {
                        e.Handled = true;
                        textbox.Focus();
                        LastHashCode = -1;
                    }
                }
            }
            if (textbox != null) textbox.Focus();
        }

        private static void SelectAllText(object sender, RoutedEventArgs e)
        {
            var textBox = e.OriginalSource as TextBox;
            if (textBox != null)
                textBox.SelectAll();
        }

        private static int LastHashCode;
        private static void GotFocus(object sender, RoutedEventArgs e)
        {
            var textBox = e.OriginalSource as TextBox;
            if (textBox != null)
                LastHashCode = textBox.GetHashCode();
        }
0 votes
answered Jan 31, 2010 by grokys

Donnelle's answer works the best, but having to derive a new class to use it is a pain.

Instead of doing that I register handlers the handlers in App.xaml.cs for all TextBoxes in the application. This allows me to use a Donnelle's answer with standard TextBox control.

Add the following methods to your App.xaml.cs:

public partial class App : Application
{
    protected override void OnStartup(StartupEventArgs e) 
    {
        // Select the text in a TextBox when it receives focus.
        EventManager.RegisterClassHandler(typeof(TextBox), TextBox.PreviewMouseLeftButtonDownEvent,
            new MouseButtonEventHandler(SelectivelyIgnoreMouseButton));
        EventManager.RegisterClassHandler(typeof(TextBox), TextBox.GotKeyboardFocusEvent, 
            new RoutedEventHandler(SelectAllText));
        EventManager.RegisterClassHandler(typeof(TextBox), TextBox.MouseDoubleClickEvent,
            new RoutedEventHandler(SelectAllText));
        base.OnStartup(e); 
    }

    void SelectivelyIgnoreMouseButton(object sender, MouseButtonEventArgs e)
    {
        // Find the TextBox
        DependencyObject parent = e.OriginalSource as UIElement;
        while (parent != null && !(parent is TextBox))
            parent = VisualTreeHelper.GetParent(parent);

        if (parent != null)
        {
            var textBox = (TextBox)parent;
            if (!textBox.IsKeyboardFocusWithin)
            {
                // If the text box is not yet focused, give it the focus and
                // stop further processing of this click event.
                textBox.Focus();
                e.Handled = true;
            }
        }
    }

    void SelectAllText(object sender, RoutedEventArgs e)
    {
        var textBox = e.OriginalSource as TextBox;
        if (textBox != null)
            textBox.SelectAll();
    }
}
0 votes
answered Jan 21, 2011 by pintag

For those interested in Donnelle's/Groky's approach, but want a click to the right of the last character (but still within the TextBox) to place the caret at the end of the entered text, I've come up with this solution:

    int GetRoundedCharacterIndexFromPoint(TextBox textBox, Point clickedPoint)
    {
        int position = textBox.GetCharacterIndexFromPoint(clickedPoint, true);

        // Check if the clicked point is actually closer to the next character
        // or if it exceeds the righmost character in the textbox
        // (in this case return increase the position by 1)
        Rect charLeftEdge = textBox.GetRectFromCharacterIndex(position, false);
        Rect charRightEdge = textBox.GetRectFromCharacterIndex(position, true);
        double charWidth = charRightEdge.X - charLeftEdge.X;
        if (clickedPoint.X + charWidth / 2 > charLeftEdge.X + charWidth) position++;

        return position;
    }

    void SelectivelyIgnoreMouseButton(object sender, MouseButtonEventArgs e)
    {
        // Find the TextBox
        DependencyObject parent = e.OriginalSource as UIElement;
        while (parent != null && !(parent is TextBox))
            parent = VisualTreeHelper.GetParent(parent);

        if (parent != null)
        {
            var textBox = (TextBox)parent;
            if (!textBox.IsKeyboardFocusWithin)
            {
                // If the text box is not yet focused, give it the focus and
                // stop further processing of this click event.
                textBox.Focus();
                e.Handled = true;
            }
            else
            {
                int pos = GetRoundedCharacterIndexFromPoint(textBox, e.GetPosition(textBox));
                textBox.CaretIndex = pos;
            }
        }
    }

    void SelectAllText(object sender, RoutedEventArgs e)
    {
        var textBox = e.OriginalSource as TextBox;
        if (textBox != null)
            textBox.SelectAll();
    }

The GetRoundedCharacterIndexFromPoint method was taken from this post.

0 votes
answered Jan 27, 2011 by ted

This seems to work well for me. It's basically a recap of some earlier posts. I just put this into my MainWindow.xaml.cs file in the constructor. I create two handlers, one for keyboard, and one for the mouse, and funnel both events into the same function, HandleGotFocusEvent, which is defined right after the constructor in the same file.

public MainWindow()
{
   InitializeComponent();

   EventManager.RegisterClassHandler(typeof(TextBox), 
      UIElement.GotKeyboardFocusEvent,
      new RoutedEventHandler(HandleGotFocusEvent), true);
   EventManager.RegisterClassHandler(typeof(TextBox),
      UIElement.GotMouseCaptureEvent,
      new RoutedEventHandler(HandleGotFocusEvent), true);   
}
private void HandleGotFocusEvent(object sender, RoutedEventArgs e)
{
   if (sender is TextBox)
      (sender as TextBox).SelectAll();
}
0 votes
answered Jan 29, 2011 by danield

I have a slightly simplified answer for this (with just the PreviewMouseLeftButtonDown event) which seems to mimic the usual functionality of a browser:

In xaml you have a textbox say:

<TextBox Text="http://www.blabla.com" BorderThickness="2" BorderBrush="Green" VerticalAlignment="Center" Height="25"
                 PreviewMouseLeftButtonDown="SelectAll" />

In codebehind:

private void SelectAll(object sender, MouseButtonEventArgs e)
{

    TextBox tb = (sender as TextBox);

    if (tb == null)
    {
        return;
    }

    if (!tb.IsKeyboardFocusWithin)
    {
        tb.SelectAll();
        e.Handled = true;
        tb.Focus();
    }
}
Welcome to Q&A, where you can ask questions and receive answers from other members of the community.
Website Online Counter

...