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 b
It is important to mention that a textbox catches both the mouse and the keyboard events, so in order to move or remove the focus from a text box you have to release these 2 elements.
Let's start with the keyboard, Keyboard.ClearFocus();
will remove the keyboard focus from the textbox, and it's great for hiding the blinking cursor, but won't move the focus from the textbox, in other words the textbox will remain as focused element but without displaying the cursor.
You can check that by printing FocusManager.GetFocusedElement(this);
after Keyboard.ClearFocus();
.
So, if you have a LostFocus
event attached to the textbox or similar event, it will not be triggered because the element has not yet lost focus.
PreviewMouseDown += (s, e) => FocusManager.SetFocusedElement(this, null);
PreviewMouseDown += (s, e) => Keyboard.ClearFocus();
As a solution, you should set the Window focused element to null, by calling:
System.Windows.Input.FocusManager.SetFocusedElement(this, null);
Now if you are wondering if we can get rid of the Keyboard.ClearFocus();
then the answer is no, because we are going to remove the mouse focus, but the keyboard focus will still be there. (you will notice the blinking cursor which is still there, and you will be able to type some text in the textbox).
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>
If you clicked on the element, which can grab the focus, you get what you need. if, for example, you have some panel, you can handle panel's mouseClick event to achive your needs, or use Richard Szalay advice.
public class ClearFocusOnOutsideClickBehavior : Behavior<FrameworkElement>
{
protected override void OnAttached()
{
AssociatedObject.GotFocus += AssociatedObjectOnGotFocus;
AssociatedObject.LostFocus += AssociatedObjectOnLostFocus;
base.OnAttached();
}
private void AssociatedObjectOnLostFocus(object sender, RoutedEventArgs e)
{
App.Current.MainWindow.MouseUp -= _paren_PreviewMouseUp;
}
private void AssociatedObjectOnGotFocus(object sender, RoutedEventArgs e)
{
App.Current.MainWindow.MouseUp += _paren_PreviewMouseUp;
}
private void _paren_PreviewMouseUp(object sender, MouseButtonEventArgs e)
{
Keyboard.ClearFocus();
}
protected override void OnDetaching()
{
AssociatedObject.GotFocus -= AssociatedObjectOnGotFocus;
AssociatedObject.LostFocus -= AssociatedObjectOnLostFocus;
}
}
Using in XAML:
<TextBox Height="30" Width="200">
<i:Interaction.Behaviors>
<behaviours:ClearFocusOnOutsideClickBehavior/>
</i:Interaction.Behaviors>
</TextBox>
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();
}
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);
}
}