locked
How to support tab navigation in a XAML GridView?

    Question

  • I have a Windows Store app written in C#/XAML. One of the pages uses a GridView bound to a collection of strings and the XAML is configured to use TextBoxes as the following snippets show:

        <DataTemplate x:Key="GridViewEditTextTemplate">
            <TextBox Header="{Binding Prefix}" Width="560" AcceptsReturn="True" TextWrapping="Wrap" Text="{Binding Content,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" IsSpellCheckEnabled="True"/>
        </DataTemplate>
    
    ....
    
        <local:RepositoryRecordGridViewTemplateSelector x:Key="GridViewSelector"
            RepoTextTemplate="{StaticResource GridViewEditTextTemplate}"/>
    
    ....
    
        <GridView
            x:Name="recordGridView"
            AutomationProperties.AutomationId="RecordGridView"
            AutomationProperties.Name="Grouped Items"
            ItemsSource="{Binding Source={StaticResource groupedItemsViewSource}}"
            ItemTemplateSelector="{StaticResource GridViewSelector}"
            Grid.RowSpan="2"
            Padding="116,137,40,46"
            IsItemClickEnabled="True"
            IsDoubleTapEnabled="False"
            IsRightTapEnabled="False"
            IsSynchronizedWithCurrentItem="False"
            SelectionMode="Single"
            ItemClick="ItemClick"
            SelectionChanged="recordGridView_SelectionChanged">
    
            <GridView.ItemsPanel>
                <ItemsPanelTemplate>
                    <StackPanel Orientation="Horizontal"/>
                </ItemsPanelTemplate>
            </GridView.ItemsPanel>
            <GridView.GroupStyle>
                <GroupStyle HidesIfEmpty="True">
                    <GroupStyle.HeaderTemplate>
                        <DataTemplate>
                            <Grid Margin="1,0,0,6" Visibility="{Binding HeaderIsAvailable, Converter={StaticResource DisplayIfTrue}}">
                                <Button
                                    AutomationProperties.Name="Group Title"
                                    Style="{StaticResource TextPrimaryButtonStyle}">
                                    <StackPanel Orientation="Horizontal">
                                        <TextBlock Text="{Binding Title}" Margin="3,-7,10,10" Style="{StaticResource GroupHeaderTextStyle}" />
                                    </StackPanel>
                                </Button>
                            </Grid>
                        </DataTemplate>
                    </GroupStyle.HeaderTemplate>
                    <GroupStyle.Panel>
                        <ItemsPanelTemplate>
                            <controls:WrapPanel Orientation="Vertical" HorizontalAlignment="Left" Margin="0,0,80,0" />
                        </ItemsPanelTemplate>
                    </GroupStyle.Panel>
                </GroupStyle>
            </GridView.GroupStyle>
        </GridView>

    So the visual result is a page containing a series of text boxes for the user to fill out. Since that is a keyboard-intensive process, I want to allow the user to be able to press TAB to move from one text box to the next. However, as it stands at the moment, pressing TAB moves you from the first text box to the Back button to the group header.

    How can I correct this behaviour? The TabIndex value is currently being generated automatically by the system and I thought that the default behaviour was for the TabIndex to be calculated such that the user can tab between the controls in the visual order, but that clearly isn't working.

    Thanks.

    Saturday, July 12, 2014 10:03 AM

Answers

  • Ok. The problem sounds like a conflict between two containers. Within the TextBox the arrows move between the characters. Within the GridView the arrows move between the GridViewItems.

    It sounds like you have a layout that will require mixing tabs and arrows: arrows between the GridViewItems, tab to move between the item and the TextBox, and then arrows again within the TextBox.

    <Understatement>This is a bit ugly</Understatement> so you'll probably want to override the default keyboard handling. You might try overriding tab from the TextBox (or GotFocus on the GridViewItem) to also change the GridView's selection, but make sure you don't end up with something more confusing than you started with.

    --Rob

    Wednesday, July 16, 2014 11:56 PM
    Owner

All replies

  • Tab takes you between controls at the same level, but within a container you use arrows to switch between items. I suspect that's what you're seeing here: tab between the GridView, back button, and header; arrows between the GridView items; tab between the controls within an item (moot since you have only the one TextBox)

    See

     

    Saturday, July 12, 2014 2:33 PM
    Owner
  • Hi Rob

    That isn't the behaviour I'm seeing. As I understand it, arrows are used within a container. So, for example, if the input focus is in a TextBox, the arrows are used to navigate around the text within the TextBox and not to move to a different TextBox.

    If I place the input focus in the first TextBox that is in the GridView's Items Panel and then press TAB, the focus moves to a different control but I can't readily see which one. Pressing Return to action the control doesn't do anything.

    Press TAB again and the Back arrow on the page's header gets highlighted.

    Press TAB again and I cannot see which control is selected again.

    Press TAB again and the header for the group that contains the TextBoxes is highlighted.

    Press TAB again and I cannot see which control is selected again.

    Finally, press TAB again and the first TextBox in the GridView is again the one with the focus.

    I've tried explicitly setting the TabIndex to 0 as per the rules explained in your first link, but that hasn't made any difference.

    I guess that keyboard navigation was never expected to be used within a GridView's child controls. I'll have to tackle this a different way. One of the reasons why I wanted to use a GridView was so that it would auto-flow the TextBoxes from one column to another based on the screen layout, and so that I can use a ListView when in minimal mode.

    Sunday, July 13, 2014 2:33 PM
  • Ok. The problem sounds like a conflict between two containers. Within the TextBox the arrows move between the characters. Within the GridView the arrows move between the GridViewItems.

    It sounds like you have a layout that will require mixing tabs and arrows: arrows between the GridViewItems, tab to move between the item and the TextBox, and then arrows again within the TextBox.

    <Understatement>This is a bit ugly</Understatement> so you'll probably want to override the default keyboard handling. You might try overriding tab from the TextBox (or GotFocus on the GridViewItem) to also change the GridView's selection, but make sure you don't end up with something more confusing than you started with.

    --Rob

    Wednesday, July 16, 2014 11:56 PM
    Owner