Strange focus behavior for simple WPF ItemsControl

后端 未结 2 1344
别那么骄傲
别那么骄傲 2021-02-10 07:22

I\'m seeing strange behavior when it comes to focus and keyboard navigation. In the example below I have a simple ItemsControl that has been templated so that it presents a list

相关标签:
2条回答
  • 2021-02-10 07:35

    @Meleak explained the problem very well. Please read the article http://www.codeproject.com/KB/WPF/EnhancedFocusScope.aspx to fully understand what the problem is and how to solve it. I will just add the complete implementation of IsEnhancedFocusScope attached behavior mentioned in the article:

    public static class FocusExtensions
    {
        private static bool SettingKeyboardFocus { get; set; }
    
        public static bool GetIsEnhancedFocusScope(DependencyObject element) {
            return (bool)element.GetValue(IsEnhancedFocusScopeProperty);
        }
    
        public static void SetIsEnhancedFocusScope(DependencyObject element, bool value) {
            element.SetValue(IsEnhancedFocusScopeProperty, value);
        }
    
        public static readonly DependencyProperty IsEnhancedFocusScopeProperty =
            DependencyProperty.RegisterAttached(
                "IsEnhancedFocusScope",
                typeof(bool),
                typeof(FocusExtensions),
                new UIPropertyMetadata(false, OnIsEnhancedFocusScopeChanged));
    
        private static void OnIsEnhancedFocusScopeChanged(DependencyObject depObj, DependencyPropertyChangedEventArgs e) {
            var item = depObj as UIElement;
            if (item == null)
                return;
    
            if ((bool)e.NewValue) {
                FocusManager.SetIsFocusScope(item, true);
                item.GotKeyboardFocus += OnGotKeyboardFocus;
            }
            else {
                FocusManager.SetIsFocusScope(item, false);
                item.GotKeyboardFocus -= OnGotKeyboardFocus;
            }
        }
    
        private static void OnGotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e) {
            if (SettingKeyboardFocus) {
                return;
            }
    
            var focusedElement = e.NewFocus as Visual;
    
            for (var d = focusedElement; d != null; d = VisualTreeHelper.GetParent(d) as Visual) {
                if (FocusManager.GetIsFocusScope(d)) {
                    SettingKeyboardFocus = true;
    
                    try {
                        d.SetValue(FocusManager.FocusedElementProperty, focusedElement);
                    }
                    finally {
                        SettingKeyboardFocus = false;
                    }
    
                    if (!(bool)d.GetValue(IsEnhancedFocusScopeProperty)) {
                        break;
                    }
                }
            }
        }
    }
    

    In your XAML you just need to set this attached property instead of standard IsFocusScope property:

    <ItemsControl my:FocusExtensions.IsEnhancedFocusScope="True"
                  ItemsSource="{Binding ElementName=TheWindow, Path=ListOStrings}">
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <CheckBox Content="{Binding}" />
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>
    

    It will work as you expect the focus scope to work.

    0 讨论(0)
  • 2021-02-10 07:50

    This article explains it very well: http://www.codeproject.com/KB/WPF/EnhancedFocusScope.aspx

    For What was FocusScope Designed?

    Microsoft uses FocusScope in WPF to create a temporary secondary focus. Every ToolBar and Menu in WPF has its own focus scope.

    With this knowledge, we can clearly see why we have those problems:

    A toolbar button should not execute commands on itself, but on whatever had focus before the toolbar was clicked. To accomplish this, routed commands ignore the focus from focus scopes and use the 'main' logical focus instead. This explains why routed commands don't work inside focus scopes.

    Why does the large text box in the test application screenshot still display a caret? I don't know the answer to this - but why shouldn't it? Granted, the text box doesn't have the keyboard focus (the small text box in the WPF focus scope has that); but it still has the main logical focus in the active Window and is the receiver of all routed commands.

    And this part covers the behavior you're seeing

    Why does the keyboard focus move to the large text box when you tab to the CheckBox in the WPF focus scope and press Space to toggle it?

    Well, this is exactly what you expect when you click a menu item or a toolbar: the keyboard focus should return to the main focus. All ButtonBase-derived controls will do this.

    0 讨论(0)
提交回复
热议问题