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

时间:2010-05-26 15:41:41

标签: wpf textbox focus

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

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

我没有任何问题为编辑开头的值设置文本。

问题是要删除元素的焦点。我不想将焦点移到任何其他组件,我只是希望TextBox失去焦点。我是否必须有一个不可见的元素来设置焦点,以便我的TextBox可以失去焦点?

10 个答案:

答案 0 :(得分:127)

.NET Framework 4中的

只是Keyboard.ClearFocus();

答案 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();
    }
}