A while back I was creating an application that needed to allow fast and accurate input. In WPF, the default behavior of the TextBox on focus is to put the cursor where it was the last time the TextBox had lost focus or if it hasn’t had focus yet, at the beginning. The users of the application wanted this to be changed so that when the TextBox got focus, all current text was selected. I found various ways to do this, but am putting this blog post together to get everything I ended up doing all in one place for easy access.
Basic Focus – GotFocus Event vs. GotKeyboardFocus Event
There is a decision to be made here. In the application that had me working on this stuff for the first time, I chose the GotKeyboardFocus Event. The difference is really that GotFocus will fire when your TextBox gets focus from within the application (or Window), but not when your Window/Application regains focus. GotKeyboardFocus will fire anytime your TextBox gains or regains keyboard focus. So if you are working with something like AvalonDock and have various sections (i.e. DockableContent) that accept input and want your TextBoxes to select all when each section regains focus use the GotKeyboardFocus event. If your application is one where users will be multi-tasking a lot causing your window to constantly lose and regain focus and you don’t want all of the text to get selected each time they come back to your application, you’d use the GotFocus event.
Sample Handler:
- private void TextBox_SelectAllText(object sender, RoutedEventArgs e)
- {
- ((TextBox)sender).SelectAll();
- }
Mouse Focus: PreviewMouseDown Event
Just using GotFocus or GotKeyboardFocus doesn’t give us what we want when someone clicks into the TextBox. You’ll see it quickly select all, then deselect and put the cursor where you clicked. Using the PreviewMouseDown event, you can check if the TextBox already has Keyboard focus and if it doesn’t, select everything. The example below also checks for a triple click…and selects all if it is a triple click.
- /// <summary>
- /// Handles PreviewMouseDown Event. Selects all on Triple click.
- /// If SelectAllOnEnter is true, when the textbox is clicked and doesn't already have keyboard focus, selects all
- /// </summary>
- /// <param name="sender"></param>
- /// <param name="e"></param>
- private void TextBox_SelectivelyIgnoreMouseButton(object sender, MouseButtonEventArgs e)
- {
- // If its a triple click, select all text for the user.
- if (e.ClickCount == 3)
- {
- TextBox_SelectAllText(sender, new RoutedEventArgs());
- return;
- }
- // Find the TextBox
- DependencyObject parent = e.OriginalSource as UIElement;
- while (parent != null && !(parent is TextBox))
- {
- parent = System.Windows.Media.VisualTreeHelper.GetParent(parent);
- }
- if (parent != null)
- {
- if (parent is TextBox)
- {
- 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;
- }
- }
- }
- }
Application-Wide Event Handlers
Now of course, in every Window, User Control, View, etc., you don’t want to have to add these event handlers to each and every TextBox. To easily and quickly attach these handlers to every TextBox within your application you can use the EventManager class to register these event handlers to the TextBox class application-wide. I put these in the event handler for the Application.Startup event.
- private void Application_Startup(object sender, StartupEventArgs e)
- {
- EventManager.RegisterClassHandler(typeof(TextBox), TextBox.GotFocusEvent, new RoutedEventHandler(TextBox_SelectAllText));
- EventManager.RegisterClassHandler(typeof(TextBox), TextBox.PreviewMouseDownEvent, new MouseButtonEventHandler(TextBox_SelectivelyIgnoreMouseButton));
- }
Pingback: Windows Client Developer Roundup 072 for 6/13/2011 - Pete Brown's 10rem.net
Greg, I’m back in WPF and using your SelectAll code in my current project. Brilliant!
great job !!!
Great, thanks.
One comment, though: When a window is loaded and the first text box is selected, this happens before binding takes place, so if binding then sets the text of that text box, it is not selected. I fixed it by checking the IsLoaded property of the text box, and if it was false, I called the SelectAll method using BeginInvoke on the UI dispatcher, so it will only occur after binding has occurred.
Thanks splintor, that issue hasn’t been brought to me yet, but your fix worked like a charm!
Great, but there is one bug. If you select text by triple click, all text in another textobexes is now selected by one click event no by triple click. So I added another part
1. Register next event to deselect text EventManager.RegisterClassHandler(typeof(TextBox), TextBox.GotFocusEvent, new RoutedEventHandler(TextBox_DeselectAllText));
2. Add code after if (e.ClickCount == 3)..
if (e.ClickCount == 1)
{
TextBox_DeselectAllText(sender, new RoutedEventArgs());
return;
}
3. Add event to deselect text user don§t use triplesclick
private void TextBox_DeselectAllText(object sender, RoutedEventArgs e)
{
((TextBox) sender).SelectionStart = 0;
((TextBox) sender).SelectionLength = 0;
}
Now everythink is OK, When user use triple click, next textboxes haven§t got selected all text without use another tripleclick 🙂
Killerlop,
That is how I designed it to work. If you look at the name of the blog post, it is “Select All on Focus“, it isn’t just about selecting all on a triple click.
Regards,
Greg
Good Stuff -this really helped me with the lostfocus problem I have been dealing with
Pingback: The Baltz Blog | WPF DataGrid set focus and mark text
nice very userful thanks