我想在我的WPF TextBox
中添加一个简单的(至少我认为是)行为。
当用户按下Escape时,我希望他正在编辑的TextBox
包含用户开始编辑时的文本,并且我想从TextBox
中移除焦点。
我没有任何问题为编辑开头的值设置文本。
问题是要删除元素的焦点。我不想将焦点移到任何其他组件,我只是希望TextBox
失去焦点。我是否必须有一个不可见的元素来设置焦点,以便我的TextBox
可以失去焦点?
答案 0 :(得分:127)
答案 1 :(得分:50)
我一直在使用的代码:
// 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);
答案 2 :(得分:17)
派对有点晚了,但这对我很有帮助,所以就这样了。
自.Net 3.0以来,FrameworkElement
有一个MoveFocus函数可以帮助我。
答案 3 :(得分:9)
您可以将焦点设置为可聚焦的祖先。即使文本框位于同一模板内没有可聚焦祖先的模板内,此代码也能正常工作:
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 :(得分:6)
AFAIK,无法完全消除焦点。窗口中的某些内容始终具有焦点。
答案 5 :(得分:1)
在Windows Phone开发中,我刚刚在 PhoneApplicationPage 中执行了Focus()
或this.Focus()
,它就像魅力一样。
答案 6 :(得分:1)
由于以上答案均不适用于我,并且接受的答案仅对键盘焦点有效,因此我采用以下方法:
// Kill logical focus
FocusManager.SetFocusedElement(FocusManager.GetFocusScope(textBox), null);
// Kill keyboard focus
Keyboard.ClearFocus();
同时杀死逻辑和键盘焦点。
答案 7 :(得分:1)
使用 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();
}
}
有了这个,我不需要为每个文本框添加一个focuslost,它可以很容易地扩展到其他元素,而不会破坏与程序其他部分的兼容性。
答案 8 :(得分:0)
对我来说,这非常棘手,尤其是在与LostFocus绑定一起使用时。 但是,我的解决方法是添加一个空标签并关注它。
<Label Name="ResetFocusArea" Focusable="True" FocusVisualStyle="{x:Null}" />
...
OnKeyDown(object sender, RoutedEventArgs e)
{
//if is Esc
ResetFocusArea.Focus();
}
答案 9 :(得分:0)
我的回答没有直接解决上述问题,但是,我觉得它的措辞已使它成为关于以编程方式摆脱焦点的“问题”。常见的情况是用户需要在鼠标左键单击根控件(如窗口)的背景时清除焦点。
因此,要实现此目的,您可以创建一个附加行为,该行为会将焦点切换到动态创建的控件(在我的情况下为空标签)。最好在Windows等最高级别的元素上使用此行为,因为它会遍历其子级来查找可以添加虚拟标签的面板。
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();
}
}