How to prevent tabs from moving on a control while allowing navigation towards that control

In WPF (MVVM, no code), let's say I have the following xaml:

<StackPanel>
    <Button>Normal 1</Button>
    <Button>Special</Button> <!--This button should not tab focus, but still focus via arrow keys-->
    <Button>Normal 2</Button>
</StackPanel>

      

By default, you can (1) insert a tab between buttons or (2) an up / down arrow between buttons. I want to make one of the buttons - a dedicated button - not focused through the tab, but still focusable with the up / down button. I tried IsTabStop="False"

but this also prevents that button from focusing with directional navigation (up / down arrows).

How can I remove one button from the tab navigation and continue to allow navigation over navigation ? Overlays and arrows should be unchanged for all other controls .

I tried the combination IsTabStop

, KeyboardNavigation.TabNavigation

and KeyboardNavigation.DirectionalNavigation

to no avail. I may not have found the right mix. Or maybe there is another approach. Ideas?


EDIT : Okay, I'm adding a bounty. To be clear, I'm looking for MVVM, with no code to decorate the control (e.g. via styling, attached property, attached behavior, etc.), so that it is removed from the tab order while still being a valid nav target. Knowledge of hard-coding controls in a window (or similar) is not acceptable. This should be a general, reusable solution. Something like: <Button AllowDirectionalNavigationButPreventTabNavigation="True"/>

.

+3


source to share


2 answers


How about this option. You insert a custom button into another container and put KeyboardNavigation.TabNavigation = "No" on that container. I just tried it and it looks like I can achieve what you need.



<StackPanel >
  <Button>Normal 1</Button>
  <StackPanel KeyboardNavigation.TabNavigation="None">
    <Button>Special</Button><!--This button should not tab focus, but still focus via arrow keys-->
  </StackPanel>
  <Button>Normal 2</Button>
</StackPanel>

      

+9


source


this is how i did it:

<Window x:Class="MvvmLight1.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:ignore="http://www.ignore.com"
    xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
    xmlns:command="http://www.galasoft.ch/mvvmlight"
    mc:Ignorable="d ignore"
    Height="300"
    Width="300"
    DataContext="{Binding Main, Source={StaticResource Locator}}">
<i:Interaction.Triggers>
    <i:EventTrigger EventName="KeyDown">
        <command:EventToCommand Command="{Binding Mode=OneWay,Path=KeyDownCommand}" PassEventArgsToCommand="True"/>
    </i:EventTrigger>
</i:Interaction.Triggers>
<Grid x:Name="LayoutRoot">
    <StackPanel>
        <Button>Normal 1</Button>
        <Button>Special</Button>
        <!--Should not tab focus, yet still focus via arrow keys-->
        <Button>Normal 2</Button>
    </StackPanel>
</Grid>

      



I am using mvvmlight and EventToCommand is used to intercept the KeyDown event and forward it to the following command in the ViewModel:

 private RelayCommand<KeyEventArgs> _keyDownCommand;
    public RelayCommand<KeyEventArgs> KeyDownCommand
    {
        get
        {
            return _keyDownCommand
                ?? (_keyDownCommand = new RelayCommand<KeyEventArgs>(
                (s) =>
                {
                    if (s.Key == Key.Tab)
                    {
                        s.Handled = true;
                    }
                }));
        }
    }

      

0


source







All Articles