Answered by:
Nested TreeViewItem controls tab order not working

Question
-
I have a WPF information entry screen composed of multiple nested controls. Tabbing doesn't work. Any help with this is greatly appreciated.
This is all programmatically generated, so I can't show you the XAML.
Specifically, I have a menu with a single "File" command at the top, 11 buttons down the left side, and a TreeView control on the right side. If I load the program and start pressing tab, I see that the focus starts with the menu "File" command. It then visits all 11 buttons on the left. Then it visits the TreeView on the right. After reaching the TreeView, the very next tab takes me back to the menu "File" command.
Meanwhile, the TreeView contains numerous nested controls, of which are a number of TextBox controls where I want to do data entry. It all looks like a data entry form organized as an outline. The TextBox (**) mentioned further below occurs on multiple worksheet entry lines, within multiple subsections, within multiple sections. Altogether, there are a few dozen of these TextBox controls.
Back to tabbing... Remember, tab takes me from the menu "File" command, through all the left side buttons, then to the TreeView, and then back to the menu "File" command. However, there's just a single stop occurring at the TreeView, and this stop is at the visually and logically outermost TreeView itself. I can't tab down into one of my TextBox controls. Furthermore, if I click on a centrally positioned TextBox to give it focus, I want to be able to tab to the next TextBox below it, or alt-tab to the prior TextBox above it. Instead, tab takes me to the menu "File" command and alt-tab takes me to the bottom of the left side buttons, both of these cases being away from the TreeView altogether.
I checked, and EVERYTHING has by default IsTabstop set to true. Also, I tried explicitly setting the TabIndex of strictly the TextBox controls, and this didn't help.
What am I missing here?
[[[
In detail, the TreeView contains multiple items of TreeViewItem class, which I call "sections". (Each section has a Label object as the .header for displaying content.) Each section TreeViewItem contains in turn multiple items of TreeViewItem class, which I call "subsections". (Each subsection has a Label object as the .header for displaying content.) Next, each subsection TreeViewItem contains multiple items of WorksheetEntry class (derived from TreeViewItem), which I call a worksheet entry. Next, each worksheet entry WorksheetEntry contains a StackPanel (horizontal), which contains three more controls: a Label, a TextBox (**), and a TextBox (readonly).
Also, I'll mention a few exceptions in the rare case that these are causing the problem. A few of the subsections are WorksheetEntry objects rather than TreeViewItem objects, and these fellows include a CheckBox rather than a Label for the .header. (In other words, some subsections have checkboxes to enable them.) It is my intent that tabbing flow through these subsections as well as the lower level worksheet item lines. Furthermore, some worksheet item lines include a CheckBox rather than a TextBox as the middle object in the horizontal StackPanel. Obviously, these CheckBox objects are to be included in the tab order.
]]]
Sunday, July 4, 2010 6:35 PM
Answers
-
The tab and focus functions in WPF stump a lot of people. Here is a modified version of your example that lets you tab through the tree view. Notice the KeyboardNavigation.TabNavigation properties on both the tree view and tree view items. The problem you had was because of how WPF assumed you wanted to tab through nested/child objects.
<Window x:Class="TestApp.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:testApp="clr-namespace:TestApp" Title="MainWindow" Height="300" Width="300" ContentRendered="Window_ContentRendered"> <Window.Resources> <Style TargetType="TreeViewItem"> <Setter Property="KeyboardNavigation.TabNavigation" Value="Continue"/> <Setter Property="IsTabStop" Value="True"/> </Style> </Window.Resources> <Grid Name="grid" Background="AliceBlue"> <TreeView Height="287" KeyboardNavigation.TabNavigation="Cycle" HorizontalAlignment="Left" Margin="93,12,0,0" Name="treeView1" VerticalAlignment="Top" Width="398" > <TreeViewItem Header="Section 1" IsExpanded="True"> <TextBox>Line 1</TextBox> </TreeViewItem> <TreeViewItem Header="Section 2" IsExpanded="True" > <TextBox>Line 2</TextBox> </TreeViewItem> <TreeViewItem Header="Section 3" IsExpanded="True" > <TextBox>Line 3</TextBox> </TreeViewItem> </TreeView> <Button Content="Button I" Height="23" HorizontalAlignment="Left" Margin="12,12,0,0" Name="button1" VerticalAlignment="Top" Width="75" /> <Button Content="Button II" Height="23" HorizontalAlignment="Left" Margin="12,41,0,0" Name="button2" VerticalAlignment="Top" Width="75" /> <Button Content="Button III" Height="23" HorizontalAlignment="Left" Margin="12,70,0,0" Name="button3" VerticalAlignment="Top" Width="75" /> </Grid> </Window>
Tuesday, July 6, 2010 4:54 AM
All replies
-
I built a test case from XAML, and it exhibits the same [faulty] tab behavior. What do I need to do to make the tab key take me between TextBox controls "Line 1", "Line 2", and "Line 3"?
<Window x:Class="TestTreeView.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Height="350" Width="525"> <Grid> <TreeView Height="287" HorizontalAlignment="Left" Margin="93,12,0,0" Name="treeView1" VerticalAlignment="Top" Width="398" > <!-- <TextBox>Line A</TextBox> <TextBox>Line B</TextBox> <TextBox>Line C</TextBox> --> <TreeViewItem Header="Section 1" IsExpanded="True"> <TextBox>Line 1</TextBox> </TreeViewItem> <TreeViewItem Header="Section 2" IsExpanded="True"> <TextBox>Line 2</TextBox> </TreeViewItem> <TreeViewItem Header="Section 3" IsExpanded="True"> <TextBox>Line 3</TextBox> </TreeViewItem> </TreeView> <Button Content="Button I" Height="23" HorizontalAlignment="Left" Margin="12,12,0,0" Name="button1" VerticalAlignment="Top" Width="75" /> <Button Content="Button II" Height="23" HorizontalAlignment="Left" Margin="12,41,0,0" Name="button2" VerticalAlignment="Top" Width="75" /> <Button Content="Button III" Height="23" HorizontalAlignment="Left" Margin="12,70,0,0" Name="button3" VerticalAlignment="Top" Width="75" /> </Grid> </Window>
Sunday, July 4, 2010 9:37 PM -
I wrote my own class to make tabstop work for controls inside a TreeView. I'll try to get permission to post it back here for others.Monday, July 5, 2010 6:25 PM
-
The tab and focus functions in WPF stump a lot of people. Here is a modified version of your example that lets you tab through the tree view. Notice the KeyboardNavigation.TabNavigation properties on both the tree view and tree view items. The problem you had was because of how WPF assumed you wanted to tab through nested/child objects.
<Window x:Class="TestApp.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:testApp="clr-namespace:TestApp" Title="MainWindow" Height="300" Width="300" ContentRendered="Window_ContentRendered"> <Window.Resources> <Style TargetType="TreeViewItem"> <Setter Property="KeyboardNavigation.TabNavigation" Value="Continue"/> <Setter Property="IsTabStop" Value="True"/> </Style> </Window.Resources> <Grid Name="grid" Background="AliceBlue"> <TreeView Height="287" KeyboardNavigation.TabNavigation="Cycle" HorizontalAlignment="Left" Margin="93,12,0,0" Name="treeView1" VerticalAlignment="Top" Width="398" > <TreeViewItem Header="Section 1" IsExpanded="True"> <TextBox>Line 1</TextBox> </TreeViewItem> <TreeViewItem Header="Section 2" IsExpanded="True" > <TextBox>Line 2</TextBox> </TreeViewItem> <TreeViewItem Header="Section 3" IsExpanded="True" > <TextBox>Line 3</TextBox> </TreeViewItem> </TreeView> <Button Content="Button I" Height="23" HorizontalAlignment="Left" Margin="12,12,0,0" Name="button1" VerticalAlignment="Top" Width="75" /> <Button Content="Button II" Height="23" HorizontalAlignment="Left" Margin="12,41,0,0" Name="button2" VerticalAlignment="Top" Width="75" /> <Button Content="Button III" Height="23" HorizontalAlignment="Left" Margin="12,70,0,0" Name="button3" VerticalAlignment="Top" Width="75" /> </Grid> </Window>
Tuesday, July 6, 2010 4:54 AM -
Thanks for the advice 8xFather. This works better, but there are still problems. I added strictly the <Window Resources> tag plus the <TreeView> KeyboardNavigation attribute. I've shown my new complete xaml below.
In order of priority...
First: I added IsTabStop="False" to my section headings that were not TextBox objects. But I still get a little strangeness on tabbing. The focus goes to each TextBox twice, once at the left edge (border) of the box, and a second time at the text content inside. I don't see another object (a zero size one) that I can set to no tab stop. With the three TextBox objects, there should be exactly three tab stops, but there are six.
Second: Backward tabbing via shift-tab doesn't work. The focus goes first to the last TextBox, and the next tab takes you outside of the TreeView rather than up to the middle TextBox.
Third: Once I get inside the TreeView with focus, tabbing can never exit. It loops within the TreeView. I can live with this.
Are there perhaps some additional settings that will fix at least the first, and perhaps also the second or third issue?
Finally, *** I need to do this in code, not xaml, because the TreeView is programmatically created. I might be able to organize putting the fundamentals in xaml, but nevertheless I'd like to know how to code the <Window.Resources> tag. Also, for TreeView, the KeyboardNavigation attribute doesn't come up [with intellisense] and I assume won't compile as a TreeView member, so there must be a different source code syntax for it. (I realize I could search further for these answers, given my new knowledge, but while we're in this forum topic...)
<Window x:Class="TestTreeView.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Height="682" Width="525"> <Window.Resources> <Style TargetType="TreeViewItem"> <Setter Property="KeyboardNavigation.TabNavigation" Value="Continue"/> <Setter Property="IsTabStop" Value="True"/> </Style> </Window.Resources> <Grid> <TreeView Height="287" KeyboardNavigation.TabNavigation="Cycle" HorizontalAlignment="Left" Margin="290,12,0,0" Name="tvTest" VerticalAlignment="Top" Width="201"> <TreeViewItem Header="Section 1" IsExpanded="True" IsTabStop="False"> <TextBox Name="txtLine1">Line 1</TextBox> </TreeViewItem> <TreeViewItem Header="Section 2" IsExpanded="True" IsTabStop="False"> <TextBox Name="txtLine2">Line 2</TextBox> </TreeViewItem> <TreeViewItem Header="Section 3" IsExpanded="True" IsTabStop="False"> <TextBox Name="txtLine3">Line 3</TextBox> </TreeViewItem> </TreeView> <Button Content="Button I" Height="23" HorizontalAlignment="Left" Margin="12,12,0,0" Name="button1" VerticalAlignment="Top" Width="75" /> <Button Content="Button II" Height="23" HorizontalAlignment="Left" Margin="12,41,0,0" Name="button2" VerticalAlignment="Top" Width="75" /> <Button Content="Button III" Height="23" HorizontalAlignment="Left" Margin="12,70,0,0" Name="button3" VerticalAlignment="Top" Width="75" /> </Grid> </Window>
Tuesday, July 6, 2010 12:30 PM -
Think of how the tree works. The text box is contained in a tree view item, and the tree view item is contained in the tree view. What looks like the text box getting focus twice is actually the tree view item getting focus then the text box. It can get a little tricky finding the right combination of settings when trying to tab through controls that are contained in other controls, that are contained in other controls and so on.
Tuesday, July 6, 2010 3:16 PM -
Thanks, 8xFather, but I already recognized the above. If you look at my XAML on my prior post, you see that I set the TreeViewItem.IsTabStop to false. Prior to doing that, there were THREE tab stops per section. The cursor would stop on the text "Section 2" for example, where that's the TreeViewItem.Header. After setting TreeViewItem.IsTabStop to false, I got rid of that tab stop. Two more tab stops remained, however. Yet inside each of the TreeViewItems of my XAML, there's only a single control, the TextBox. It's as if compilation of the XAML has inserted some kind of container that's inside the TreeViewItem and outside the TextBox, and its this contain that's getting the extra, unwanted tab stop.
Anyway, given the other problems I mentioned above, I believe I'll just stick with the class I wrote to manually handle this. It works great, allowing complete and correct tabbing forward and backward.
Thanks very much for helping nevertheless. You've opened my eyes to the Style and Setter tags
Wednesday, July 7, 2010 2:58 PM