DockPanel Tab Order
Asked Answered
P

3

18

I have a DockPanel set up in the DataTemplate of an ItemsControl as below:

<ItemsControl HorizontalContentAlignment="Stretch">
  <ItemsControl.ItemTemplate>
    <DataTemplate>
      <DockPanel>
        <ComboBox DockPanel.Dock="Left"/>
        <ComboBox DockPanel.Dock="Left"/>
        <Button DockPanel.Dock="Right">Button</Button>
        <!-- This will appear before the button...it has to go after it in the XAML so it will fill properly in the DockPanel -->
        <TextBox DockPanel.Dock="Left" MinWidth="100" HorizontalAlignment="Stretch"/>
      </DockPanel>
    </DataTemplate>
  </ItemsControl.ItemTemplate>
</ItemsControl>

I want the textbox to fill all the remaining space between the comboboxes and the button. I had to put the textbox last in the XAML because DockPanel will only fill the last child. It looks great; however, the tab order is now screwed up. It now tabs combobox-combobox-button-textbox instead of combobox-combobox-textbox-button.

I tried using KeyboardNavigation.TabIndex properties on each item, but since this is a DataTemplate for an ItemsControl (each of these dockpanels will be for a separate item), that made the tab order jump vertically down each of the items' comboboxes, then vertically down each textbox, then vertically down each button, rather than the desired behavior of going across each row, then down.

Example UI:

[Combo11] [Combo12] [Text1] [Button1]
[Combo21] [Combo22] [Text2] [Button2]

In the current state of affairs, it goes Combo11,Combo12,Button1,Text1,Combo21,Combo22,Button2,Text2. If I add TabOrder properties, it goes Combo11,Combo21,Combo12,Combo22,Text1,Text2,Button1,Button2.

I'd like it to go Combo11,Combo12,Text1,Button1,Combo21,Combo22,Text2,Button2.

Does anyone have any ideas on how to solve this UI problem?

Poisonous answered 23/8, 2010 at 16:39 Comment(0)
E
9

You could use a Grid instead of the DockPanel, like so:

<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="Auto"/>
        <ColumnDefinition Width="Auto"/>
        <ColumnDefinition Width="*"/>
        <ColumnDefinition Width="Auto"/>
    </Grid.ColumnDefinitions>
    <ComboBox />
    <ComboBox Grid.Column="1"/>
    <TextBox Grid.Column="2" MinWidth="100" />
    <Button Grid.Column="3">Button</Button>
 </Grid>

And if you want them to align nicely in the different columns - you could use SharedSizeGroup.

Evars answered 23/8, 2010 at 18:2 Comment(6)
That worked really well...and I have to ask, why does the first combobox have no column number? Does that mean it's automatically assigned to column #0? And thanks a bunch for the SharedSizeGroup tip--I would have had no idea what to even search! (p.s. you forgot / in </Grid.ColumnDefinitions>)Poisonous
It could have a Grid.Column="0" - but 0 is the default value - and I'm lazy :-). Yeah, SharedSizeGroup is sort of a hidden gem. I updated my example for others.Evars
Bah, couldn't get the SharedSizeGroup to work properly--probably because of the star sizing in the third column. :(Poisonous
Ah, it seems I needed a header for that, as per directions here blogs.interknowlogy.com/johnbowen/archive/2007/08/27/21132.aspx -EDIT- or perhaps not...but that site still helped. It seems to be working now, thanks a bunch!Poisonous
Last update, I promise! It turned out it all hinged on the Grid.IsSharedSizeScope property, which I didn't realize had to be on the parent -- in this case, the ItemsControl.Poisonous
I'm happy you got it working :-). Should probably have mentioned the IsSharedSizeScope...Evars
M
38

If you want to retain the DockPanel, you can use KeyboardNavigation.TabNavigation="Local" on the parent dockpanel, and then you CAN set the tab index values on the controls within it.

Like this -

    <ItemsControl HorizontalContentAlignment="Stretch">
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <DockPanel KeyboardNavigation.TabNavigation="Local">
                    <ComboBox DockPanel.Dock="Left" TabIndex="1"/>
                    <ComboBox DockPanel.Dock="Left" TabIndex="2"/>
                    <Button DockPanel.Dock="Right" TabIndex="4">Button</Button>
                    <!-- This will appear before the button...it has to go after it in the XAML so it will fill properly in the DockPanel -->
                    <TextBox DockPanel.Dock="Left" MinWidth="100" HorizontalAlignment="Stretch" TabIndex="3"/>
                </DockPanel>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>

As you found, if you just set the tab index values of the controls, these are global to the form, so all the TabIndex="0" are tabbed into first, then all the TabIndex="1", and so on. Set KeyboardNavigation.TabNavigation="Local" on the parent container fixes it.

Marylou answered 26/1, 2011 at 19:8 Comment(1)
I like this option as I feel pretty strongly about the DockPanel layout in some cases, and went to lengths to avoid using grids everywhere, unless they made sense for some other reason.Stinker
E
9

You could use a Grid instead of the DockPanel, like so:

<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="Auto"/>
        <ColumnDefinition Width="Auto"/>
        <ColumnDefinition Width="*"/>
        <ColumnDefinition Width="Auto"/>
    </Grid.ColumnDefinitions>
    <ComboBox />
    <ComboBox Grid.Column="1"/>
    <TextBox Grid.Column="2" MinWidth="100" />
    <Button Grid.Column="3">Button</Button>
 </Grid>

And if you want them to align nicely in the different columns - you could use SharedSizeGroup.

Evars answered 23/8, 2010 at 18:2 Comment(6)
That worked really well...and I have to ask, why does the first combobox have no column number? Does that mean it's automatically assigned to column #0? And thanks a bunch for the SharedSizeGroup tip--I would have had no idea what to even search! (p.s. you forgot / in </Grid.ColumnDefinitions>)Poisonous
It could have a Grid.Column="0" - but 0 is the default value - and I'm lazy :-). Yeah, SharedSizeGroup is sort of a hidden gem. I updated my example for others.Evars
Bah, couldn't get the SharedSizeGroup to work properly--probably because of the star sizing in the third column. :(Poisonous
Ah, it seems I needed a header for that, as per directions here blogs.interknowlogy.com/johnbowen/archive/2007/08/27/21132.aspx -EDIT- or perhaps not...but that site still helped. It seems to be working now, thanks a bunch!Poisonous
Last update, I promise! It turned out it all hinged on the Grid.IsSharedSizeScope property, which I didn't realize had to be on the parent -- in this case, the ItemsControl.Poisonous
I'm happy you got it working :-). Should probably have mentioned the IsSharedSizeScope...Evars
W
-5

Have you tried explicitly setting the tab order?

<Control KeyboardNavigation.TabIndex="0" />
Weatherly answered 23/8, 2010 at 16:46 Comment(2)
"I tried using KeyboardNavigation.TabIndex properties on each item, but since this is a DataTemplate for an ItemsControl (each of these dockpanels will be for a separate item), that made the tab order jump vertically down each of the items' comboboxes, then vertically down each textbox, then vertically down each button, rather than the desired behavior of going across each row, then down."Poisonous
No harm meant, but I tend to downvote answers that don't really help explain anything...in this example, I had already mentioned trying the tab order in my question. Again, I know since you can't hear me talking, you could misconstrue this as a snarky comment, but I'm really just trying to keep StackOverflow a helpful and uncluttered place.Poisonous

© 2022 - 2024 — McMap. All rights reserved.