C# WPF-在文本框外单击时移除焦点

C# WPF-在文本框外单击时移除焦点,c#,wpf,focus,click,C#,Wpf,Focus,Click,我有一些文本框,我希望焦点的行为与WPF应用程序的正常行为稍有不同。基本上,我希望它们的行为更像网页上的文本框。也就是说,如果我点击文本框之外的任何地方,它就会失去焦点。最好的方法是什么 如果答案是以编程方式移除焦点,那么检测鼠标点击超出边界的最佳方法是什么?如果我正在单击的元素将成为焦点的新接收者,该怎么办?我不是100%确定,但是如果在容器元素(网格、StackPanel等)上将Focusable设置为true,那么它应该会将焦点从文本框中移除。如果您单击可以抓住焦点的元素,您将得到所需的内

我有一些文本框,我希望焦点的行为与WPF应用程序的正常行为稍有不同。基本上,我希望它们的行为更像网页上的文本框。也就是说,如果我点击文本框之外的任何地方,它就会失去焦点。最好的方法是什么


如果答案是以编程方式移除焦点,那么检测鼠标点击超出边界的最佳方法是什么?如果我正在单击的元素将成为焦点的新接收者,该怎么办?

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

如果您单击可以抓住焦点的元素,您将得到所需的内容。例如,如果您有一些面板,您可以处理面板的mouseClick事件以满足您的需要,或者使用Richard Szalay的建议。

与其向窗口添加新控件,我认为您应该为您的网格命名,并对窗口上的MouseDown事件作出反应,将焦点移动到网格本身。大概是这样的:

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

不能显式地失去控件的焦点

您可以改为将焦点设置为其他控件

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

试试这个

我认为,解决这个问题的更好方法是在窗口中添加MouseDown事件处理程序,并隐藏代码:

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

另一种对我有效的方法是使用

Mouse.AddPreviewMouseDownOutsideCapturedElementHandler

例如,假设您有一个文本块,单击该文本块时,应该通过显示一个聚焦的文本框来进行编辑。然后,当用户在文本框外单击时,它应该再次被隐藏。以下是您如何做到这一点:

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

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

您可以使用
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 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;
    }
}
公共类ClearFocusOnClickBehavior:Behavior { 受保护的覆盖无效附加() { AssociatedObject.MouseDown+=AssociatedObject\u MouseDown; base.onatached(); } 私有静态无效关联对象\u MouseDown(对象发送方,System.Windows.Input.MouseButtonEventArgs e) { Keyboard.ClearFocus(); } 附加时受保护的覆盖无效() { AssociatedObject.MouseDown-=AssociatedObject\u MouseDown; } } 在XAML中使用:

在文本框外您希望他清除焦点的任何元素上,单击“添加”:

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

我在react native WPF应用程序中尝试了选择的答案,但它没有触发textbox的焦点丢失,因为textbox没有丢失焦点。下面的解决方案对我有用

将鼠标按下事件绑定到窗口:

<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>
公共类ClearFocusOnOutsideClickBehavior:Behavior
{
受保护的覆盖无效附加()
{
AssociatedObject.GotFocus+=AssociatedObjectOnGotFocus;
AssociatedObject.LostFocus+=AssociatedObjectOnLostFocus;
base.onatached();
}
private void AssociatedObjectOnLostFocus(对象发送方,路由目标)
{
App.Current.MainWindow.MouseUp-=\u paren\u PreviewMouseUp;
}
与ObjectOnGotFocus关联的私有void(对象发送方,RoutedEventTarget e)
{
App.Current.MainWindow.MouseUp+=\u paren\u PreviewMouseUp;
}
私有void _paren _PreviewMouseUp(对象发送器,鼠标按钮ventargs e)
{
Keyboard.ClearFocus();
}
附加时受保护的覆盖无效()
{
AssociatedObject.GotFocus-=AssociatedObjectOnGotFocus;
AssociatedObject.LostFocus-=AssociatedObjectOnLostFocus;
}
}
在XAML中使用:

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

您可以在应用程序启动时将
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;
     }
}

值得一提的是,文本框同时捕获鼠标和键盘事件,因此为了移动或移除文本框的焦点,必须释放这两个元素

让我们从键盘开始,
keyboard.ClearFocus()
将从文本框中删除键盘焦点,它非常适合隐藏闪烁的光标,但不会从文本框中移动焦点,换句话说,文本框将保持为焦点元素,但不显示光标。 您可以通过打印
FocusManager.GetFocusedElement来检查这一点(this)
键盘之后。ClearFocus()

因此,如果将
LostFocus
事件附加到文本框或类似事件,则不会触发该事件,因为元素尚未失去焦点

PreviewMouseDown += (s, e) => FocusManager.SetFocusedElement(this, null);
PreviewMouseDown += (s, e) => Keyboard.ClearFocus();
作为一种解决方案,您应该通过调用以下命令将以窗口为中心的元素设置为null:
System.Windows.Input.FocusManager.SetFocusedElement(这个,null)键盘.ClearFocus()
那么答案是否定的,因为我们将移除鼠标焦点,但键盘焦点仍然存在。(您会注意到闪烁的光标仍在那里,您可以在文本框中键入一些文本)。

如果您单击其他UI元素,文本框会自动失去焦点。@Merlyn Morgan Graham:不,不会。@Charlie:我的评论是针对“如果我单击的元素将成为焦点的新接收者,该怎么办?”我同意,如果用户仅单击框外的任何位置(例如窗口),它不会引发
LostFocus
事件,而是引发另一个可聚焦元素(例如另一个文本框)默林·摩根·格雷厄姆:同意,很明显,如果你点击另一个文本框,上一个文本框会失去焦点,但这不是OP希望它失去焦点的情况
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;
     }
}
PreviewMouseDown += (s, e) => FocusManager.SetFocusedElement(this, null);
PreviewMouseDown += (s, e) => Keyboard.ClearFocus();