In this tip, you will see a solution to a bug concerning focus of child controls inside a WPF UserControl.
Introduction
This is my scenario: I have a login usercontrol
in my WPF application that is shown in the main form. On that, I have a UserName textbox
and a Password passwordbox
. When a login is successful, I save the username
for the next application run and automatically populate the username
box with it so that the user does not have to type it again (if it is indeed the same user - which it is in 99.9% of the cases).
So I want my login control to set focus to the username textbox
if it is empty and to the passwordbox
if the username
is filled in.
That proved to be a very difficult task. I must have tried at least 30 different solutions to get that to happen, but they didn't work. No matter WHAT I did, NONE of the boxes would be focused.
Background
First, I tried simply setting focus to the desired control in the Usercontrol
s constructor (after the Initialize
call of course) using:
txtPassword.Focus();
That doesn't work. I also tried the keyboard
method:
Keyboard.Focus(txtPassword);
And (even though that wasn't what I wanted), I tried the XAML FocusManager
method:
FocusManager.FocusedElement="{Binding ElementName=txtPassword}"
No, nothing of that worked.
I noticed the property Focusable
and set it to true
(didn't help, and it turned out in the end that it wasn't even necessary to set it).
I tried the two first methods again, but tried to put them in the Loaded
event, in the GotFocus
event, etc.
I tried setting focus to the parent controls and the entire usercontrol
from the MainForm
.
I tried from a different thread - Nope, didn't work!
I tried several combinations of Dispatcher.BeginInvoke
, but to no avail.
I tried using Sleep();
before the focus events, didn't work...
All articles I found on Google had different solutions, and none of them worked. Some articles claimed it was a bug and that it had been reported to Microsoft. But that wasn't much help of course.
The Code that Did the Trick
After more than 3 hours of trial and error - just on the verge of breakdown, and the painful realization that I ought to just accept that the user was forced to manually click the box to enter the information - I finally came across this:
public LoginControl()
{
InitializeComponent();
this.IsVisibleChanged += new DependencyPropertyChangedEventHandler
(LoginControl_IsVisibleChanged);
}
void LoginControl_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
{
if ((bool)e.NewValue == true)
{
Dispatcher.BeginInvoke(
DispatcherPriority.ContextIdle,
new Action(delegate()
{
txtPassword.Focus();
}));
}
}
Thanks a lot to Oli on StackOverflow - I FINALLY got the problem solved.
Please note: The code above is simplified and just concerns setting the focus to a given control. As you would recall, I wanted the focus to be set on different control based on whether or not one of them contained text. But since it is trivial to adapt the code above for that, I have chosen to keep the eye on the ball.
Finally
I really can't help thinking: Why the heck does it have to be so difficult to solve such a simple problem????
It took me +3 hours just to solve such a reasonably irrelevant issue - time that could have been used to develop far more interesting features.
There might be other solutions, but I've got the problem solved now... I simply decided to share this tip with you if any of you should have the same problem (and also to be able to remember it myself next time).
History
- 17th October, 2012: Initial version