WPF:如何以编程方式从 TextBox 中移除焦点

Posted

技术标签:

【中文标题】WPF:如何以编程方式从 TextBox 中移除焦点【英文标题】:WPF: How to programmatically remove focus from a TextBox 【发布时间】:2011-02-24 06:18:52 【问题描述】:

我想向我的 WPF TextBox 添加一个简单的(至少我认为是的)行为。

当用户按下 Escape 时,我希望他正在编辑的 TextBox 拥有用户开始编辑时的文本,并且我想从 TextBox 移除焦点。

将文本设置为编辑开始时的值没有任何问题。

问题是移除元素的焦点。我不想将焦点移动到任何其他组件,我只想让 TextBox 失去焦点。我是否必须有一个不可见的元素来设置焦点,这样我的TextBox 才能失去焦点?

【问题讨论】:

【参考方案1】:

AFAIK,不可能完全移除焦点。 Window 中的某些内容始终是焦点。

【讨论】:

【参考方案2】:

我一直在使用的代码:

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

【讨论】:

这段代码很棒,Keyboard.ClearFocus() 有一些意想不到的副作用 为什么条件 !((IInputElement)parent).Focusable 有 "!"在前?如果父母是可聚焦的,这个条件不应该是真的吗? Mert - 不确定,但只是浏览这篇文章,看起来继续循环直到条件为真才是重点。这样第一个可聚焦的项目就会终止循环。 @patrick,哪些 意外副作用?你能举出相关的例子吗? 这是一个很好的解决方案。我也遇到了 Keyboard.ClearFocus() 的问题。在模式窗口内的 TextBox 上运行 ClearFocus() 时,会导致 TextBox 和 Window 失去焦点。这意味着 KeyDown 事件不再进入窗口。相反,通过更改它使 Focus 更改为父级(可能是 Window),未来的 KeyDown 事件不会丢失。在我的实际示例中,我让窗口寻找“Key.Escape”并调用 Close()。如果您在任何地方运行 ClearFocus(),这将停止工作。【参考方案3】:

您可以将焦点设置为可聚焦的祖先。即使文本框位于同一模板内没有可聚焦祖先的模板内,此代码也将起作用:

DependencyObject ancestor = textbox.Parent;
while (ancestor != null)

    var element = ancestor as UIElement;
    if (element != null && element.Focusable)
    
        element.Focus();
        break;
    

    ancestor = VisualTreeHelper.GetParent(ancestor);

【讨论】:

【参考方案4】:

在 .NET Framework 4 中只是 Keyboard.ClearFocus();

【讨论】:

这正是我今晚要找的! 这并不总是清除焦点:我有一个问题,即在单击某处后从代码隐藏运行 Keyboard.ClearFocus() 时,ListBox 内的 AutoCompleteTextBox 不会失去焦点。 ClearFocus 导致GotFocus 不会为最近聚焦的控件触发,但它仍会为其他控件触发。例如,对于我的自定义屏幕键盘来说,这是一个大问题。它确实会导致插入符号消失,这可能就是“键盘焦点”所需要的全部内容。也许我对“鼠标焦点”之类的东西更感兴趣。 谢谢 Grault,我遇到了同样的问题。我想出的最好方法是使用other.Focus() 将焦点转移到其他控件。 @Grault 这只会清除键盘焦点,而不是逻辑焦点(这是触发GotFocus 事件的原因)。在你的程序中总是有一些具有逻辑焦点的东西。在清除键盘焦点之前,使用LostKeyboardFocus 事件或将焦点转移到另一个元素(逻辑焦点随之转移)。【参考方案5】:

聚会有点晚了,但对我有帮助,所以就这样吧。

从 .Net 3.0 开始,FrameworkElement 有一个 MoveFocus 函数,这对我有用。

【讨论】:

获取说明-> msdn.microsoft.com/en-us/library/… "确保检查此方法的返回值。如果遍历遇到由控件组合定义的制表位,并且遍历请求没有要求包装。” - msdn.microsoft.com/en-us/library/…【参考方案6】:

在 Windows Phone 开发中,我刚刚在 PhoneApplicationPage 中执行了Focus()this.Focus(),它就像一个魅力。

【讨论】:

【参考方案7】:

对我来说,这很棘手,尤其是在使用 LostFocus 绑定时。 但是,我的解决方法是添加一个空标签并专注于它。

<Label Name="ResetFocusArea" Focusable="True" FocusVisualStyle="x:Null" />

...

OnKeyDown(object sender, RoutedEventArgs e)

  //if is Esc
  ResetFocusArea.Focus();

【讨论】:

【参考方案8】:

我的回答并没有直接解决上述问题,但是,我觉得它的措辞导致它成为关于以编程方式摆脱焦点的“问题”。需要这样做的常见场景是用户能够在左键单击根控件(如窗口)的背景时清除焦点。

因此,要实现这一点,您可以创建一个附加行为,它将焦点切换到动态创建的控件(在我的例子中是一个空标签)。最好在***别的元素(如窗口)上使用此行为,因为它会遍历其子元素以找到可以添加虚拟标签的面板。

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

【讨论】:

【参考方案9】:

由于上述答案均不适合我,而接受的答案仅适用于键盘焦点,因此我采用了以下方法:

// Kill logical focus
FocusManager.SetFocusedElement(FocusManager.GetFocusScope(textBox), null);
// Kill keyboard focus
Keyboard.ClearFocus();

同时杀死逻辑和键盘焦点。

【讨论】:

非常感谢,我已经尝试了其他所有方法将焦点转移到其他地方,你的方法很有效。【参考方案10】:

使用 LPL 的答案对我有用,但它也会让我无法在下拉菜单中选择任何选项。为了解决这个问题,我添加了一个检查以查看焦点元素是否是文本框。

按回车时做同样的检查,我的最终代码如下所示:

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

有了这个,我不需要为每个文本框添加一个焦点丢失,它可以很容易地扩展到其他元素,而不会破坏与程序其他部分的兼容性。

【讨论】:

以上是关于WPF:如何以编程方式从 TextBox 中移除焦点的主要内容,如果未能解决你的问题,请参考以下文章

如何从Tkinter,Python中的Text小部件中移除焦点

(Adobe Animate actionscript) 如何使用 name 、 arry 和 lib() 从舞台中移除特定符号?

以编程方式将控件添加到WPF表单

从购物车中移除商品

在 iOS7 中移除 UISearchBar 的边框

从 Android Studio 中移除项目