DockPanel Tab Order

2019-06-15 07:19发布

问题:

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?

回答1:

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.



回答2:

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.



回答3:

Have you tried explicitly setting the tab order?

<Control KeyboardNavigation.TabIndex="0" />