Можно ли обнаружить события фокуса клавиатуры глобально?

Можно использовать следующие события, но они должны быть прикреплены для каждого элемента:

GotKeyboardFocus, LostKeyboardFocus

Есть ли способ в .NET WPF глобально определить, изменился ли сфокусированный элемент? без необходимости добавлять слушателей событий для всех возможных элементов?

Ответ 1

Вы можете подключиться к туннелированию событий предварительного просмотра:

<Window x:Class="WpfApplication1.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Height="350" Width="525" 
    PreviewGotKeyboardFocus="Window_PreviewGotKeyboardFocus" 
    PreviewLostKeyboardFocus="Window_PreviewLostKeyboardFocus">
....

Таким образом, как показано выше, окно будет уведомлено перед всеми потомками, когда любой из потомков получает или теряет фокус клавиатуры.

Подробнее читайте .

Ответ 2

Вы можете сделать это в любом классе с помощью этого:

//In the constructor
EventManager.RegisterClassHandler(
        typeof(UIElement),
        Keyboard.PreviewGotKeyboardFocusEvent,
        (KeyboardFocusChangedEventHandler)OnPreviewGotKeyboardFocus);

...

private void OnPreviewGotKeyboardFocus(object sender, 
                                       KeyboardFocusChangedEventArgs e)
{

     // Your code here

}

Ответ 3

Вы можете добавить обработчик маршрутизированного события в основное окно и указать, что вы заинтересованы в обработанных событиях.

mainWindow.AddHandler(
    UIElement.GotKeyboardFocusEvent,
    OnElementGotKeyboardFocus,
    true
);

Ответ 4

Посмотрите, как Microsoft запускает событие CommandManager.RequerySuggested при изменении фокуса: они подписываются на InputManager.PostProcessInput событие.

ReferenceSource

Простой пример:

static KeyboardControl()
{
    InputManager.Current.PostProcessInput += InputManager_PostProcessInput;
}

static void InputManager_PostProcessInput(object sender, ProcessInputEventArgs e)
{
    if (e.StagingItem.Input.RoutedEvent == Keyboard.GotKeyboardFocusEvent ||
        e.StagingItem.Input.RoutedEvent == Keyboard.LostKeyboardFocusEvent)
    {
        KeyboardFocusChangedEventArgs focusArgs = (KeyboardFocusChangedEventArgs)e.StagingItem.Input;
        KeyboardControl.IsOpen = focusArgs.NewFocus is TextBoxBase;
    }
}

Это также работает в многооконных приложениях.