215

It seems that when a WPF application starts, nothing has focus.

This is really weird. Every other framework I've used does just what you'd expect: puts initial focus on the first control in the tab order. But I've confirmed that it's WPF, not just my app -- if I create a new Window, and just put a TextBox in it, and run the app, the TextBox doesn't have focus until I click on it or press Tab. Yuck.

My actual app is more complicated than just a TextBox. I have several layers of UserControls within UserControls. One of those UserControls has Focusable="True" and KeyDown/KeyUp handlers, and I want it to have the focus as soon as my window opens. I'm still somewhat of a WPF novice, though, and I'm not having much luck figuring out how to do this.

If I start my app and press the Tab key, then focus goes to my focusable control, and it starts working the way I want. But I don't want my users to have to hit Tab before they can start using the window.

I've played around with FocusManager.FocusedElement, but I'm not sure which control to set it on (the top-level Window? the parent that contains the focusable control? the focusable control itself?) or what to set it to.

What do I need to do to get my deeply-nested control to have initial focus as soon as the window opens? Or better yet, to focus the first focusable control in the tab order?

12 Answers 12

197

This works, too:

<Window FocusManager.FocusedElement="{Binding ElementName=SomeElement}">

   <DataGrid x:Name="SomeElement">
     ...
   </DataGrid>
</Window>
3
  • 4
    I'm surprised I'm the first person who commented on this. I was confused as to where this went because it could go on almost any control. In answer to this specific question, I think it would go on the window, but you can read the remarks on msdn.microsoft.com/en-us/library/… to understand how the control you attach this to matters. Commented Jul 1, 2014 at 23:07
  • I have used this approach on a stackpanel with success. If one is interested, there is an example at stackoverflow.com/a/2872306/378115 Commented Dec 17, 2016 at 0:35
  • 1
    This worked for me much better than accepted answer because I need to put focus on element that is after first. Commented Aug 1, 2017 at 12:28
177

I had the bright idea to dig through Reflector to see where the Focusable property is used, and found my way to this solution. I just need to add the following code to my Window's constructor:

Loaded += (sender, e) =>
    MoveFocus(new TraversalRequest(FocusNavigationDirection.First));

This will automatically select the first control in the tab order, so it's a general solution that should be able to be dropped into any window and Just Work.

9
  • 21
    Add turn that into a behavior. <Window FocusBehavior.FocusFirst="true"> ... </Window>
    – wekempf
    Commented May 8, 2009 at 16:08
  • 6
    @wekempf, I wasn't familiar with the idea of behaviors, but I looked into it and that's not a bad idea at all. If anyone else (like me) isn't already familiar with attached behaviors, here's an explanation: codeproject.com/KB/WPF/AttachedBehaviors.aspx
    – Joe White
    Commented May 9, 2009 at 13:43
  • 1
    Additionally, this works if the desired element is a UserControl which contains the actual focusable element (even in deep hierarchies). Great! Commented May 21, 2015 at 10:08
  • 1
    Great idea, but sometimes it doesn't work if the control that would accept focus is a Button. To fix this, I flip the MoveFocus call over the dispatcher at ContextIdle priority (Background or higher does not work). Also, there is a FocusNavigationDirection.First that matches the intent better and does the same thing in this case. Commented Apr 15, 2017 at 8:18
  • that should be the default behavior! Yuck (in original post) is right!
    – NH.
    Commented May 30, 2017 at 23:47
68

Based on the accepted answer implemented as an attached behavior:

using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;

namespace UI.Behaviors
{
    public static class FocusBehavior
    {
        public static readonly DependencyProperty FocusFirstProperty =
            DependencyProperty.RegisterAttached(
                "FocusFirst",
                typeof(bool),
                typeof(FocusBehavior),
                new PropertyMetadata(false, OnFocusFirstPropertyChanged));

        public static bool GetFocusFirst(Control control)
        {
            return (bool)control.GetValue(FocusFirstProperty);
        }

        public static void SetFocusFirst (Control control, bool value)
        {
            control.SetValue(FocusFirstProperty, value);
        }

        static void OnFocusFirstPropertyChanged(
            DependencyObject obj, DependencyPropertyChangedEventArgs args)
        {
            Control control = obj as Control;
            if (control == null || !(args.NewValue is bool))
            {
                return;
            }

            if ((bool)args.NewValue)
            {
                control.Loaded += (sender, e) =>
                    control.MoveFocus(new TraversalRequest(FocusNavigationDirection.First));
            }
        }
    }
}

Use it like this:

<Window xmlns:Behaviors="clr-namespace:UI.Behaviors"
        Behaviors:FocusBehavior.FocusFirst="true">
5
  • 6
    In my opinion, this is by far the best solution I have found. Thanks!
    – Shion
    Commented Mar 21, 2014 at 14:23
  • 1
    There is a bug in the code in this answer in the call to DependencyProperty.RegisterAttached. The third parameter should be typeof(FocusBehavior), not typeof(Control). Making this change will prevent the designer from reporting 'FocusFirst' property already registered by 'Control' errors. Commented Mar 10, 2016 at 18:58
  • @TonyVitabile Fixed. You are always free to edit and improve answers if you can. :)
    – Mizipzor
    Commented Apr 1, 2016 at 14:13
  • 1
    Shouldn't control.Loaded event handler be deregistered during unload?
    – andreapier
    Commented Sep 21, 2016 at 14:58
  • @andreapier You could if you cared, but skipping the deregister wouldn't cause a memory leak or anything. You only need to worry about events causing memory leaks if a short-lived object has a method being attached to an event on a long-lived object. In this case, the lifetime is that of the window, so you're fine.
    – Joe White
    Commented Oct 20, 2016 at 15:52
14

I found another possible solution. Mark Smith posted a FirstFocusedElement markup extension for use with FocusManager.FocusedElement.

<UserControl x:Class="FocusTest.Page2"
    xmlns:FocusTest="clr-namespace:FocusTest"
    FocusManager.FocusedElement="{FocusTest:FirstFocusedElement}">
3
  • Totally slick! Thank you!
    – Andy
    Commented May 10, 2017 at 2:13
  • broken link, can you please explain @Joe White
    – paraJdox1
    Commented Jul 30, 2021 at 6:38
  • @Hacki I updated the broken link, thanks for the heads-up.
    – Joe White
    Commented Aug 5, 2021 at 21:44
9

After having a 'WPF Initial Focus Nightmare' and based on some answers on stack, the following proved for me to be the best solution.

First, add your App.xaml OnStartup() the followings:

EventManager.RegisterClassHandler(typeof(Window), Window.LoadedEvent,
          new RoutedEventHandler(WindowLoaded));

Then add the 'WindowLoaded' event also in App.xaml :

void WindowLoaded(object sender, RoutedEventArgs e)
    {
        var window = e.Source as Window;
        System.Threading.Thread.Sleep(100);
        window.Dispatcher.Invoke(
        new Action(() =>
        {
            window.MoveFocus(new TraversalRequest(FocusNavigationDirection.First));

        }));
    }

The threading issue must be use as WPF initial focus mostly fails due to some framework race conditions.

I found the following solution best as it is used globally for the whole app.

Hope it helps...

Oran

1
  • 8
    Use BeginInvoke instead of that scary Sleep(100) statement.
    – l33t
    Commented Nov 23, 2016 at 22:23
9

Had same problem solved it with simple solution: In the main window:

  <Window ....
        FocusManager.FocusedElement="{Binding ElementName=usercontrolelementname}"
         ... />

In the user control:

private void UserControl_GotFocus_1(object sender, RoutedEventArgs e)
        {
            targetcontrol.Focus();
            this.GotFocus -= UserControl_GotFocus_1;  // to set focus only once
        }
1
  • 4
    Only works if the control is directly inside the Window, not if it's nested inside a UserControl.
    – Joe White
    Commented Feb 16, 2013 at 16:34
9

You can easily have the control set itself as the focused element in XAML.

<Window>
   <DataGrid FocusManager.FocusedElement="{Binding RelativeSource={RelativeSource Self}}">
     ...
   </DataGrid>
</Window>

I've never tried setting this in a usercontrol and seeing if this works, but it may.

4
  • It sounds interesting, because you don't have do name the control just for a focus issue. In the other hand, my test with user control did not work.
    – heringer
    Commented Oct 9, 2015 at 16:23
  • That doesn't surprise me @heringer... that would be like trying to set focus on a <border> or similar non-interactive control. You could try applying this FocusedElement attribute on an interactive control inside the usercontrol. But that may not be an option. Commented Oct 11, 2015 at 2:06
  • I have used this approach on a stackpanel to set which child button I wanted to focus once the form is loaded. Thanks a lot Commented Dec 17, 2016 at 0:32
  • Be careful, it may make bindings totally broken. stackoverflow.com/questions/30676863/… Commented Feb 6, 2018 at 11:53
3

A minimal version of Mizipzor's answer for C# 6+.

public static class FocusBehavior
{
    public static readonly DependencyProperty GiveInitialFocusProperty =
        DependencyProperty.RegisterAttached(
            "GiveInitialFocus",
            typeof(bool),
            typeof(FocusBehavior),
            new PropertyMetadata(false, OnFocusFirstPropertyChanged));

    public static bool GetGiveInitialFocus(Control control) => (bool)control.GetValue(GiveInitialFocusProperty);
    public static void SetGiveInitialFocus(Control control, bool value) => control.SetValue(GiveInitialFocusProperty, value);

    private static void OnFocusFirstPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
    {
        var control = obj as Control;

        if (control == null || !(args.NewValue is bool))
            return;

        if ((bool)args.NewValue)
            control.Loaded += OnControlLoaded;
        else
            control.Loaded -= OnControlLoaded;
    }

    private static void OnControlLoaded(object sender, RoutedEventArgs e) => ((Control)sender).MoveFocus(new TraversalRequest(FocusNavigationDirection.Next));
}

Use in your XAML:

<Window local:FocusBehavior.GiveInitialFocus="True" />
2

Above solution was not working as expected for me, I've changed slightly the behavior proposed by Mizipzor as following:

From this part

if ((bool)args.NewValue)
        {
            control.Loaded += (sender, e) =>
                   control.MoveFocus(new TraversalRequest(FocusNavigationDirection.Next));
        }

To this

if ((bool)args.NewValue)
        {
            control.Loaded += (sender, e) => control.Focus();
        }

ANd I'm not attaching this behavior to Window or UserControl, but to control I want to focus initially, e.g.:

<TextBox ui:FocusBehavior.InitialFocus="True" />

Oh, sorry for different naming I'm using InitialFocus name for the attached property.

And this is working for me, maybe it could help someone else.

1

If you are like me, and you are using some frameworks that, somehow, mess up with the basic focus behaviors, and make all solutions above irrelevant, you can still do this :

1 - Note the element which get the focus (whatever it is!)

2 - Add this in your code behind xxx.xaml.cs

private bool _firstLoad;

3 - Add this on the element which get the first focus :

GotFocus="Element_GotFocus"

4 - Add the Element_GotFocus method in the code behind, and specify the WPF named element who need the first focus :

private void Element_GotFocus(object sender, RoutedEventArgs e)
{
    if(_firstLoad)
    {
        this.MyElementWithFistFocus.Focus();
        _firstLoad = false;
    }
}

5 - Manage the Loaded event

in XAML

Loaded="MyWindow_Loaded"   

in xaml.cs

private void MyWindow_Loaded(object sender, RoutedEventArgs e)
{
        _firstLoad = true;
        this.Element_GotFocus(null, null);
}

Hope this will help as a last resort solution

0

I also faced the same problem. I had three text boxes inside canvas container and wanted the first text box to be focused when the user control opens. WPF code followed MVVM pattern. I created a separate behavior class for focusing the element and binded it to my view like this.

Canvas behavior code

public  class CanvasLoadedBehavior : Behavior<Canvas>
{
    private Canvas _canvas;
    protected override void OnAttached()
    {
        base.OnAttached();
        _canvas = AssociatedObject as Canvas;
        if (_canvas.Name == "ReturnRefundCanvas")
        {

            _canvas.Loaded += _canvas_Loaded;
        }


    }

    void _canvas_Loaded(object sender, RoutedEventArgs e)
    {
        FocusNavigationDirection focusDirection = FocusNavigationDirection.Next;

        // MoveFocus takes a TraveralReqest as its argument.
        TraversalRequest request = new TraversalRequest(focusDirection);
        UIElement elementWithFocus = Keyboard.FocusedElement as UIElement;
        if (elementWithFocus != null)
        {
            elementWithFocus.MoveFocus(request);
        }

    }

}

Code for view

<Canvas  Name="ReturnRefundCanvas" Height="200" Width="1466" DataContext="{Binding RefundSearchViewModel}">
                <i:Interaction.Behaviors>
                    <b:CanvasLoadedBehavior />
                </i:Interaction.Behaviors>
                <uc:Keyboard Canvas.Left="973" Canvas.Top="111" ToolTip="Keyboard" RenderTransformOrigin="-2.795,9.787"></uc:Keyboard>
                <Label  Style="{StaticResource Devlbl}" Canvas.Left="28" Content="Return and Refund Search" Canvas.Top="10" />
                <Image Height="30" Width="28" Canvas.Top="6" Canvas.Left="5" Source="pack://application:,,,/HomaKiosk;component/images/searchF.png">
                    <Image.OpacityMask>
                        <ImageBrush ImageSource="pack://application:,,,/HomaKiosk;component/images/searchF.png"/>
                    </Image.OpacityMask>
                </Image>

                <Separator Height="4" Canvas.Left="6" Margin="0" Canvas.Top="35" Width="1007"/>

                <ContentControl Canvas.Top="45" Canvas.Left="21"
                    ContentTemplate="{StaticResource ErrorMsg}"
                    Visibility="{Binding Error, Converter={c:StringNullOrEmptyToVisibilityConverter}}" 
                    Content="{Binding Error}" Width="992"></ContentControl>

                <Label  Style="{StaticResource Devlbl}" Canvas.Left="29" Name="FirstName" Content="First Name" Canvas.Top="90" />
                <wpf:AutoCompleteTextBox  Style="{StaticResource AutoComp}" Height="32" Canvas.Left="33" ToolTip="First Name"  Canvas.Top="120" Width="205"                     Padding="10,5" TabIndex="1001"
                    VerticalAlignment="Top"

                    Watermark=""
                    IconPlacement="Left"
                    IconVisibility="Visible"
                    Delay="100"

                    Text="{Binding FirstName, Mode=TwoWay, TargetNullValue=''}" 
                    Provider="{Binding FirstNameSuggestions}">
                    <wpf:AutoCompleteTextBox.ItemTemplate>
                        <DataTemplate>
                            <Border Padding="5">
                                <StackPanel Orientation="Vertical">
                                    <TextBlock Text="{Binding}"
                   FontWeight="Bold" />
                                </StackPanel>
                            </Border>
                        </DataTemplate>
                    </wpf:AutoCompleteTextBox.ItemTemplate>
                </wpf:AutoCompleteTextBox>

                <Label Style="{StaticResource Devlbl}" Canvas.Left="250" Content="Last Name" Canvas.Top="90" />
                <wpf:AutoCompleteTextBox  Style="{StaticResource AutoComp}" Height="32" ToolTip="Last Name" Canvas.Left="250"  Canvas.Top="120" Width="205" Padding="10,5"  TabIndex="1002"
                    VerticalAlignment="Top"
                    Watermark=""
                    IconPlacement="Left"
                    IconVisibility="Visible"
                    Delay="100"
                   Text="{Binding LastName, Mode=TwoWay, TargetNullValue=''}" 
                    Provider="{Binding LastNameSuggestions}">
                    <wpf:AutoCompleteTextBox.ItemTemplate>
                        <DataTemplate>
                            <Border Padding="5">
                                <StackPanel Orientation="Vertical">
                                    <TextBlock Text="{Binding}"
                   FontWeight="Bold" />
                                </StackPanel>
                            </Border>
                        </DataTemplate>
                    </wpf:AutoCompleteTextBox.ItemTemplate>
                </wpf:AutoCompleteTextBox>

                <Label Style="{StaticResource Devlbl}" Canvas.Left="480" Content="Receipt No" Canvas.Top="90" />
                             <wpf:AutoCompleteTextBox  Style="{StaticResource AutoComp}" Height="32" ToolTip="Receipt No" Canvas.Left="480"  Canvas.Top="120" Width="205" Padding="10,5"  TabIndex="1002"
                    VerticalAlignment="Top"
                    Watermark=""
                    IconPlacement="Left"
                    IconVisibility="Visible"
                    Delay="100"
                    Text="{Binding ReceiptNo, Mode=TwoWay, TargetNullValue=''}" 
                    Provider="{Binding ReceiptIdSuggestions}">
                    <wpf:AutoCompleteTextBox.ItemTemplate>
                        <DataTemplate>
                            <Border Padding="5">
                                <StackPanel Orientation="Vertical" >
                                    <TextBlock Text="{Binding}"
                   FontWeight="Bold">

                                    </TextBlock>
                                </StackPanel>
                            </Border>
                        </DataTemplate>
                    </wpf:AutoCompleteTextBox.ItemTemplate>
                    <i:Interaction.Behaviors>
                        <b:AllowableCharactersTextBoxBehavior RegularExpression="^[0-9]+$" MaxLength="15" />
                    </i:Interaction.Behaviors>
                </wpf:AutoCompleteTextBox>
                <!--<Label Style="{StaticResource Devlbl}" Canvas.Left="710" Content="Duration" Canvas.Top="79" />-->
                <!--<ComboBox AllowDrop="True" Canvas.Left="710" ToolTip="Duration" Canvas.Top="107" Width="205" TabIndex="1004"
                    Style="{StaticResource CommonComboBox}"      
                    ItemsSource="{Binding Durations}" DisplayMemberPath="Description" SelectedValuePath="Id" SelectedValue="{Binding SelectedDate, Mode=TwoWay}">

                </ComboBox>-->

                <Button Content="Search" Style="{StaticResource MyButton}" ToolTip="Search" 
                    Canvas.Top="116" Canvas.Left="710" Cursor="Hand" 
                    Command="{Binding SearchCommand}" TabIndex="2001">
                </Button>
                <Button Content="Clear" Style="{StaticResource MyButton}"  ToolTip="Clear"
                    Canvas.Top="116" Canvas.Left="840" Cursor="Hand" 
                    Command="{Binding ClearCommand}" TabIndex="2002">
                </Button>
                <Image Height="25" Width="25" Canvas.Top="175" Canvas.Left="25" Source="pack://application:,,,/HomaKiosk;component/images/chkpending.png"/>
                <Label  Style="{StaticResource LegendLbl}" Canvas.Left="50" Content="Check Returned and Payment Pending" Canvas.Top="178" />
                <Image Height="25" Width="25" Canvas.Top="175" Canvas.Left="300" Source="pack://application:,,,/HomaKiosk;component/images/chkrepaid.png"/>
                <Label  Style="{StaticResource LegendLbl}" Canvas.Left="325" Content="Repaid" Canvas.Top="178" />
                <Image Height="25" Width="25" Canvas.Top="175" Canvas.Left="395" Source="pack://application:,,,/HomaKiosk;component/images/refund.png"/>
                <Label  Style="{StaticResource LegendLbl}" Canvas.Left="415" Content="Refunded" Canvas.Top="178" />
                 </Canvas>
-1
<Window FocusManager.FocusedElement="{Binding ElementName=yourControlName}">
2

Not the answer you're looking for? Browse other questions tagged or ask your own question.