我想要在我的WPF TextBox
中添加一个简单的(至少我认为是简单的)行为。
当用户按下Escape键时,我希望他正在编辑的TextBox
拥有它开始编辑时的文本,并且我想将焦点从TextBox
中移除。
我没有任何问题来设置文本以便它在编辑开始时有价值。
问题在于如何移除元素的焦点。我不想将焦点移到任何其他组件,我只想让TextBox
失去焦点。我需要创建一个不可见的元素来设置焦点吗,以便我的TextBox
可以失去焦点?
我一直在使用的代码:
// 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);
ClearFocus
会导致最近获得焦点的控件不会触发 GotFocus
事件,而其他控件仍会触发。这对于我的自定义屏幕键盘来说是一个大问题。 - Grault因为以上回答都对我没有用,而被接受的答案仅适用于键盘焦点,所以我采取了以下方法:
// Kill logical focus
FocusManager.SetFocusedElement(FocusManager.GetFocusScope(textBox), null);
// Kill keyboard focus
Keyboard.ClearFocus();
会导致逻辑和键盘焦点都失效。
有点晚了,但这对我很有帮助,以下是内容。
自从.Net 3.0以来,FrameworkElement
拥有一个MoveFocus函数,这对我起到了作用。
DependencyObject ancestor = textbox.Parent;
while (ancestor != null)
{
var element = ancestor as UIElement;
if (element != null && element.Focusable)
{
element.Focus();
break;
}
ancestor = VisualTreeHelper.GetParent(ancestor);
}
对我来说,这很棘手,尤其是在使用LostFocus绑定时。 然而,我的解决方法是添加一个空标签并聚焦于它。
<Label Name="ResetFocusArea" Focusable="True" FocusVisualStyle="{x:Null}" />
...
OnKeyDown(object sender, RoutedEventArgs e)
{
//if is Esc
ResetFocusArea.Focus();
}
使用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();
}
}
因此,为了实现这一点,您可以创建一个附加行为,将焦点切换到动态创建的控件(在我的情况下是空标签)。最好将此行为用于最高级别的元素,例如窗口,因为它会遍历其子元素以查找可以添加虚拟标签的面板。
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();
}
}
PhoneApplicationPage
中使用Focus()
或者this.Focus()
,就可以轻松实现聚焦。
Keyboard.ClearFocus()
并且点击其他地方后,ListBox中的AutoCompleteTextBox无法失去焦点。这并不总是清除焦点。 - ANevesother.Focus()
实现。 - Tor Klingberg