Disable tabstop between columns in a WPF datagrid

21,934

Solution 1

It's interesting that setting the KeyboardNavigation directly on the DataGridTextColumn's doesn't work. An alternative that should work is to set up a DataGridCell style.

<toolkit:DataGrid.CellStyle>
    <Style TargetType="{x:Type toolkit:DataGridCell}">
        <Setter Property="KeyboardNavigation.IsTabStop"
                Value="False" />
        <Style.Triggers>
            <Trigger Property="IsSelected"
                     Value="True">
                <Setter Property="KeyboardNavigation.IsTabStop"
                        Value="True" />
            </Trigger>
        </Style.Triggers>
    </Style>
</toolkit:DataGrid.CellStyle>

Attaching this to the DataGrid will ensure that a cell is only a TabStop if it is already selected. However, if you are selecting full rows and don't have SelectionUnit="Cell" set on the DataGrid, it will still cycle through each column of the currently selected row.

Instead, we can create multiple CellStyles as resources within the DataGrid:

<toolkit:DataGrid.Resources>

    <Style  x:Key="SelectableCellStyle"
            TargetType="{x:Type toolkit:DataGridCell}">
        <Setter Property="KeyboardNavigation.IsTabStop"
                Value="False" />
        <Style.Triggers>
            <Trigger Property="IsSelected"
                     Value="True">
                <Setter Property="KeyboardNavigation.IsTabStop"
                        Value="True" />
            </Trigger>
        </Style.Triggers>
    </Style>

    <Style TargetType="{x:Type toolkit:DataGridCell}">
        <Setter Property="KeyboardNavigation.IsTabStop"
                Value="False" />
    </Style>

</toolkit:DataGrid.Resources>

Now we have a style being applied to all DataGridCells by default and turning off TabStop, and a keyed style that allows selection when the Cell (or whole Row) is selected. Applying this style to only a single column will give us the same single-tab-in effect while allowing the whole row and all of it's columns to be selected.

 <my:DataGridTextColumn x:Name="ID" Header="ID" Width="1*" CellStyle={StaticResource  SelectableCellStyle}"/>

This does also stop tabbing into the DataGrid if nothing is selected, which may be preferred or not depending on the situation you are using it in.

Solution 2

Thank you rmoore. To get the tab stop to be disabled for columns I took your answer and modified it slightly;

     <my:DataGrid Name="datagrid" 
                 AutoGenerateColumns="False" IsReadOnly="True" 
                 CanUserAddRows="False" CanUserDeleteRows="False" 
                 Background="White" 
                 KeyboardNavigation.TabNavigation="Once"
                 SelectionUnit="FullRow"> 
        <my:DataGrid.Columns> 
            <my:DataGridTextColumn x:Name="ID" Header="ID" Width="1*" ></my:DataGridTextColumn> 
            <my:DataGridTextColumn x:Name="Ticker" Header="Ticker" Width="1*">
                    <my:DataGridTextColumn.CellStyle>
                        <Style TargetType="{x:Type my:DataGridCell}">
                            <Setter Property="KeyboardNavigation.IsTabStop" Value="False"></Setter>
                        </Style>
                    </my:DataGridTextColumn.CellStyle>
            </my:DataGridTextColumn> 

            <my:DataGridTextColumn x:Name="OfficialName" Header="Name" Width="3*">
                  <my:DataGridTextColumn.CellStyle>
                        <Style TargetType="{x:Type my:DataGridCell}">
                            <Setter Property="KeyboardNavigation.IsTabStop" Value="False"></Setter>
                        </Style>
                  </my:DataGridTextColumn.CellStyle>
            </my:DataGridTextColumn> 
        </my:DataGrid.Columns> 
    </my:DataGrid>

So tricks;

  1. SelectionUnit="FullRow" makes the GUI look like you are doing things one row at a time (like I wanted).
  2. By adding a CellStyle to the columns I want to disable TabStop in (but not including it in those I would like to stop in) allowed me to take control over which cells that tab-key would navigate into. - The KeyboardNavigation.TabNavigation not having an effect when defined on columns.

Solution 3

I know this is a really old question, but I'm posting this here in case it helps someone. While the accepted answer is good, I don't believe it covers the case where there's another control on the same window, and you would like to tab into the DataGrid from that control. Additionally, you may want the behavior as described in the original question (single tab in, single tab out, no tabbing through cells/columns). This solution aims to achieve this.

Note: This solution is assuming you want your SelectionUnit to be FullRow in your DataGrid.

First, here is the Style to apply to the DataGrid:

<DataGrid.Resources>
    <Style TargetType="DataGridRow">
        <Style.Setters>
            <Setter Property="Focusable" Value="True"/>
        </Style.Setters>
        <Style.Triggers>
            <Trigger Property="IsFocused" Value="True">
                <Setter Property="IsSelected" Value="True"/>
            </Trigger>
        </Style.Triggers>
    </Style>
    <Style TargetType="DataGridCell">
        <Style.Setters>
            <Setter Property="Focusable" Value="False"/>
        </Style.Setters>
    </Style>
</DataGrid.Resources>

This style allows focus on rows but prevents focus on individual cells, which keeps the focus consistent with the SelectionUnit of FullRow. The trigger set inside this style is optional - it is only needed if you want to automatically select the row when it receives focus.

In my case, I wanted the single tab in / tab out behavior, so I also set the KeyboardNavigation.TabNavigation property on my DataGrid = "Once."

<DataGrid SelectionUnit="FullRow" KeyboardNavigation.TabNavigation="Once">

With this approach, I can still use the up/down arrow keys to cycle through rows once the DataGrid receives focus, but I can still tab out quickly if I want to move focus to the next control in the tab order.

Share:
21,934
Thies
Author by

Thies

Consultant Love to program agile. C# is preferred language, but anything object oriented will do. Lava Lamps connected to a CI platform is the only way to work...

Updated on June 09, 2020

Comments

  • Thies
    Thies almost 4 years

    I have a WPF Toolkit datagrid with mulitple columns. I am trying to get a behaviour where you can tab into the grid using tab, then tab out again using a single tab. E.g. I do not want to tab through all the columns or cells of the grid, just once in, and once out.

    Is there a simple solution, I have tried setting the TabNavigation to Once, along with disabling TabStop (not shown in code below) and setting TabNavigation on the columns to None, but without success.

    Is there something I am missing or do I need to handle the Tab-key in code?

            <my:DataGrid Name="datagrid"
                         AutoGenerateColumns="False" IsReadOnly="True"
                         CanUserAddRows="False" CanUserDeleteRows="False"
                         Background="White"
                         KeyboardNavigation.TabNavigation="Once">
                <my:DataGrid.Columns>
                    <my:DataGridTextColumn x:Name="ID" Header="ID" Width="1*" ></my:DataGridTextColumn>
                    <my:DataGridTextColumn x:Name="Ticker" Header="Ticker" Width="1*" KeyboardNavigation.TabNavigation="None"></my:DataGridTextColumn>
                    <my:DataGridTextColumn x:Name="OfficialName" Header="Name" Width="3*" KeyboardNavigation.TabNavigation="None"></my:DataGridTextColumn>
                </my:DataGrid.Columns>
            </my:DataGrid>