WPF: как программно удалить фокус из TextBox

96

Я хочу добавить простое (по крайней мере, я так думал) поведение в свой WPF TextBox.

Когда пользователь нажимает Escape, я хочу, чтобы TextBoxон редактировал текст, который был, когда пользователь начал редактирование, И я хочу убрать фокус с TextBox.

У меня нет проблем с установкой текста для значения, которое он имел в начале редактирования.

Проблема в том, чтобы убрать фокус элемента. Я не хочу перемещать фокус на какой-либо другой компонент, я просто хочу, TextBoxчтобы он потерял фокус. Должен ли я иметь невидимый элемент, чтобы установить фокус, чтобы я TextBoxмог потерять фокус?

jpsstavares
источник

Ответы:

153

в .NET Framework 4 просто Keyboard.ClearFocus();

LPL
источник
1
Это было именно то, что я искал сегодня вечером!
Джош
9
Это не всегда сбрасывает фокус: у меня проблема, когда AutoCompleteTextBox внутри ListBox не теряет фокус, когда я запускаю Keyboard.ClearFocus()код программной части после щелчка где-то.
Аневс считает SE злом
3
ClearFocusзаставляет GotFocusне срабатывать для недавно сфокусированного элемента управления, пока он все еще срабатывает для других элементов управления. Например, это большая проблема для моей пользовательской экранной клавиатуры. Это вызывает исчезновение каретки, что, вероятно, и есть все, что влечет за собой «фокус клавиатуры». Может меня больше интересует что-то вроде «фокус мыши».
Grault 03
3
Спасибо Грауль, у меня такая же проблема. Лучшее, что я придумал, - это переключить фокус на другой элемент управления other.Focus().
Тор Клингберг
7
@Grault Очищает только фокус клавиатуры, но не логический фокус (который запускает GotFocusсобытие). В вашей программе всегда есть что-то с логической направленностью. Либо используйте LostKeyboardFocusсобытие, либо переместите фокус на другой элемент (который смещает логический фокус вместе с ним) перед очисткой фокуса клавиатуры.
Чириморин
56

Код, который я использовал:

// 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);
Decasteljau
источник
2
Этот код отличный, Keyboard.ClearFocus () имеет некоторые непреднамеренные побочные эффекты
Патрик
Почему условие! ((IInputElement) parent) .Focusable имеет "!" спереди? Разве это условие не должно выполняться, если родительский объект фокусируется?
Мерт Акчакая
Мерт - не уверен, но, похоже, просто просматривая этот пост, продолжая цикл до тех пор, пока это условие не будет истинным, является сутью. Таким образом, цикл завершается первым фокусируемым элементом.
jpierson
4
@patrick, какие нежелательные побочные эффекты? Не могли бы вы привести соответствующие примеры?
Аневс считает SE злом
2
Это отличное решение. У меня тоже были проблемы с Keyboard.ClearFocus (). При запуске ClearFocus () для TextBox внутри модального Window это приводит к потере фокуса как TextBox, так и Window. Это означает, что события KeyDown больше не поступают в окно. Вместо этого изменив его так, чтобы Focus изменился на родительский (который может быть Window), будущие события KeyDown не теряются. В моем практическом примере у меня есть окно, которое ищет «Key.Escape» и вызывает Close (). Это перестает работать, если вы запускаете ClearFocus () где угодно.
Denis P
19

Немного поздно на вечеринку, но это было полезно для меня, так что поехали.

Начиная с .Net 3.0, FrameworkElementесть функция MoveFocus, которая помогала мне.

СуперОли
источник
Для получения инструкций -> msdn.microsoft.com/en-us/library/…
Картер Медлин,
«Убедитесь, что вы проверили возвращаемое значение этого метода. Возвращаемое значение false может быть возвращено, если обход выполняется до позиции табуляции, которая определяется составом элемента управления, и запрос обхода не запрашивал перенос». - msdn.microsoft.com/en-us/library/…
aderesh
16

Поскольку ни один из приведенных выше ответов не помог мне, а принятый ответ действительно работает только для фокуса клавиатуры, я пришел к следующему подходу:

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

Убивает и логику, и фокус клавиатуры.

Циклон
источник
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);
}
Джулиан Домингес
источник
6

AFAIK, полностью убрать фокус невозможно. Что-то в вашем окне всегда будет в центре внимания.

Bitbonk
источник
2

В разработке для Windows Phone я просто использовал Focus()или this.Focus()в PhoneApplicationPage, и это сработало отлично .

Бруно Лемос
источник
1

Для меня это довольно сложно, особенно при использовании с привязкой LostFocus. Однако мой обходной путь - добавить пустую метку и сосредоточиться на ней.

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

...

OnKeyDown(object sender, RoutedEventArgs e)
{
  //if is Esc
  ResetFocusArea.Focus();
}
Брайан Нг
источник
0

Мой ответ не касается непосредственно вышеупомянутого вопроса, однако я чувствую, что его формулировка превратила его в «Вопрос» о программном избавлении от фокуса. Обычный сценарий, когда это необходимо, - чтобы пользователь мог очистить фокус, щелкнув левой кнопкой мыши фон корневого элемента управления, например окна.

Итак, для этого вы можете создать Attached Behavior, который переключит фокус на динамически созданный элемент управления (в моем случае - пустую метку). Предпочтительно использовать это поведение на элементах самого высокого уровня, таких как окна, поскольку оно выполняет итерацию по дочерним элементам, чтобы найти панель, к которой можно добавить фиктивную метку.

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();
    }
}
TripleAccretion
источник