My .NET focused coding blog.

Tabbing between items in a ListBox in WPF

This post explains what XAML changes you need to make in order to be able to navigate between elements that are the defined in the ItemsTemplate of a WPF ListBox using the TAB key on the keyboard.

ItemTemplate

The ItemTemplate of the ListBox defines the visual appearance of an object in the ListBox’s ItemsSource collection. For example, the below DataTemplate uses three TextBox elements to display the first name, last name and age of each Person object in an IList<Person> collection.

View

<ListBox ItemsSource="{Binding Persons}">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <Grid>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="Auto"/>
                    <ColumnDefinition Width="1*"/>
                </Grid.ColumnDefinitions>
                <Grid.RowDefinitions>
                    <RowDefinition />
                    <RowDefinition />
                    <RowDefinition />
                </Grid.RowDefinitions>

                <!-- First name-->
                <TextBlock Text="First name" Grid.Row="0" Grid.Column="0"
                                    FontWeight="Bold" Margin="8"/>
                <TextBox Text="{Binding FirstName}" Grid.Row="0" Grid.Column="1"
                                    Margin="8" Width="100"/>

                <!-- Last name -->
                <TextBlock Text="Last name" Grid.Row="1" Grid.Column="0"
                                   FontWeight="Bold" Margin="8"/>
                <TextBox Text="{Binding LastName}" Grid.Row="1" Grid.Column="1"
                                 Margin="8" Width="100"/>

                <!-- Age -->
                <TextBlock Text="Age" Grid.Row="2" Grid.Column="0"
                                   FontWeight="Bold" Margin="8"/>
                <TextBox Text="{Binding Age}" Grid.Row="2" Grid.Column="1"
                                 Margin="8" Width="100"/>
            </Grid>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

View Model

public class ViewModel
{
    public ViewModel()
    {
        this.Persons = new List<Person>
            {
                new Person{ FirstName="Bill", LastName="Gates", Age=59},
                new Person{ FirstName="Steve", LastName="Ballmer", Age=58},
                new Person{ FirstName="Satya", LastName="Nadella", Age=47}
            };
    }

    public IList<Person> Persons { get; private set; }
}

Model

public class  Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public int Age { get; set; }
}

ListBox
By default, if you put the cursor in the first TextBox (First name) element and press the TAB key on the keyboard when running the application, the cursor will move to the second TextBox (Last name) and then to the third TextBox (Age) if you press the TAB key once more.

You might expect to be able to move the cursor to the first TextBox of the second ListBoxItem, i.e. the one with the text “Steve” in it in the image above, by pressing the TAB once more but if you try to do this, you will probably only see a dashed border around the entire first ListBoxItem and if you press the TAB key once again you will notice that the cursor goes back to the first TextBox again.

KeyboardNavigation.TabNavigation

You can modify this default behavior by setting a different value for the KeyboardNavigation.TabNavigation property of the ListBox. This property controls the logical tab navigation behavior for the children of the element that the property is set on. If you for example set it to Cycle, the user will able to tab through all TextBox elements in the entire ListBox just as expected:

<ListBox KeyboardNavigation.TabNavigation="Cycle" ItemsSource="{Binding Persons}">

All possible values of the KeyboardNavigationMode enumeration are documented on MSDN here. For a ListBox, the KeyboardNavigation.TabNavigation property is set to System.Windows.Input.KeyboardNavigationMode.Once by default.

ListBoxItem

The ItemTemplate of the ListBox will be rendered inside a ListBoxItem container. In order to get rid of the dashed border that appears when you attempt to tab out from a ListBoxItem, you need to set the IsTabStop property of the ListBoxItem container to false. You can do this by specifying an ItemContainerStyle for the ListBox:

<ListBox KeyboardNavigation.TabNavigation="Cycle" ItemsSource="{Binding Persons}">
    <ListBox.ItemContainerStyle>
        <Style TargetType="ListBoxItem">
            <Setter Property="IsTabStop" Value="False"/>
        </Style>
    </ListBox.ItemContainerStyle>
    ...
</ListBox>

IsTabStop

The IsTabStop property is defined in the common System.Windows.Controls.Control class from which most WPF controls derive and decides whether a control is included in the tab navigation.

Focusable

There is also a Focusable property that is defined in the System.Windows.UIElement class which is another common base class in WPF. This property indicates whether focus can be set to the element. It is for example set to true for TextBox elements and to false for TextBlock elements. This is why the TextBlock elements don’t receive any focus when you tab through the elements in the ListBox.

Note that you could set this property to false for the ListBoxItem (instead of setting the IsTabStop property) but then you won’t be able to select an item in the ListBox using the mouse or keyboard.

See Also

Data Templating Overview: http://msdn.microsoft.com/en-us/library/ms742521(v=vs.110).aspx (MSDN)
KeyboardNavigation.TabNavigation Attached Property: http://msdn.microsoft.com/en-us/library/system.windows.input.keyboardnavigation.tabnavigation(v=vs.110).aspx (MSDN)



Leave a comment