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


96

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

Коли користувач натискає Escape, я хочу, щоб TextBoxвін редагував текст, який він мав, коли користувач починав редагувати, І я хочу видалити фокус зTextBox .

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

Проблема полягає у видаленні фокусу елемента. Я не хочу переносити фокус на будь-який інший компонент, я просто хочу, TextBoxщоб втратити фокус. Чи повинен я мати невидимий елемент, щоб встановити фокус, щоб я TextBoxміг втратити фокус?

Відповіді:


152

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


1
Це було саме те, що я шукав сьогодні ввечері!
Джош

9
Це не завжди чітко фокусує: у мене проблема, коли AutoCompleteTextBox всередині ListBox не втрачає фокус, коли я Keyboard.ClearFocus()десь клацну з коду позаду.
ANeves вважає, що SE є злим

3
ClearFocusпризводить GotFocusдо того, що не спрацьовує нещодавно сфокусований елемент керування, тоді як він все ще спрацьовує для інших елементів керування. Наприклад, це велика проблема для моєї власної екранної клавіатури. Це спричиняє зникнення каретки, що, мабуть, і все, що пов’язане з «фокусом клавіатури». Можливо, мене більше цікавить щось на кшталт «фокус миші».
Grault

2
Дякую Grault, у мене така ж проблема. Найкраще, що я придумав, - це перенести фокус на якийсь інший елемент управління other.Focus().
Тор Клінгберг,

7
@Grault Це лише очищає фокус клавіатури, а не логічний фокус (саме це спрацьовує на GotFocusподію). У вашій програмі завжди є щось із логічним фокусом. Або використовуйте LostKeyboardFocusподію, або перемістіть фокус на інший елемент (який зміщує логічний фокус разом з ним) перед очищенням фокусу на клавіатурі.
Chirimorin

54

Код, який я використовував:

// 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
Цей код чудовий, Keyboard.ClearFocus () має кілька небажаних побічних ефектів
Патрік

Чому умова! ((IInputElement) батько) .Фокусовані мають "!" попереду? Чи не повинна ця умова бути істинною, якщо батько зосереджений?
Mert Akcakaya

Мерт - не впевнений, але просто переглядаючи цю публікацію, здається, продовжуючи цикл, доки ця умова не буде справдженою. Таким чином перший фокусується елемент завершує цикл.
jpierson,

4
@patrick, які небажані побічні ефекти? Не могли б ви навести відповідні приклади?
ANeves вважає, що SE є злим

1
Це чудове рішення. У мене також були проблеми з Keyboard.ClearFocus (). Під час запуску ClearFocus () на TextBox всередині модального вікна це призводить до втрати фокусу як TextBox, так і Window. Значення подій KeyDown більше не переходять у вікно. Замість того, щоб змінити його так, щоб Focus змінився на батьківського (а це може бути Вікно), майбутні події KeyDown не втрачаються. У моєму практичному прикладі у мене є Вікно, яке шукає "Key.Escape" і викликає Close (). Це перестає працювати, якщо ви будь-де запускаєте ClearFocus ().
Денис П

19

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

Оскільки .Net 3.0 FrameworkElementмає функцію MoveFocus, яка зробила для мене фокус.


Для отримання вказівок -> msdn.microsoft.com/en-us/library/…
Картер Медлін

"Переконайтеся, що ви перевіряєте повернене значення цього методу. Повернене значення false може бути повернуто, якщо обхід потрапляє на табулятор, визначений складом елемента керування, а запит обходу не вимагає перенесення." - msdn.microsoft.com/en-us/library/…
aderesh

13

Оскільки жодна з наведених відповідей не працювала для мене, а прийнята відповідь працює лише для фокусування на клавіатурі, я прийшов до наступного підходу:

// 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, неможливо повністю зняти фокус. Щось у вашому Вікні завжди буде фокусуватись.


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

Моя відповідь не стосується вищезазначеного питання безпосередньо, однак, я вважаю, що його формулювання призвело до того, що воно стало "Питанням" про програмне позбавлення від фокусу. Поширений сценарій, коли це потрібно, полягає в тому, щоб користувач міг очистити фокус, клацнувши лівою кнопкою миші фон кореневого елемента керування, наприклад вікна.

Отже, для досягнення цього ви можете створити вкладену поведінку, яка переведе фокус на динамічно створений елемент керування (у моєму випадку порожня мітка). Переважно використовувати таку поведінку на елементах найвищого рівня, таких як вікна, оскільки вона перебирає через своїх дітей, щоб знайти панель, до якої можна додати фіктивну мітку.

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();
    }
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.