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() 从舞台中移除特定符号?