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"/>
.
source to share
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>
source to share
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;
}
}));
}
}
source to share