WPF - Remove focus when clicking outside of a textbox

45,930

Solution 1

Rather than adding new control to window, I think you should give your Grid a name and react to the MouseDown event on your window, moving the focus to the Grid itself. Something like this:

<Window x:Class="WpfApplication1.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    Title="Window1" 
    Height="412" Width="569" 
    MouseDown="Window_MouseDown" 
    Name="window1">

    <Grid ShowGridLines="False" 
          Background="#01FFFFFF"
          KeyDown="Grid_KeyDown" 
          Name="grid1" 
          Focusable="True">

          <TextBox Width="120" Margin="117,61,0,0" 
                   Name="textBox1" 
                   VerticalAlignment="Top" 
                   HorizontalAlignment="Left"/>
    </Grid>
</Window>

code behind:

private void window1_MouseDown(object sender, MouseButtonEventArgs e)
{
    grid1.Focus();
}

Solution 2

I think, better way to solve this problem is adding MouseDown event handler to window with code behind:

private void window_MouseDown(object sender, MouseButtonEventArgs e)
{
    Keyboard.ClearFocus();
}

Solution 3

I have tried the selected answer in react native WPF application but it was not triggering lost focus of textbox due to which textbox was not losing the focus. Following solution work for me.

Bound a mouse-down event to Window:

<Window x:Class="WpfApplication1.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    Title="Window1" Height="412" Width="569" MouseDown="window_MouseDown" Name="window1" >
    <Grid ShowGridLines="False" KeyDown="Grid_KeyDown" Name="grid1" Focusable="True">
          <TextBox HorizontalAlignment="Left" Margin="117,61,0,0" Name="textBox1" VerticalAlignment="Top" Width="120" />
    </Grid>
</Window>

and event is:

private void window_MouseDown(object sender, MouseButtonEventArgs e)
{
    TextBox textBox = Keyboard.FocusedElement as TextBox;
    if (textBox != null)
    {
        TraversalRequest tRequest = new TraversalRequest(FocusNavigationDirection.Next);
        textBox.MoveFocus(tRequest);
    }
}

Solution 4

To avoid code behind you can use this Behavior The behavior

 public class ClearFocusOnClickBehavior : Behavior<FrameworkElement>
 {
    protected override void OnAttached()
    {
        AssociatedObject.MouseDown += AssociatedObject_MouseDown;
        base.OnAttached();
    }

    private static void AssociatedObject_MouseDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
    {
        Keyboard.ClearFocus();
    }

    protected override void OnDetaching()
    {
        AssociatedObject.MouseDown -= AssociatedObject_MouseDown;
    }
}

Useing in XAML:

On any element outside the text box that you want him to clear the focus on click add:

    <i:Interaction.Behaviors>
        <behaviors:ClearFocusOnClickBehavior/>
    </i:Interaction.Behaviors>

Solution 5

Another way that worked for me was using

Mouse.AddPreviewMouseDownOutsideCapturedElementHandler

For example, say you had a TextBlock that when clicked, should become editable by showing a focused TextBox. Then when the user clicked outside the TextBox, it should be hidden again. Here's how you can do it:

private void YourTextBlock_OnMouseDown(object sender, MouseButtonEventArgs e)
{
    YourTextBox.Visibility = Visibility.Visible;
    YourTextBox.Focus();
    CaptureMouse();
    Mouse.AddPreviewMouseDownOutsideCapturedElementHandler(this, OnMouseDownOutsideElement);
}

private void OnMouseDownOutsideElement(object sender, MouseButtonEventArgs e)
{
    Mouse.RemovePreviewMouseDownOutsideCapturedElementHandler(this, OnMouseDownOutsideElement);
    ReleaseMouseCapture();
    YourTextBox.Visibility = Visibility.Hidden;
}
Share:
45,930
JacobJ
Author by

JacobJ

Senior Principal software engineer at a Biomedical company. Author of the WPF Sound Visualization library (wpfsvl.codeplex.com)

Updated on November 16, 2021

Comments

  • JacobJ
    JacobJ over 2 years

    I have some textboxes where I would like focus to behave a little differently than normal for a WPF application. Basically, I would like them to behave more like a textbox behaves on a webpage. That is, if I click anywhere outside of the textbox, it will lose its focus. What is the best way to do so?

    If the answer is to programmatically remove focus, what is the best way to detect a Mouseclick outside of the bounds? What if the element I'm clicking on will be the new recipient of focus?

  • JacobJ
    JacobJ almost 13 years
    Ah, this worked. To expand on the solution, there is no need to name the window either - just override OnMouseDown for a slightly cleaner bit of XAML.
  • JacobJ
    JacobJ almost 13 years
    I tried this before asking the question, and it didn't quite do it. In addition to setting Focusable on the container element, I needed to actually manually set focus on mousedown as per Charlie Sharma's solution.
  • love Computer science
    love Computer science almost 13 years
    @JacobJ: oops.. what i wanted to write was add name to your 'grid' not window. Edited. thanks for pointing out!
  • Merlyn Morgan-Graham
    Merlyn Morgan-Graham almost 13 years
    I tried it out too. Not sure why, but this isn't working for me. LostFocus isn't getting called for the text boxes I have in my window.
  • love Computer science
    love Computer science almost 13 years
    @ Merlyn Morgan-Graham: In simple words, what you need to do is, Add Name Property to your grid, make grid focusable, on mouse down event of window: set focus to that grid. is that what you have tried?
  • Merlyn Morgan-Graham
    Merlyn Morgan-Graham almost 13 years
    @Charlie: "make grid focusable" is the part I missed. Thanks! +1
  • Anyone
    Anyone over 10 years
    I don't have much knowledge regarding this, but won't this also clear the focus when pressing on the textfield itself?
  • Liero
    Liero about 9 years
    No, because if you click on textbox, the click event is handled by textbox and it is not routed to window. Therefore Windows.MouseDown is never called when you click on textbox.
  • user3162662
    user3162662 almost 8 years
    make sure your grid has non-transparent background color, else it cannot respond to mousedown event.
  • skiwi
    skiwi almost 8 years
    This prevents the LostFocus event from being called on the text box.
  • Brandon Hood
    Brandon Hood about 7 years
    I know I'm a little late, but this is (approximately) the solution I went with for this very same issue I just wanted to reply to the thing @skiwi presented. I was able to get around this by grabbing Keyboard.FocusedElement before clearing focus, then doing element.RaiseEvent(new RoutedEventArgs(UIElement.LostFocusEvent)) -- I had to do this because my TextBox's border depends on focus state.
  • J'swier
    J'swier almost 5 years
    I think you mean wrapping a scrollviewer around your textboxes not the other way around. Suggested an edit. Wrapping a scrollviewer around my textbox solved the issue
  • maets
    maets almost 5 years
    You should cast e.NewValue to bool instead
  • Meow Cat 2012
    Meow Cat 2012 almost 5 years
    Not working unless having a MessageBox.Show within YourTextBlock_OnMouseDown. CaptureMouse returns true and OnMouseDownOutsideElement won't be called.
  • Admin
    Admin over 4 years
    This actually works great, and just saved me a bunch of frustration. Thanks!
  • Ian Campbell
    Ian Campbell over 3 years
    While this code snippet may be the solution, including an explanation helps to improve the quality of your post. Remember that you are answering the question for readers in the future, and those people might not know the reasons for your code suggestion.
  • hesed
    hesed over 3 years
    You can also to omit the name of the grid: ((sender as Window).Content as Grid).Focus();.
  • birgersp
    birgersp over 2 years
    @user3162662: The background color doesn't need to be non-transparent. But it needs to be specified (i.e. not null) for the mousedown event to be fired. You can use Background="Transparent" and the event will fire.
  • Felix
    Felix almost 2 years
    Unfortuntely, this will only be of limited use when you have the TextBox contained inside a UserControl. The "lose focus" functionality is then limited to the area of the user control.
  • Josh Noe
    Josh Noe almost 2 years
    This doesn't work when you have other controls in your window that handle the click, because then the click event won't bubble up to the window. So in most cases, this is a limited solution.
  • Josh Noe
    Josh Noe almost 2 years
    This might work under certain situations, but I found it extremely finicky. YMMV.