WPF: How to programmatically remove focus from a TextBox

WpfTextboxFocus

Wpf Problem Overview


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?

Wpf Solutions


Solution 1 - Wpf

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

Solution 2 - Wpf

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);

Solution 3 - Wpf

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.

Solution 4 - Wpf

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.

Solution 5 - Wpf

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);
}

Solution 6 - Wpf

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

Solution 7 - Wpf

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();
}

Solution 8 - Wpf

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

Solution 9 - Wpf

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();
    }
}

Solution 10 - Wpf

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.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionjpsstavaresView Question on Stackoverflow
Solution 1 - WpfLPLView Answer on Stackoverflow
Solution 2 - WpfdecasteljauView Answer on Stackoverflow
Solution 3 - WpfCycloneView Answer on Stackoverflow
Solution 4 - WpfSuperOliView Answer on Stackoverflow
Solution 5 - WpfJulian DominguezView Answer on Stackoverflow
Solution 6 - WpfbitbonkView Answer on Stackoverflow
Solution 7 - WpfBrian NgView Answer on Stackoverflow
Solution 8 - WpfBruno LemosView Answer on Stackoverflow
Solution 9 - WpfTripleAccretionView Answer on Stackoverflow
Solution 10 - WpfStefan H. TanderupView Answer on Stackoverflow