简体   繁体   English

WPF - 单击文本框外部时移除焦点

[英]WPF - Remove focus when clicking outside of a textbox

I have some textboxes where I would like focus to behave a little differently than normal for a WPF application.我有一些文本框,我希望焦点的行为与 WPF 应用程序的正常情况略有不同。 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?如果我点击的元素将成为焦点的新接收者怎么办?

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.与其向窗口添加新控件,我认为您应该为您的Grid命名并对窗口上的MouseDown事件做出反应,将焦点移至Grid本身。 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 think, better way to solve this problem is adding MouseDown event handler to window with code behind:我认为,解决这个问题的更好方法是将 MouseDown 事件处理程序添加到带有代码的窗口:

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

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.例如,假设您有一个 TextBlock,单击该文本块后,应通过显示聚焦的 TextBox 变为可编辑状态。 Then when the user clicked outside the TextBox, it should be hidden again.然后当用户在 TextBox 外部单击时,它应该再次隐藏。 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;
}

To avoid code behind you can use this Behavior The behavior为了避免背后的代码,你可以使用这个 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:在 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>

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.我已经在 React Native WPF 应用程序中尝试了选定的答案,但它没有触发文本框失去焦点,因为哪个文本框没有失去焦点。 Following solution work for me.以下解决方案对我有用。

Bound a mouse-down event to Window:将鼠标按下事件绑定到 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);
    }
}

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();让我们从键盘开始, 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);您可以通过打印FocusManager.GetFocusedElement(this);来检查它FocusManager.GetFocusedElement(this); after Keyboard.ClearFocus();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.所以,如果你有一个LostFocus事件附加到文本框或类似的事件,它不会被触发,因为元素还没有失去焦点。

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);作为解决方案,您应该通过调用以下方法将 Window 焦点元素设置为 null: System.Windows.Input.FocusManager.SetFocusedElement(this, null); Now if you are wondering if we can get rid of the Keyboard.ClearFocus();现在,如果您想知道我们是否可以摆脱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). (您会注意到闪烁的光标仍然存在,您将能够在文本框中键入一些文本)。

我不是 100% 确定,但是如果您在容器元素(Grid、StackPanel 等)上将Focusable设置为 true,那么它应该将焦点从文本框移开。

我遇到了类似的问题,但是当我在 textboxes 周围包裹一个 ScrollViewer 控件时,单击 texboxes 外的任何地方时,所有文本框都会自动失去焦点。

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.例如,如果您有一些面板,您可以处理面板的 mouseClick 事件以满足您的需求,或者使用 Richard Szalay 的建议。

you cant explicitly loose the focus of a control你不能明确地失去控件的焦点

you can set the focus to other control instead您可以将焦点设置为其他控件

**txt.Focusable=true;
label.focus();
Keyboard.Focus(txtPassword);**

try this尝试这个

You can use the IsKeyboardFocusedChanged event:您可以使用IsKeyboardFocusedChanged事件:

myTextBox.IsKeyboardFocusedChanged += myTextBox_IsKeyboardFocusedChanged;

private void SendFileCaptionTextBox_IsKeyboardFocusedChanged(object sender, DependencyPropertyChangedEventArgs e)
{
    if (e.NewValue.ToString() == "True")
    {
        // it's focused
    }
    else
    {
        // it's not focused
    }
}    
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:在 XAML 中使用:

<TextBox Height="30" Width="200">
            <i:Interaction.Behaviors>
                <behaviours:ClearFocusOnOutsideClickBehavior/>
            </i:Interaction.Behaviors>
 </TextBox>

You can register the PreviewMouseLeftButtonDownEvent to every type of element in App.xaml.cs on application startup.您可以在应用程序启动时将PreviewMouseLeftButtonDownEvent注册到 App.xaml.cs 中的每种类型的元素。

EventManager.RegisterClassHandler(typeof(UIElement), UIElement.PreviewMouseLeftButtonDownEvent,
                new MouseButtonEventHandler(FocusElement));

private void FocusElement(object sender, MouseButtonEventArgs e)
{
     var parent = e.OriginalSource as DependencyObject;
     if (parent is UIElement element && !element.Focusable)
     {
         element.Focusable = true;
         element.Focus();
         element.Focusable = false;
     }
}

This could be done with a small amount of code.这可以通过少量代码来完成。 Just set the window's Focusable="True" where the textboxes or other controls are placed and add this on it's MouseDown event:只需在放置文本框或其他控件的位置设置窗口的Focusable="True"并将其添加到其MouseDown事件中即可:

private void Window_MouseDown(object sender, MouseButtonEventArgs e)
{
     FocusManager.SetFocusedElement(this, this);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM