I have a view in WPF that I have been fighting to get the tab order correct on. I have three text boxes (lets call them Text1, Text2, and Text3) and two custom controls, each of which has several other text boxes and assorted controls on them (lets call them Custom1 and Custom2).
The layout is such that tab flow should go Text1, Text2, Custom1, Custom2, Text3. I have set the TabIndex property on each control to match this ordering, and verified that all of them are set to IsTabStop.
The problem is, the actual tab flow goes Text1, Text2, Text3, and then Custom1, Custom2, and I cannot figure out why. When it goes to the custom controls, it does properly step over every control in them as I would expect. I just can't figure out why it goes to the third text box before it goes to the first custom control.
I have tried everything I can think of, including making sure all of the xaml elements are arranged in tab order, but nothing seems to help.
I suspect it is going over all of its basic controls before giving focus to any custom controls, but I am out of ideas. Any help would be great.
EDIT: Here's my xaml:
<Grid>
<GroupBox x:Name="_groupBox" BorderBrush="Transparent" BorderThickness="0">
<Grid x:Name="_card">
<Label Content="A:" Height="28" HorizontalAlignment="Left" Margin="5,3,0,0" Name="_labelA" VerticalAlignment="Top" />
<Label Content="B:" Height="28" HorizontalAlignment="Left" Margin="5,25,0,0" Name="_labelB" VerticalAlignment="Top" />
<TextBox Name="_a" Height="20" HorizontalAlignment="Left" Text="{Binding AText, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" IsEnabled="{Binding AEnabled}" Margin="94,5,0,0" VerticalAlignment="Top" LostFocus="InputNameLeave" Width="221" TabIndex="0" />
<TextBox Name="_b" Height="20" HorizontalAlignment="Left" Margin="94,26,0,0" Text="{Binding BText, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" VerticalAlignment="Top" Width="102" TabIndex="1" />
<my:CustomControlA HorizontalAlignment="Left" Margin="-6,55,0,0" x:Name="_custom1" VerticalAlignment="Top" TabIndex="2" IsTabStop="True" />
<my:CustomControlB HorizontalAlignment="Left" Margin="334,0,0,0" x:Name="_custom2" VerticalAlignment="Top" Width="320" TabIndex="3" IsTabStop="True" />
<Label Content="C:" Height="28" HorizontalAlignment="Left" Margin="342,59,0,0" Name="_labelC" VerticalAlignment="Top" />
<TextBox Name="_c" Height="20" HorizontalAlignment="Left" Margin="417,60,0,0" Text="{Binding CText, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" IsEnabled="{Binding CEnabled}" VerticalAlignment="Top" Width="154" TabIndex="4" />
</Grid>
</GroupBox>
</Grid>
I don't have your custom control to hand, so I created one that contained just a TextBox. After wiring this up to your XAML, I found that the tab order went as follows:
TextBox1, TextBox2, CustomControl1, CustomControl2, TextBox3, TextBox within CustomControl1, TextBox within CustomControl2.
Note that after TextBox2 tabbing moves the focus onto the custom controls themselves, not any child controls they happen to have. The TextBox in my custom control didn't have a TabIndex, so its TabIndex was assumed to be the default value, Int32.MaxValue (see the MSDN documentation for the TabIndex property). Hence they come last in the tab order.
I found that things worked better if I marked the custom controls as IsTabStop="False"
(I don't see why I'd want the focus on the custom controls themselves), and set the tab-index of the TextBox in the custom control to that given in the <my:CustomControl />
element by adding the attribute TabIndex="{TemplateBinding TabIndex}"
to the TextBox in the custom control. Once I'd done that, the tab order was, as I would expect,
TextBox1, TextBox2, TextBox within CustomControl1, TextBox within CustomControl2, TextBox3.
Of course, my custom control consists only of a single TextBox, so setting a single tab-index fixed things for me. I don't have your code, so I can't say for sure, but it might be enough to set the tab-index of all child controls within your custom controls to that in the <my:CustomControl />
element in the same way.
EDIT: if you can't use a TemplateBinding
, and instead have a .xaml file with a corresponding .xaml.cs file, then you have what's called a user control, not a custom control. In that case,
you can try setting the tab index inside the XAML for CustomControlA using something like the following:
TabIndex="{Binding Path=TabIndex, RelativeSource={RelativeSource AncestorType={x:Type my:CustomControlA}}}"