WPF: How to programmatically remove focus from a TextBox
Asked Answered
M

11

118

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?

Moncada answered 26/5, 2010 at 15:41 Comment(0)
S
176

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

Surmullet answered 9/1, 2012 at 16:32 Comment(7)
This was exactly what I was looking for this evening!Creighton
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.Disannul
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."Thaothapa
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().Clangor
@Thaothapa 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.Tiatiana
@Tiatiana exactly what I needed. thanks for your solution.Borne
Works in .NET 6.0 as well.Abmho
M
61

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);
Minnieminnnie answered 26/5, 2010 at 15:53 Comment(11)
This code is great, Keyboard.ClearFocus() has some unintended side effectsShing
Why the condition !((IInputElement)parent).Focusable have "!" infront? Shouldn't this condition be true if parent is focusable?Grudging
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.Salvage
@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.Tolbutamide
@patrick, which unintended side effects? Could you give relevant examples?Disannul
@Disannul 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.Thaothapa
@Thaothapa 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();?Disannul
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.Cussedness
If you want to detect the currently selected textbox add this to the start -> var textBox = Keyboard.FocusedElement as Windows.Controls.TextBox;Rost
@Disannul 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.Brahmanism
Unfortunately, this solution causes a dotted outline to appear around the focused parent.Reef
I
42

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.

Iconography answered 18/5, 2019 at 3:5 Comment(1)
Thanks so much, I had tried every other way of moving the focus elsewhere, yours was the one that worked.Niggardly
B
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.

Birdiebirdlike answered 2/10, 2013 at 18:48 Comment(2)
For instructions -> msdn.microsoft.com/en-us/library/…Rost
"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." - msdn.microsoft.com/en-us/library/…Leone
A
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);
}
Arching answered 5/11, 2010 at 18:30 Comment(0)
S
6

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

Spongy answered 26/5, 2010 at 15:44 Comment(0)
S
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();
}
Snuggery answered 18/4, 2019 at 10:56 Comment(0)
Z
4

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.

Zugzwang answered 9/4, 2021 at 8:1 Comment(0)
S
2

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

Scatterbrain answered 15/6, 2014 at 1:11 Comment(0)
P
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();
    }
}
Planer answered 10/5, 2019 at 20:54 Comment(0)
T
1

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

textBox.Focusable = false;
Tropaeolin answered 10/1, 2023 at 5:12 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.