Search code examples
c#wpftreeviewarrow-keysctrl

Is it possible to disable the default Ctrl-Arrow scroll behaviors of a TreeView?


We have a TreeView which we want to manually process CTRL-Arrow key combinations on. However, the built-in behavior is to scroll the list without actually changing the selected item.

Is thee any way to disable this functionality so even when the control key is down, the arrows change the selected item?

Note: Yes, I know about the PreviewKeyDown function, but when I get the event and handle it, I'm not sure how to programmatically make the selection in the tree work as a user would expect. (i.e. respecting expanded or collapsed nodes, jumping from branch to branch, etc.)


Solution

  • The keyboard selection code in a TreeView is ugly as a mutha... I was trying to implement proper multi-selection and the keyboard navigation code is just not very expandable.

    I ended up calling a non-public method that served as a decent entry point:

    private delegate DependencyObject PredictFocusedElement(DependencyObject sourceElement, FocusNavigationDirection direction, bool treeViewNavigation, bool considerDescendants);
    
    // get the default KeyboardNavigation instance
    
    KeyboardNavigation keyboardNavigation = (KeyboardNavigation)typeof(FrameworkElement).GetProperty("KeyboardNavigation", BindingFlags.NonPublic | BindingFlags.Static).GetMethod.Invoke(null, null);
    
    // create a delegate for the PredictFocusedElement method
    
    _predictFocusedElement = (PredictFocusedElement)typeof(KeyboardNavigation).GetMethod("PredictFocusedElement", BindingFlags.NonPublic | BindingFlags.Instance, Type.DefaultBinder,
                                                                                            new Type[] { typeof(DependencyObject), typeof(FocusNavigationDirection), typeof(bool), typeof(bool) },
                                                                                            null).CreateDelegate(typeof(PredictFocusedElement), keyboardNavigation);
    

    Now, once you have that delegate, you can control the focus:

    tvi = (TreeViewItemEx)_predictFocusedElement(tvi, FocusNavigationDirection.Down, true, true);
    
    tvi.Focus();
    

    If you want to see ugly code, you can look at that PredictFocusedElement code in ILSpy or whatever :).