Откат Wpf | остановить передачу фокуса и остановить другие события - PullRequest
0 голосов
/ 04 мая 2020

У меня действительно большое wpf-приложение со множеством вложенных элементов управления, использующих caliburn micro и MVVM. Один элемент управления должен проверить условие перед тем, как пользователь уйдет. Если проверка не пройдена, фокус возвращается обратно к указанному элементу управления.

Использование Поиск ВСЕХ дочерних элементов управления WPF Я решил проблему с дочерним элементом управления, также вызвав событие LostFocus. И я использовал Диспетчер, чтобы вернуть фокус к элементу управления.

мой код выглядит так:

public void LostKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
{
    var parent = ParentFinder.TryFindParent<ProfileFunctionView>(e.NewFocus as FrameworkElement);
    //only fire for outside controls, not child controls
    if (parent == null)
    {
        if (!Apply())
        {
            var restoreFocus = (System.Threading.ThreadStart)delegate { SyntaxEditor.Focus(); };
            Application.Current.Dispatcher.BeginInvoke(restoreFocus);
            //stuff should happen here
        }

    }
}

Проблема в том, что, если я нажимаю на элемент управления вкладкой где-то над моим контроль Fe. Фокус вернется обратно, но вкладка изменится. Я хочу, чтобы элементы управления, нажимаемые за пределами моего элемента управления, реагировали в случае сбоя условия.

Возможно ли это? Правильный ли мой подход?

Пожалуйста, извините за мой запутанный заголовок, эту проблему действительно трудно сформулировать или гуглить. Любая помощь приветствуется.

1 Ответ

0 голосов
/ 04 мая 2020

Итак, первое, что я хотел бы сделать, это использовать FocusManager для создания области фокусировки. Вот документация MSDN.

https://docs.microsoft.com/en-us/dotnet/api/system.windows.input.focusmanager?view=netcore-3.1

Настройка области фокусировки - это, по сути, контейнер элементов внутри области. Итак, для вашего примера я бы сделал что-то вроде этого.

ProfileFunctionView () 
{
    // This will make child controls use this as their FocusScope.
    FocusManager.SetIsFocusScope ( this ); 
}

Далее, теперь, когда мы создали FocusScope, легко проверить, находится ли элемент с фокусом в области видимости или нет.

public void LostKeyboardFocus( object sender, KeyboardFocusChangedEventArgs e )
{
    if ( sender is UIElement element ) {
       var scope = FocusManager.GetFocusScope ( element );
       if ( scope is Window ) {
           // This is the default focus scope you have actually lost focus.
           RestoreFocus();
       }
       else if ( scope is ProfileFunctionView view ) 
       {
           // Haven't lost focus do nothing
           return;
       }
       else 
       {
          // Handle case where focus does not belong to either.
       }
    }
}

Другой метод и, возможно, более подходящий метод - установить для свойства Focusable родительских элементов значение False. Это предотвратит возникновение событий потерянного фокуса.

Редактировать: Добавление информации на основе вашего комментария.

Если события нежелательны Отключите все элементы управления вне FocusScope.

ProfileFunctionView () 
{
    // This will make child controls use this as their FocusScope.
    FocusManager.SetIsFocusScope ( this ); 

    // Better to do this during the Loaded event.
    FocusManagerUtility.DisableUIOutsideOfScope ( scope: this );
}

public static class FocusScopeUtility 
{
    public static void DisableUIOutsideScope ( scope ) 
    {
        // Psuedo function to get the top level UIElement in the tree.
        var container = GetOwningWindowOrPage ( scope );

        // Psuedo function to get traversal of tree
        var traversal = GetVisualTreeTraversalAsEnumerable ();
        foreach ( var node in traversal ) 
        {
            var element = node as UIElement;
            if ( FocusScopeUtility.IsInScope ( scope, element ) 
            {
                // This line disables the control from receiving input.
                element.Enabled = false;
            }
        }    
    }
}
...