27

I am banging my head on what looks like such a simple problem to fix in wpf but i have yet to discover why i can't get my app to behave according to my plan.

I have a small search box that pops-up in my wpf application when user presses ctrl+f. All i want is for the caret to be flashing inside the search box text box, ready to take whatever user input without the user having to click on it. Here is the xaml code for the text box which is visible, enabled, hit testable, tabstopable and focusable.

   <TextBox x:Name="SearchCriteriaTextBox" Text="{Binding SearchCriteria}" Focusable="True" IsEnabled="True" IsTabStop="True" IsHitTestVisible="True" Style="{DynamicResource SearchTextBoxStyle}" Grid.Column="1" Margin="5,10,0,5" />

In the code behind, i have this method called when the visibility of the search box is affected. the search box is loaded at the start of the app.

    /// <summary>
    /// Handles events triggered from focusing on this view.
    /// </summary>
    /// <param name="sender">The sender.</param>
    /// <param name="dependencyPropertyChangedEventArgs">The key event args.</param>
    private void OnIsVisibleChanged(object sender, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
    {
        if (!((bool) dependencyPropertyChangedEventArgs.NewValue))
        {
            return;
        }

        SearchCriteriaTextBox.Focus();
        Keyboard.Focus(SearchCriteriaTextBox);
        SearchCriteriaTextBox.Select(0, 0);

        if (SearchCriteriaTextBox.Text.Length > 0)
        {
            SearchCriteriaTextBox.SelectAll();
        }
    }

The problem is, code gets called, component becomes IsFocused=true but does not gain keyboard focus. Am I missing something? Unless another control keeps hold ferociously to the keyboard focus which i am pretty sure i didn't code, why would this piece of rather simple code would not work properly.

legrandviking
  • 2,348
  • 1
  • 22
  • 29

4 Answers4

82

As a workaround, you could try using the Dispatcher to set the focus at a later DispatcherPriority, such as Input

Dispatcher.BeginInvoke(DispatcherPriority.Input,
    new Action(delegate() { 
        SearchCriteriaTextBox.Focus();         // Set Logical Focus
        Keyboard.Focus(SearchCriteriaTextBox); // Set Keyboard Focus
     }));

From the description of your problem, it sounds like you don't have Keyboard focus set. WPF can have multiple Focus Scopes, so multiple elements can have Logical Focus (IsFocused = true), however only one element can have Keyboard Focus and will receive keyboard input.

The code you posted should set the focus correctly, so something must be occurring afterwards to move Keyboard Focus out of your TextBox. By setting focus at a later dispatcher priority, you'll be ensuring that setting keyboard focus to your SearchCriteriaTextBox gets done last.

Rachel
  • 130,264
  • 66
  • 304
  • 490
  • 2
    Just discovered that , was about to post my own response, thanks Rachel it does work perfectly in a multi threaded environnement. EDIT: You can call Dispatcher.BeginInvoke(DispatcherPriority.Input, new ThreadStart(() => SearchCriteriaTextBox.Focus())); to the same result, without having to call textbox focus – legrandviking Dec 19 '12 at 15:56
  • This works for me: MessageBox.Show("foo"); myTextBox.Select(0, myTextBox.Text.Length); myTextBox.Focus(); – Krafty Dec 26 '14 at 22:29
  • 2
    Does anyone have an explanation for this problem? – Dennis Kassel Oct 23 '17 at 16:51
  • 2
    I tried everything from Keyboard Focus to setting the Focusable to true and the visibility to true and then calling Focus, tried also to FocusManager but this is the only thing that worked. – Devid Aug 29 '18 at 13:13
  • @DennisKassel I have a theory about why this works, see https://stackoverflow.com/a/75507847/1688738. – Hugh W Feb 20 '23 at 10:08
2

Building on Rachel's solution there is a simpler way.

in XAML add to the TextBox Loaded="Got_Loaded"

and in code behind

    private void Got_Loaded(object sender, RoutedEventArgs e)
    {
        Keyboard.Focus(((TextBox)sender));
    }
0

If it helps anyone I had this problem and my application had a main window with multiple user controls placed in separate grids with a visibility data binding. Because the grids were there when the application was built the .Focus() called on Loaded or Constructor would be called at the build time, not at visibility time.

Anyhow I fixed it by calling .Focus() on MouseEnter event of the grid. Works fine for me.

Cristian G
  • 460
  • 1
  • 4
  • 22
0

I encountered the similar problem.

In my case, I need a particular textbox get keyboard focus after a modal window popped up. This would save the user extra effort to move focus into this textbox before he/she can start offering input information.

I tried Window.Loaded += (o, e) => Keyboard.Focus(textBox), but this won't work.

So I used a workaround, and that got the job done, even thought it may not be that elegant.

Here it is:

Window.PreviewKeyDown += Window_PreviewKeyDown;

private void Window_PreviewKeyDown(object sender, KeyEventArgs e) {
    Keyboard.Focus(TextBox);
    Window.PreviewKeyDown -= Window_PreviewKeyDown;
}
west
  • 11
  • 2