WPF: Tab navigation broken with collapsed hyperlink
Problem: Navigation with the TAB key stops at collapsed TextBlock/Hyperlink.
Reproduction:
<Window x:Class="TabTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Width="200" Height="200">
<Grid>
<StackPanel Orientation="Vertical">
<TextBox Text="before" />
<TextBlock>
<TextBlock.Style>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="Visibility" Value="Colla开发者_Go百科psed"/>
</Style>
</TextBlock.Style>
<Hyperlink Focusable="False">
<TextBlock Text="test" />
</Hyperlink>
</TextBlock>
<TextBox Text="after" />
</StackPanel>
</Grid>
</Window>
If you run this super-simple demo and press TAB, the cursor moves to the "before" TextBox. Pressing TAB again does ... nothing. The cursor stays in the "before" TextBox and never reaches the "after" Textbox. Navigation works as expected when the Hyperlink's TextBlock is visible.
Question: How do I make TAB navigation work correctly with the HyperLink collapsed?
The problem is not the Hyperlink but the nested controls within the TextBlock. You could change it to
<TextBlock Visibility="Collapsed">
<TextBlock Text="MyText" />
</TextBlock>
and the Tab navigation would still be broken.
The solution is to use KeyboardNavigation.TabNavigation="Once"
at the outer TextBlock:
<TextBlock KeyboardNavigation.TabNavigation="Once">
<TextBlock.Style>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="Visibility" Value="Collapsed"/>
</Style>
</TextBlock.Style>
<Hyperlink Focusable="False">
<TextBlock Text="test" />
</Hyperlink>
</TextBlock>
then everything works the way as intended. The problem is that the inner TextBlock gets the Focus, even if the outer Control it is collapsed. Setting KeyboardNavigation.TabNavigation
to Once
solves it as the whole Container and its childs get the focus only once. (MSDN)
@Gimno's answer put me on the right track, but I found that using KeyboardNavigation.TabNavigation="None"
actually gives the top element focus only once (as you would expect from Once
). Gimno's answer works because he/she also set Focusable="False"
on the Hyperlink. With TabNav=None, you don't have to set Focusable on all the children controls.
Here's my application of this method (only the Button gets tab focus, not either textblock or the hyperlink):
<Button Command="{Binding ChangeSoundCommand}" Click="ChangeSoundClick" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Background="Transparent" BorderBrush="Transparent" BorderThickness="0" Padding="0"
KeyboardNavigation.TabNavigation="None">
<Button.Template>
<ControlTemplate>
<Grid>
<TextBlock Name="tb" HorizontalAlignment="Center" VerticalAlignment="Center" Visibility="Collapsed" >
<Hyperlink>Browse...</Hyperlink>
</TextBlock>
<TextBlock Name="w_content" Text="{Binding FilePath}" TextTrimming="CharacterEllipsis" />
</Grid>
<ControlTemplate.Triggers>
<Trigger SourceName="w_content" Property="Text" Value="">
<Setter TargetName="tb" Property="Visibility" Value="Visible"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Button.Template>
</Button>
In my case, it worked even with a collapsed hyperlink. But I had a similar trouble when I used the FocusManager to auto set the focus on certain element. When the StackPanel was collapsed, it was blocking the keyboard navigation by using the Tab key. In my case, I had to remove FocusManager.FocusedElement and everything was fine again.
<StackPanel FocusManager.FocusedElement="{Binding ElementName=tbUser}"/>
Maybe this is helpful to someone else too, as I spent some time to figure it out.
精彩评论