Disable tabstop between columns in a WPF datagrid
Asked Answered
W

3

15

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>
Warenne answered 21/1, 2010 at 17:19 Comment(1)
#859438Whetstone
M
21

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.

Martingale answered 21/1, 2010 at 19:17 Comment(0)
W
10

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.
Warenne answered 22/1, 2010 at 8:57 Comment(0)
P
2

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.

Prey answered 8/6, 2019 at 18:55 Comment(1)
This didn't quite work for me, but it's close! When there is more than one row in the DataGrid, tabbing into the DataGrid the first time selects the first row, and the next tab tabs out of the DataGrid. But then if you select the second row and tab enough to cycle back around to the DataGrid, it re-selects the FIRST row.Gorge

© 2022 - 2024 — McMap. All rights reserved.