114

I want to add a simple (at least I thought it was) behaviour to my WPF TextBox.

When the user presses Escape I want the TextBox he is editing to have the text it had when the user started editing, AND I want to remove the focus from the TextBox.

I don't have any problem setting the text for the value it had in the beginning of the edit.

The problem is to remove the focus of the element. I don't want to move the focus to any other component, I just want the TextBox to lose focus. Will I have to have an invisible element to set the focus so my TextBox can lose focus?

jpsstavares
  • 3,303
  • 5
  • 25
  • 32

11 Answers11

172

in .NET Framework 4 just Keyboard.ClearFocus();

LPL
  • 16,827
  • 6
  • 51
  • 95
  • 1
    This was exactly what I was looking for this evening! – Josh Jun 26 '12 at 05:28
  • 9
    This does not always clear focus: I have a problem where an AutoCompleteTextBox inside a ListBox does not lose focus when I run `Keyboard.ClearFocus()` from code-behind after a click somewhere. – ANeves Jul 30 '15 at 11:10
  • 3
    `ClearFocus` causes `GotFocus` to not fire for the recently focused control while it still fires for other controls. That's a big problem for my custom onscreen keyboard, for example. It does cause the caret to disappear, which is probably all that "keyboard focus" entails. Maybe I'm more interested in something like "mouse focus." – Grault Mar 03 '16 at 22:16
  • 4
    Thank you Grault, I got the same problem. The best I have come up with is to move focus to some other control with `other.Focus()`. – Tor Klingberg Aug 18 '16 at 09:31
  • 7
    @Grault This only clears the keyboard focus, not the logical focus (which is what fires to the `GotFocus` event). There is always something with logical focus in your program. Either use the `LostKeyboardFocus` event or shift focus to another element (which shifts logical focus along with it) before clearing keyboard focus. – Chirimorin Feb 20 '17 at 09:48
  • @Chirimorin exactly what I needed. thanks for your solution. – Tobias Koller Sep 13 '17 at 16:00
  • Works in .NET 6.0 as well. – Michal Diviš Nov 28 '22 at 12:55
60

The code I have been using :

// Move to a parent that can take focus
FrameworkElement parent = (FrameworkElement)textBox.Parent;
while (parent != null && parent is IInputElement && !((IInputElement)parent).Focusable)
{
    parent = (FrameworkElement)parent.Parent;
}

DependencyObject scope = FocusManager.GetFocusScope(textBox);
FocusManager.SetFocusedElement(scope, parent as IInputElement);
decasteljau
  • 7,655
  • 10
  • 41
  • 58
  • 3
    This code is great, Keyboard.ClearFocus() has some unintended side effects – patrick Feb 16 '12 at 16:28
  • Why the condition !((IInputElement)parent).Focusable have "!" infront? Shouldn't this condition be true if parent is focusable? – Mert Akcakaya Mar 30 '12 at 12:42
  • Mert - not sure but just browsing through this post it looks like by continuing looping until that condition is true is the point. That way the first focusable item terminates the loop. – jpierson Oct 20 '12 at 10:24
  • @Mert - if parent is not focusable then parent is set in the loop to the parent's parent. At the point that the parent is focusable, the loop stops and the parent is focused. – junichiro Apr 19 '13 at 09:54
  • 4
    @patrick, **which** unintended side effects? Could you give relevant examples? – ANeves Sep 22 '14 at 19:06
  • @ANeves 2 years late, but `ClearFocus` causes `GotFocus` to not fire for the recently focused control while it still fires for other controls. That's a big problem for my custom onscreen keyboard, for example. – Grault Feb 29 '16 at 20:53
  • @Grault not too late though :) , because the question that suggests ClearFocus() is still the accepted one. Would you add your example to that top-voted answer that suggests to use `Keyboard.ClearFocus();`? – ANeves Mar 01 '16 at 11:55
  • 4
    This is a great solution. I also had problems with Keyboard.ClearFocus(). When running ClearFocus() on a TextBox inside a modal Window, it causes both the TextBox and the Window to lose focus. Meaning KeyDown events no longer go to the Window. By instead changing it so the Focus changes to a parent (which may be the Window), the future KeyDown events are not lost. In my practical example, I have the Window looking for "Key.Escape" and calling Close(). This stops working if you run ClearFocus() anywhere. – Denis P Feb 08 '17 at 23:34
  • If you want to detect the currently selected textbox add this to the start -> `var textBox = Keyboard.FocusedElement as Windows.Controls.TextBox;` – Carter Medlin Apr 13 '17 at 15:59
  • @ANeves it removes focus from the whole window. I want to take focus away from a TextBox and allow its parent window to respond to PreviewKeyDown event. `ClearFocus()` just removes focus completely from the window when I tried it. – Simon_Weaver Oct 25 '17 at 01:25
  • 1
    Unfortunately, this solution causes a dotted outline to appear around the focused parent. – redcurry Aug 18 '20 at 22:33
40

Since none of the above answers worked for me and the accepted answer does work only for a keyboard focus, I came to the following approach:

// Kill logical focus
FocusManager.SetFocusedElement(FocusManager.GetFocusScope(textBox), null);
// Kill keyboard focus
Keyboard.ClearFocus();

Kills both, logical as well as the keyboard focus.

Cyclone
  • 14,839
  • 23
  • 82
  • 114
  • 2
    Thanks so much, I had tried every other way of moving the focus elsewhere, yours was the one that worked. – Derf Skren Sep 03 '21 at 05:19
19

A bit late to the party, but it was helpful to me so here it goes.

Since .Net 3.0, FrameworkElement has a MoveFocus function which did the trick for me.

SuperOli
  • 1,784
  • 1
  • 11
  • 23
  • For instructions -> https://msdn.microsoft.com/en-us/library/system.windows.frameworkelement.movefocus.aspx – Carter Medlin Apr 13 '17 at 15:14
  • "Make sure you check the return value of this method. A return value of false might be returned if the traversal runs into a tab stop that is defined by a control's composition, and the traversal request did not request to wrap." - https://msdn.microsoft.com/en-us/library/system.windows.uielement.movefocus(v=vs.110).aspx – aderesh Mar 28 '18 at 17:45
9

You can set the focus to a focusable ancestor. This code will work even if the textbox is inside a template with no focusable ancestors inside that same template:

DependencyObject ancestor = textbox.Parent;
while (ancestor != null)
{
    var element = ancestor as UIElement;
    if (element != null && element.Focusable)
    {
        element.Focus();
        break;
    }

    ancestor = VisualTreeHelper.GetParent(ancestor);
}
Julian Dominguez
  • 2,573
  • 21
  • 15
6

AFAIK, it is not possible to completely remove the focus. Something in your Window will always have the focus.

bitbonk
  • 48,890
  • 37
  • 186
  • 278
5

For me, it's quite tricky, especially when using with LostFocus binding. However, my workaround is to add an empty label and focus on it.

<Label Name="ResetFocusArea" Focusable="True" FocusVisualStyle="{x:Null}" />

...

OnKeyDown(object sender, RoutedEventArgs e)
{
  //if is Esc
  ResetFocusArea.Focus();
}
Brian Ng
  • 1,005
  • 12
  • 13
3

Using LPL's answer worked for me, but it would also make me unable to select any options in dropdown menues. To combat this, I added a check to see if the focused element was a textbox.

Doing the same check for when pressing enter, my final code looked like this:

    public Menu()
    {
        InitializeComponent();
        this.PreviewMouseDown += PreviewMouseDownEventHandler;
        this.KeyDown += WindowKeyDownHandler;
    }
    void ClearFocus()
    {
        UIElement elementWithFocus = Keyboard.FocusedElement as UIElement;
        if (elementWithFocus is System.Windows.Controls.TextBox tb)
        {
            if (Keyboard.FocusedElement != null)
            {
                Keyboard.FocusedElement.RaiseEvent(new RoutedEventArgs(UIElement.LostFocusEvent));
                Keyboard.ClearFocus();
            }
        }
    }

    private void PreviewMouseDownEventHandler(object sender, MouseButtonEventArgs e)
    {
        ClearFocus();
    }
    private void WindowKeyDownHandler(object sender, System.Windows.Input.KeyEventArgs e)
    {
        if (e.Key == Key.Enter)
        {
            ClearFocus();
        }
    }

With this, I didn't need to add a focuslost to every textbox, and it can easily extend to other elements without breaking compatability with other parts of the program.

2

In Windows Phone Development, I just did Focus() or this.Focus() in the PhoneApplicationPage and it worked like a charm.

Bruno Lemos
  • 8,847
  • 5
  • 40
  • 51
2

My answer does not adress the above question directly, however, I feel that the wording of it has caused it to become "The Question" about programmatically getting rid of focus. A common scenario where this is needed is for the user to be able to clear focus upon left-clicking the background of a root control, like window.

So, to achieve this, you can create an Attached Behavior that will switch focus to a dynamically created control (in my case, an empty label). It is preferrable to use this behavior on the highest-level elements like windows, as it iterates through it's children to find a panel it can add a dummy label to.

public class LoseFocusOnLeftClick : Behavior<FrameworkElement>
{
    private readonly MouseBinding _leftClick;
    private readonly Label _emptyControl = new Label() { Focusable = true, HorizontalAlignment = HorizontalAlignment.Left, VerticalAlignment = VerticalAlignment.Top };

    public LoseFocusOnLeftClick()
    {
        _leftClick = new MouseBinding(new RelayCommand(LoseFocus), new MouseGesture(MouseAction.LeftClick));
    }

    protected override void OnAttached()
    {
        AssociatedObject.InputBindings.Add(_leftClick);
        AssociatedObject.Loaded += AssociatedObject_Loaded;
    }        

    protected override void OnDetaching()
    {
        AssociatedObject.InputBindings.Remove(_leftClick);
        AssociatedObject.Loaded -= AssociatedObject_Loaded;
    }

    private void AssociatedObject_Loaded(object sender, RoutedEventArgs e)
    {
        AssociatedObject.Loaded -= AssociatedObject_Loaded;

        AttachEmptyControl();
    }

    private void AttachEmptyControl()
    {            
        DependencyObject currentElement = AssociatedObject;
        while (!(currentElement is Panel))
        {
            currentElement = VisualTreeHelper.GetChild(currentElement, 0);
        }

        ((Panel)currentElement).Children.Add(_emptyControl);
    }

    private void LoseFocus()
    {            
        _emptyControl.Focus();
    }
}
TripleAccretion
  • 312
  • 3
  • 10
0

If you want to remove focus from a certain TextBox, just add this line..

textBox.Focusable = false;