Introduction
I had a task to set focus on the first control of a RadTilePane
that was very dynamic. By this, I mean that the control was the Content
of a ContentControl
using a DataTemplate
with a DataType
that used the DataContext
to determine the DataTemplate
. I read everything, and must have tried everything but nothing worked. Controls have a Focus()
method and there is also the FocusManager
. I am sure that the Focus()
method uses the FocusManager
in some way to give the control focus. Finally, I started using the GotFocus
event, the FocusManager
. GetFocusedElement() and the Debug.Print
method to try to understand what was happening. I tried setting the Focus
on the Loaded
and Initialized
events for the UserControl
, but neither worked. To make things even weirder, that was control that was getting focus, but is seemed like it was the last one being created. Finally, I decided to try a delay and that worked.
Using the Code
This is what I ended up putting in the constructor of the UserControl
:
Initialized += (sender, args) =>
{
var t = Task.Run(() => Task.Delay(250)).ContinueWith(x =>
{
_password.Focus();
}, TaskScheduler.FromCurrentSynchronizationContext());
};
and it worked.
Conclusion
Before I found this solution, I had struggled with the focus issue numerous times, especially since it was significant enough to the customer for me to spend so much time on it. I will no longer avoid the WPF after this since I understand that the FocusManager
suffers from contention with the creation of the VisualTree
. I would have thought that Microsoft would have dealt with any issues of timing that would require any such code to be used by developers, but, again, I am wrong. Maybe this will help you quickly solve your focus problem. I set 250 milliseconds for the delay since this seemed that it was short enough that it should not cause any usability issues. A second I think is too long.
Also want to note how clean and easy the implementation is using TPL, which provides a Task.Run
, ContinueWith
, and a Task.Delay
, along with the TaskScheduler.FromCurrentSynchronizationContext()
. It seems that people still rely heavily on the BackgroundWorker
, and I cannot understand why.
History
- 08/25/2015: First version