21

have a TextBox item (MyTextBox) on a TabItem control. I have code that looks as follows:

MyTextBox.Focus();
Keyboard.Focus(MyTextBox);

When I run this code through the debugger I see the following after the lines are executed:

MyTextBox.IsFocused = true
MyTextBox.IsKeyboardFocused = false

Can anyone tell me why the textbox isn't receiving keyboard focus? It's just a standard TextBox control that is enabled.

Randy Minder
  • 47,200
  • 49
  • 204
  • 358

6 Answers6

9

When you try to set Focus to an element besides the things enumerated above by our coleague, you must also know that WPF does not allow cross threaded operations.

In some cases this exception is not raised like in the Focus method call case. What I've done to fix this issue is to call all the code that involves Keyboards focus in an action.

This action is ran inside the control dispatcher to make sure that my code is not being executed from another thread than the UI thread (e.g. timer event or an event raised from another thread):

[UIElement].Dispatcher.BeginInvoke(
      new Action(
         delegate{
             /// put your Focus code here
         }
      )
);
Stephan
  • 41,764
  • 65
  • 238
  • 329
Silviu
  • 99
  • 1
  • 2
9

MyTextBox.IsKeyboardFocused is false because you are looking at it under debugger and the keyboard focus is probably in your Visual Studio... Try debugging focus without breakpoints (e.g. Debug.Write or trace brakepoints) to see actual values of MyTextBox.IsKeyboardFocused in runtime.

Also notice that Focus() method returns boolean value that indicates whether focus was successfully set. Does it return False in your case? If yes, I would suggest stepping into Focus() method in order to find out what is wrong.

Fredrik Hedblad
  • 83,499
  • 23
  • 264
  • 266
Pavlo Glazkov
  • 20,498
  • 3
  • 58
  • 71
  • 1
    Just want to point out that Control.focus() returns a boolean. Keyboard.Focus() returns an IInputElement (https://learn.microsoft.com/en-us/dotnet/api/system.windows.input.keyboard.focus) – bluegreen Oct 29 '20 at 23:26
8

3 important properties must be true: IsVisible="True", Focusable="True". IsEnabled="True".

To be focusable, Focusable and IsEnabled must both be true.

http://msdn.microsoft.com/en-us/library/system.windows.uielement.focus.aspx

slavoo
  • 5,798
  • 64
  • 37
  • 39
legrandviking
  • 2,348
  • 1
  • 22
  • 29
  • 1
    Thanks for this, I had been trying to set the focus before a `Visibility` `Binding` had refreshed (solved with `MyTextBox.GetBindingExpression(VisibilityProperty).UpdateTarget();`). `MyTextBox.SelecAll()` is also magically working now. :) – Chris Mack Jul 17 '19 at 13:26
2

The accepted answer here does not solve the problem of textboxes who dont gain focus, no matter what the debugger tells you. If you have and can write to your textbox, then you have it keyboard-focused.

I found this here solving the problem (and actually gaining focus, not just settings the values so it looks like focus in the debugger), it comes very close to Pavlov's answer but with the "Focus code" : Keyboard.Focus does not work on text box in WPF

Community
  • 1
  • 1
Marv
  • 119
  • 3
  • 14
2

It's important where your first two lines of code are executed.

If they are in an event handler that relates to the user pressing a key, using the mouse, altering the visibility of a control, or otherwise taking an action that might have an impact on focus, I find manually calling Focus() often doesn't work.

My theory is that internally, WPF operates as follows:

  1. User or code takes action which could have an impact on focus, e.g. a TextBox control becomes enabled inside a focus scope which previously had no focusable control.
  2. WPF notifies various event handlers, including yours which calls Focus().
  3. WPF updates focus based on the state changes in step 1. This overrides whatever you did in step 2.

That is why this answer suggests to call your Focus() in a queued callback which will be executed after step 3.

Side note: you don't need to call both UIElement.Focus and Keyboard.Focus since the first includes the second (at least if you trust the Microsoft docs).

In conclusion, replace your first two lines of code with this:

// using System.Windows.Threading;
Dispatcher.BeginInvoke(DispatcherPriority.Input, MyTextBox.Focus);
Hugh W
  • 716
  • 2
  • 10
  • 33
1

This worked for me (had to do UpdateLayout, otherwise Focus() didn't work immediately after changing tab from script)

tabControl.SelectedIndex = 2;
this.UpdateLayout();
txtMyTextBox.Focus();
mgear
  • 1,333
  • 2
  • 22
  • 39