Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why doesn't the Tab order between/inside a TreeView work?

Tags:

wpf

treeview

I have a window with following xaml:

<Window x:Class="TestDemoApp.TreeViewWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="TreeViewWindow" Height="300" Width="300">
    <Window.Resources>
        <Style TargetType="Control" x:Key="FocusedStyle">
            <Setter Property="Control.Template">
                <Setter.Value>
                    <ControlTemplate>
                        <Rectangle StrokeThickness="1"
                              Stroke="Red"
                              StrokeDashArray="1 2 3 4"
                              SnapsToDevicePixels="true"/>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>

        <Style TargetType="TreeViewItem">
            <Setter Property="IsTabStop" Value="True"/>
            <Setter Property="Focusable" Value="True"/>
            <Setter Property="FocusVisualStyle" Value="{StaticResource FocusedStyle}"/>
            <Setter Property="KeyboardNavigation.TabNavigation" Value="Continue"/>
        </Style>
        <Style TargetType="ListViewItem">
            <Setter Property="IsTabStop" Value="True"/>
            <Setter Property="Focusable" Value="True"/>
            <Setter Property="FocusVisualStyle" Value="{StaticResource FocusedStyle}"/>
            <Setter Property="KeyboardNavigation.TabNavigation" Value="Continue"/>
        </Style>
    </Window.Resources>

    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="*"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>

        <ListView TabIndex="1" BorderThickness="5" Focusable="True" IsTabStop="True" KeyboardNavigation.TabNavigation="Continue" FocusVisualStyle="{StaticResource FocusedStyle}">
            <ListViewItem TabIndex="2" Content="List Item 1"/>
            <ListViewItem TabIndex="3" Content="List Item 2"/>
        </ListView>

        <TreeView TabIndex="6" BorderThickness="5" Focusable="True" IsTabStop="True" KeyboardNavigation.TabNavigation="Continue" Grid.Row="1" FocusVisualStyle="{StaticResource FocusedStyle}">
            <TreeView.Items>
                <TreeViewItem TabIndex="7" Header="Tree Item 1">
                    <TreeViewItem Header="Tree Item 11"></TreeViewItem>
                    <TreeViewItem Header="Tree Item 12"/>
                </TreeViewItem>
                <TreeViewItem Header="Tree Item 2">
                </TreeViewItem>
            </TreeView.Items>
        </TreeView>
    </Grid>
</Window>

When I run the program, the tab order is:

1. List View
2. List Item 1
3. List Item 2
4. Tree View
5. Tree Item 1
6. Tree Item 2

7. List View (#1)
8. List Item 1 (#2)
9. List Item 2 (#3)
10. Tree Item 2 (6#)

11+ Repeat #7 - #10

The expected behavior is that it would repeats from #1 to #6 upon further iterations, however instead it skips #4 and #5 on any subsequent iterations.

Why is this? And how can I fix it?

like image 346
Alex Cube Avatar asked May 08 '13 09:05

Alex Cube


1 Answers

Wow, this is UGLY. The WPF treeview is my favorite target for this adjective in so many respects, but I haven't encountered this particular issue before.

I don't think you can do better than Continue for KeyboardNavigation.TabNavigation, the only other possibility is Local, and that doesn't work either. See this msdn article. Also, combinations like Cycle on the items and Continue on the control did not produce the desired result for me.

Quite obviously, the selected item is preserved in the treeview when the focus goes back to the listview, and when the treeview receives focus the next time, it passes focus on directly to the previously selected item (Tree Item 2), unlike the listview, which preserves selection but correctly focuses the control first, then the items.

So a quick and dirty hack that might work for you is to remove the selection from the treeview when it loses focus. Unfortunately, the event fires every time the selected item changes, but the hack works nevertheless.

<TreeView (...) LostFocus="TreeView_LostFocus">

code behind:

private void TreeView_LostFocus(object sender, RoutedEventArgs e)
{
    TreeView tv = (TreeView)sender;
    TreeViewItem item = tv.SelectedItem as TreeViewItem;
    if (item != null)
        item.IsSelected = false;
}
like image 129
Mike Fuchs Avatar answered Oct 16 '22 10:10

Mike Fuchs