views:

5094

answers:

8

I have a UserControl which contains a TextBox. When my main window loads I want to set the focus to this textbox so I added Focusable="True" GotFocus="UC_GotFocus" to the UserControls definition and FocusManager.FocusedElement="{Binding ElementName=login}" to my main windows definition. In the UC_GotFocus method i simply call .Focus() on the control i want to focus on but this doesn't work.

All i need to do is have a TextBox in a UserControl receive focus when the application starts.

Any help would be appreciated, thanks.

+2  A: 

WPF supports two different flavors of focus:

  1. Keyboard focus
  2. Logical focus

The FocusedElement property gets or sets logical focus within a focus scope. I suspect your TextBox does have logical focus, but its containing focus scope is not the active focus scope. Ergo, it does not have keyboard focus.

So the question is, do you have multiple focus scopes in your visual tree?

HTH, Kent

Kent Boogaart
Hmmm, i know nothing of Focus Scopes. Time for some research! cheers Kent.
Stimul8d
I could be wrong but I thought I read somewhere that UserControls have their own implicit FocusScope. Perhaps if this is true then the answer to whether the original poster has multiple focus scopes in their visual tree is obviously YES!.
jpierson
+1  A: 

Just recently I had a list-box that housed some TextBlocks. I wanted to be able to double click on the text block and have it turn into a TextBox, then focus on it and select all the text so the user could just start typing the new name (Akin to Adobe Layers)

Anyway, I was doing this with an event and it just wasn't working. The magic bullet for me here was making sure that I set the event to handled. I figure it was setting focus, but as soon as the event went down the path it was switching the logical focus.

The moral of the story is, make sure you're marking the event as handled, that might be your issue.

Vassi
+1  A: 

I've noticed a focus issue specifically related to hosting WPF UserControls within ElementHosts which are contained within a Form that is set as an MDI child via the MdiParent property.

I'm not sure if this is the same issue others are experiencing but you dig into the details by following the link below.

Issue with setting focus within a WPF UserControl hosted within an ElementHost in a WindowsForms child MDI form

jpierson
+5  A: 

I recently fixed this problem for a login splash screen that is being displayed via a storyboard when the main window is first loaded.

I believe there were two keys to the fix. One was to make the containing element a focus scope. The other was to handle the Storyboard Completed event for the storyboard that was triggered by the window being loaded.

This storyboard makes the username and password canvas visible and then fades into being 100% opaque. The key is that the username control was not visible until the storyboard ran and therefore that control could not get keyboard focus until it was visible. What threw me off for awhile was that it had "focus" (i.e. focus was true, but as it turns out this was only logical focus) and I did not know that WPF had the concept of both logical and keyboard focus until reading Kent Boogaart's answer and looking at Microsoft's WPF link text

Once I did that the solution for my particular problem was straightforward:

1) Make the containing element a focus scope

<Canvas FocusManager.IsFocusScope="True" Visibility="Collapsed">
 <TextBox x:Name="m_uxUsername" AcceptsTab="False" AcceptsReturn="False">
 </TextBox>
</Canvas>

2) Attach a Completed Event Handler to the Storyboard

    <Storyboard x:Key="Splash Screen" Completed="UserNamePassword_Storyboard_Completed">
...
</Storyboard>

and

3) Set my username TextBox to have the keyboard focus in the storyboard completed event handler.

void UserNamePassword_Storyboard_Completed(object sender, EventArgs e)
{
 m_uxUsername.Focus();
}

Note that calling item.Focus() results in the call Keyboard.Focus(this), so you don't need to call this explicitly. See this question about the difference between Keyboard.Focus(item) and item.Focus.

eesh
Cool, well Kent has enough points and you gave a fully answer. cheers man.
Stimul8d
Thanks Stimul8d!
eesh
+1  A: 
  1. Set your user control to Focusable="True" (XAML)
  2. Handle the GotFocus event on your control and call yourTextBox.Focus()
  3. Handle the Loaded event on your window and call yourControl.Focus()

I have a sample app running with this solution as I type. If this does not work for you, there must be something specific to your app or environment that causes the problem. In your original question, I think the binding is causing the problem. I hope this helps.

Josh Fischer
+5  A: 

Its stupid but it works:

Pop a thread that waits a while then comes back and sets the focus you want. It even works within the context of an element host.

private void ListView_SelectionChanged(object sender, SelectionChangedEventArgs e)
{

 System.Threading.ThreadPool.QueueUserWorkItem(
                   (a) =>
                        {
                            System.Threading.Thread.Sleep(100);
                            someUiElementThatWantsFocus.Dispatcher.Invoke(
                            new Action(() =>
                            {
                                someUiElementThatWantsFocus.Focus();

                            }));
                        }
                   );

}
fuzquat
I agree this is not something I like to use, but the most robust mechanism I found so far. There are some circumstances where uiElement.Focus() returns false, race conditions, CommandBindings etc. If all I know is, that in the end I should be able to Focus, then I have indeed used this now, because it's too time consuming to try all other methods at runtime (unit tests are hard to write for this). Still I wouldn't recommend it as a best-practice, but rahter ultima ratio.
Simpzon
+2  A: 

I found a good series of blog posts on WPF focus.

http://www.julmar.com/blog/mark/2008/09/02/Part1ItsBasicallyFocus.aspx

http://www.julmar.com/blog/mark/2008/09/04/Part2ChangingWPFFocusInCode.aspx

http://www.julmar.com/blog/mark/2008/09/12/Part3ShiftingFocusToTheFirstAvailableElementInWPF.aspx

They are all good to read, but the 3rd part specifically deals with setting focus to a UI element in a UserControl.

Ashley Davis
+1  A: 

“When setting initial focus at application startup, the element to receive focus must be connected to a PresentationSource and the element must have Focusable and IsVisible set to true. The recommended place to set initial focus is in the Loaded event handler" (MSDN)

Simply add a "Loaded" event handler in the constructor of your Window (or Control), and in that event handler call the Focus() method on the target control.

    public MyWindow() {
        InitializeComponent();
        this.Loaded += new RoutedEventHandler(MyWindow_Loaded);
    }

    void MyWindow_Loaded(object sender, RoutedEventArgs e) {
        textBox.Focus();
    }
David