0

I have a search screen in my WPF application. The screen is implemented as a UserControl in a TabItem of a TabControl. When the user switches to the Search tab, I want the focus to go into one particular field. I asked a question here about how to figure out where the focus was going to. I now know where it's going. Now I want to figure out why it's going there so I can stop it.

Note that the focus is changing spontaneously and has nothing to do with any user activity. All the user has done is click on the search tab in the main window. The focus is supposed to go to this one particular text box; this is done in the UserControl's Loaded event handler. And it does go to that TextBox initially. Then, for some reason, it goes to the CheckBox.

I have assigned values to the TabIndex controls on my form that the user can interact with. The CheckBox is at TabIndex 1. The TextBox in question is at TabIndex 9. This is also the only TextBox on the form.

In the past, the focus would move to the TextBox and stay there. Without realizing it, I changed something that causes the focus to go to the CheckBox. I don't know what it was that I changed, exept that it was at about the time I upgraded the Telerik controls library to the latest version.

Here is the Xaml for the whole control, minus some stuff that wouldn't matter:

<UserControl x:Class="CarSystem.CustomControls.Searcher"
         <!-- XML Namespaces removed for brevity -->
         Height="620"
         Loaded="UserControl_Loaded"
         Width="990">

<UserControl.Resources>
    <!--- Resource removed for brevity -->
</UserControl.Resources>

<Grid Background="{DynamicResource ContentBackground}"
      FocusManager.IsFocusScope="True"
      Name="LayoutRoot">
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="*" />
        <ColumnDefinition Width="110" />
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto" />
        <RowDefinition Height="*" />
    </Grid.RowDefinitions>

    <Grid Grid.Column="0"
          Grid.Row="0">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>

        <GroupBox BorderBrush="{DynamicResource ControlBorder}"
                  FontSize="16"
                  FontWeight="Bold"
                  Foreground="{DynamicResource TextForeground}"
                  Grid.Column="0"
                  Grid.Row="0"
                  Header="Alarm Class:"
                  Margin="5,0">
            <Grid VerticalAlignment="Center">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="*" />
                    <ColumnDefinition Width="Auto" />
                </Grid.ColumnDefinitions>
                <Grid.RowDefinitions>
                    <RowDefinition Height="35" />
                    <RowDefinition Height="*" />
                </Grid.RowDefinitions>
                <CheckBox Click="AllAlarmClasses_Click"
                          Content="ALL"
                          FontSize="14"
                          FontWeight="Bold"
                          Grid.Column="0"
                          Grid.Row="0"
                          HorizontalAlignment="Left"
                          Margin="5"
                          Name="AllAlarmClasses"
                          TabIndex="1"
                          VerticalAlignment="Center" />
                <Button Background="{DynamicResource ButtonBackground}"
                        Click="ExpandPicker_Click"
                        Content="Expand"
                        FontSize="14"
                        FontWeight="Bold"
                        Grid.Column="1"
                        Grid.Row="0"
                        Foreground="{DynamicResource ButtonForeground}"
                        Margin="5"
                        Name="ExpandAlarmClass"
                        TabIndex="2" />
                <ListBox BorderBrush="Black"
                         BorderThickness="1"
                         CheckBox.Click="AlarmClassPicker_Click"
                         ItemTemplate="{StaticResource CheckableChoice}"
                         FontSize="14"
                         FontWeight="Bold"
                         Grid.Column="0"
                         Grid.ColumnSpan="2"
                         Grid.Row="1"
                         Height="100"
                         ItemsSource="{Binding Path=AlarmClassChoices, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}, Mode=TwoWay}"
                         Margin="5,0"
                         Name="AlarmClassPicker"
                         SelectionMode="Multiple"
                         TabIndex="3"
                         Visibility="Collapsed" />
            </Grid>
        </GroupBox>

        <GroupBox BorderBrush="{DynamicResource ControlBorder}"
                  FontSize="16"
                  FontWeight="Bold"
                  Foreground="{DynamicResource TextForeground}"
                  Grid.Column="0"
                  Grid.Row="1"
                  Header="Source:"
                  Margin="5,0">
            <cs:TouchComboBox Background="{DynamicResource UnfocusedBackground}"
                              BorderBrush="{DynamicResource ControlBorder}"
                              FontSize="14"
                              FontWeight="Bold"
                              Foreground="{DynamicResource UnfocusedForeground}"
                              GridBackground="{DynamicResource ContentBackground}"
                              Height="50"
                              IsTabStop="True"
                              ItemsSource="{Binding Path=HotListChoices, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}, Mode=TwoWay}"
                              Margin="5,0"
                              x:Name="HotListPicker"
                              SelectionChanged="SourcePicker_SelectionChanged"
                              TabIndex="4"
                              TimeOfDayMode="{Binding Path=TimeOfDayMode, RelativeSource={RelativeSource AncestorType={x:Type cs:Searcher}}}"
                              VerticalAlignment="Top" />
        </GroupBox>
        <GroupBox BorderBrush="{DynamicResource ControlBorder}"
                  FontSize="16"
                  FontWeight="Bold"
                  Foreground="{DynamicResource TextForeground}"
                  Grid.Column="1"
                  Grid.Row="0"
                  Header="Start Date:"
                  Margin="5,0">
            <telerik:RadDateTimePicker FontWeight="Bold"
                                       Height="35"
                                       Margin="5"
                                       Name="StartDatePicker"
                                       SelectionChanged="DateTimePicker_SelectionChanged"
                                       Style="{DynamicResource RadDateTimePickerControlTemplate1}"
                                       TabIndex="5"
                                       VerticalAlignment="Center" />
        </GroupBox>
        <GroupBox BorderBrush="{DynamicResource ControlBorder}"
                  FontSize="16"
                  FontWeight="Bold"
                  Foreground="{DynamicResource TextForeground}"
                  Grid.Column="1"
                  Grid.Row="1"
                  Header="End Date:"
                  Margin="5,0">
            <telerik:RadDateTimePicker FontSize="14"
                                       FontWeight="Bold"
                                       Height="35"
                                       Margin="5"
                                       Name="EndDatePicker"
                                       SelectionChanged="DateTimePicker_SelectionChanged"
                                       Style="{DynamicResource RadDateTimePickerControlTemplate1}"
                                       TabIndex="6"
                                       VerticalAlignment="Center" />
        </GroupBox>

        <GroupBox BorderBrush="{DynamicResource ControlBorder}"
                  FontSize="16"
                  FontWeight="Bold"
                  Foreground="{DynamicResource TextForeground}"
                  Grid.Column="2"
                  Grid.Row="0"
                  Header="State:"
                  Margin="5,0">
            <cs:TouchComboBox Background="{DynamicResource UnfocusedBackground}"
                              BorderBrush="{DynamicResource ControlBorder}"
                              DisplayMemberPath="Value"
                              FontSize="14"
                              FontWeight="Bold"
                              Foreground="{DynamicResource UnfocusedForeground}"
                              GridBackground="{DynamicResource ContentBackground}"
                              Height="50"
                              ItemsSource="{Binding Path=LocaleChoices, Mode=TwoWay, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}"
                              Margin="5"
                              x:Name="StatePicker"
                              SelectedValue="{Binding Path=LocaleCode}"
                              SelectedValuePath="Key"
                              SelectionChanged="StatePicker_SelectionChanged"
                              TabIndex="7"
                              TimeOfDayMode="{Binding Path=TimeOfDayMode, RelativeSource={RelativeSource AncestorType={x:Type cs:Searcher}}}"
                              VerticalAlignment="Center" />
        </GroupBox>
        <GroupBox BorderBrush="{DynamicResource ControlBorder}"
                  FontSize="16"
                  FontWeight="Bold"
                  Foreground="{DynamicResource TextForeground}"
                  Grid.Column="2"
                  Grid.Row="1"
                  Header="Plate:"
                  Margin="5,0">
            <Border BorderBrush="{DynamicResource ControlBorder}"
                    BorderThickness="1"
                    Height="35"
                    Margin="5"
                    VerticalAlignment="Center">
                <TextBox FontSize="14"
                         FontWeight="Bold"
                         GotFocus="PlateBox_GotFocus"
                         LostFocus="PlateBox_LostFocus"
                         Margin="-1"
                         MaxLength="25"
                         MaxLines="1"
                         Name="PlateBox"
                         TabIndex="8"
                         Text="{Binding Path=Plate, Mode=TwoWay}"
                         TextChanged="PlateBox_TextChanged"
                         ToolTip='Wildcards ("%", "_", "[", "]") can be used' />
            </Border>
        </GroupBox>
    </Grid>

    <TabControl Background="{DynamicResource TabBackground}"
                Grid.Row="1"
                Margin="0,20,0,5"
                Name="ResultTabs"
                TabIndex="9">

        <TabItem Background="{DynamicResource TabHeaderBackground}"
                 FontSize="16"
                 FontWeight="Bold"
                 Foreground="{DynamicResource TabHeaderForeground}"
                 Header="Hot List Entries:"
                 Name="HotListEntryTab">
            <Grid>
                <Grid.RowDefinitions>
                    <RowDefinition Height="*" />
                    <RowDefinition Height="Auto" />
                </Grid.RowDefinitions>

                <telerik:RadGridView AutoExpandGroups="True"
                                     AutoGenerateColumns="False"
                                     CanUserDeleteRows="False"
                                     CanUserFreezeColumns="False"
                                     CanUserInsertRows="False"
                                     CanUserResizeColumns="True"
                                     CanUserSortColumns="True"
                                     EnableColumnVirtualization="True"
                                     EnableRowVirtualization="True"
                                     FontSize="14"
                                     FontWeight="Bold"
                                     IsReadOnly="True"
                                     Name="HotListEntriesGrid"
                                     SelectionChanged="HotListEntriesGrid_SelectionChanged"
                                     SelectionUnit="FullRow"
                                     ScrollViewer.CanContentScroll="True"
                                     ScrollViewer.HorizontalScrollBarVisibility="Auto"
                                     ScrollViewer.VerticalScrollBarVisibility="Auto"
                                     TabIndex="10"
                                     ToolTip="Matching Hot List Entries">
                    <telerik:RadGridView.Columns>
                        <telerik:GridViewDataColumn DataMemberBinding="{Binding Plate,        Mode=OneWay}"
                                                    Header="Plate"
                                                    Width="*" />
                        <telerik:GridViewDataColumn DataMemberBinding="{Binding LocaleCode, Mode=OneWay}"
                                                    Header="State"
                                                    Width="75" />
                        <telerik:GridViewDataColumn DataMemberBinding="{Binding ListName,   Mode=OneWay}"
                                                    Header="Source"
                                                    Width="150" />
                        <telerik:GridViewDataColumn DataMemberBinding="{Binding AlarmClass, Mode=OneWay}"
                                                    Header="Alarm Class"
                                                    Width="150" />
                        <telerik:GridViewDataColumn DataMemberBinding="{Binding Notes,     Mode=OneWay}"
                                                    Header="Notes"
                                                    Width="*" />
                    </telerik:RadGridView.Columns>
                </telerik:RadGridView>
                <cs:ProgressControl FontSize="14"
                                    FontWeight="Bold"
                                    Grid.Column="0"
                                    Grid.Row="1"
                                    Height="55"
                                    Margin="0,5"
                                    x:Name="HotListProgressCtrl"
                                    TabIndex="11"
                                    TimeOfDayMode="{Binding Path=TimeOfDayMode, RelativeSource={RelativeSource AncestorType={x:Type cs:Searcher}}}"
                                    Visibility="Collapsed" />
            </Grid>
        </TabItem>

        <TabItem Background="{DynamicResource TabHeaderBackground}"
                 FontSize="16"
                 FontWeight="Bold"
                 Foreground="{DynamicResource TabHeaderForeground}"
                 Header="Reads &amp; Alarms:"
                 IsSelected="True"
                 Name="ReadsTabItem">
            <Grid>
                <Grid.RowDefinitions>
                    <RowDefinition Height="*" />
                    <RowDefinition Height="Auto" />
                </Grid.RowDefinitions>

                <telerik:RadGridView AutoExpandGroups="True"
                                     AutoGenerateColumns="False"
                                     CanUserDeleteRows="False"
                                     CanUserFreezeColumns="False"
                                     CanUserInsertRows="False"
                                     CanUserResizeColumns="True"
                                     CanUserSortColumns="True"
                                     EnableColumnVirtualization="True"
                                     EnableRowVirtualization="True"
                                     FontSize="14"
                                     FontWeight="Bold"
                                     IsReadOnly="True"
                                     Name="ReadsGrid"
                                     RowDetailsTemplate="{StaticResource ReadRowDetailsTemplate}"
                                     RowStyleSelector="{StaticResource StyleSelector}"
                                     SelectionChanged="ReadsGrid_SelectionChanged"
                                     SelectionUnit="FullRow"
                                     ScrollViewer.CanContentScroll="True"
                                     ScrollViewer.HorizontalScrollBarVisibility="Auto"
                                     ScrollViewer.VerticalScrollBarVisibility="Auto"
                                     ShowGroupFooters="True"
                                     TabIndex="12"
                                     ToolTip="Matching Reads">
                    <telerik:RadGridView.Columns>
                        <cs:CustomGridViewToggleRowDetailsColumn IsEnabled="False"
                                                                 IsFilterable="False"
                                                                 IsGroupable="False"
                                                                 ToggleButtonVisibility="{Binding Path=HasAlarms, Converter={StaticResource BoolToVisibility}}" />
                        <telerik:GridViewDataColumn DataMemberBinding="{Binding Plate,       Mode=OneWay}"
                                                    Header="Plate"
                                                    Width="*" />
                        <telerik:GridViewDataColumn DataMemberBinding="{Binding State,       Mode=OneWay}"
                                                    Header="State"
                                                    Width="75" />
                        <telerik:GridViewDataColumn DataMemberBinding="{Binding TimeStamp,  Mode=OneWay, Converter={StaticResource DateConverter}}"
                                                    Header="Date &amp; Time"
                                                    Width="150" />
                        <telerik:GridViewDataColumn DataMemberBinding="{Binding Latitude, Converter={StaticResource CoordConverter}, ConverterParameter=NS}"
                                                    Header="Latitude"
                                                    Width="150" />
                        <telerik:GridViewDataColumn DataMemberBinding="{Binding Longitude, Converter={StaticResource CoordConverter}, ConverterParameter=EW}"
                                                    Header="Longitude"
                                                    Width="150" />
                    </telerik:RadGridView.Columns>
                </telerik:RadGridView>
                <cs:ProgressControl FontSize="14"
                                    FontWeight="Bold"
                                    Grid.Row="1"
                                    Height="55"
                                    Margin="0,5"
                                    x:Name="ProgressCtrl"
                                    TabIndex="13"
                                    TimeOfDayMode="{Binding Path=TimeOfDayMode, RelativeSource={RelativeSource AncestorType={x:Type cs:Searcher}}}"
                                    Visibility="Collapsed" />
            </Grid>
        </TabItem>
    </TabControl>

    <GridSplitter Background="{DynamicResource SeparatorColor}"
                  Grid.Row="1"
                  Height="10"
                  HorizontalAlignment="Stretch"
                  Margin="0,5"
                  VerticalAlignment="Top" />

    <Grid Grid.Column="1"
          Grid.RowSpan="2">
        <Grid.RowDefinitions>
            <RowDefinition Height="55" />
            <RowDefinition Height="55" />
            <RowDefinition Height="55" />
            <RowDefinition Height="*" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="*" />
            <RowDefinition Height="55" />
            <RowDefinition Height="55" />
        </Grid.RowDefinitions>
        <Button Background="{DynamicResource ButtonBackground}"
                Click="SearchButton_Click"
                Content="Search"
                FontSize="16"
                FontWeight="Bold"
                Foreground="{DynamicResource ButtonForeground}"
                Grid.Row="0"
                IsDefault="True"
                Margin="5"
                Name="SearchButton"
                TabIndex="14" />
        <Button Background="{DynamicResource ButtonBackground}"
                Click="ClearButton_Click"
                Content="Clear"
                FontSize="16"
                FontWeight="Bold"
                Foreground="{DynamicResource ButtonForeground}"
                Grid.Row="1"
                Margin="5"
                Name="ClearButton"
                TabIndex="15" />
        <Button Background="{DynamicResource ButtonBackground}"
                Click="SaveCriteriaButton_Click"
                FontSize="16"
                FontWeight="Bold"
                Grid.Row="2"
                Foreground="{DynamicResource ButtonForeground}"
                Margin="5"
                Name="SaveCriteriaButton"
                TabIndex="16"
                Visibility="Visible">
            <Button.Content>
                <TextBlock Text="Save Report"
                           TextAlignment="Center"
                           TextWrapping="Wrap" />
            </Button.Content>
        </Button>
        <TextBlock FontSize="14"
                   FontWeight="Bold"
                   Foreground="{DynamicResource TextForeground}"
                   Grid.Row="4"
                   Margin="5"
                   Text="Number of Matches:"
                   TextAlignment="Center"
                   TextWrapping="Wrap" />
        <TextBlock FontSize="14"
                   FontWeight="Bold"
                   Foreground="{DynamicResource TextForeground}"
                   Grid.Row="5"
                   Margin="5"
                   Text="Hot List Entries:"
                   TextAlignment="Center"
                   TextWrapping="Wrap" />
        <TextBlock FontSize="14"
                   FontWeight="Bold"
                   Foreground="{DynamicResource TextForeground}"
                   Grid.Row="6"
                   Margin="5,0,5,10"
                   Text="{Binding Converter={StaticResource LongConverter}, ConverterParameter='#,##0', Path=NoHotListEntries, RelativeSource={RelativeSource AncestorType={x:Type cs:Searcher}}}"
                   TextAlignment="Center"
                   TextWrapping="Wrap" />
        <TextBlock FontSize="14"
                   FontWeight="Bold"
                   Foreground="{DynamicResource TextForeground}"
                   Grid.Row="7"
                   Margin="5"
                   Text="Reads:"
                   TextAlignment="Center"
                   TextWrapping="Wrap" />
        <TextBlock FontSize="14"
                   FontWeight="Bold"
                   Foreground="{DynamicResource TextForeground}"
                   Grid.Row="8"
                   Margin="5,0,5,10"
                   Text="{Binding Converter={StaticResource LongConverter}, ConverterParameter='#,##0', Path=NoReads, RelativeSource={RelativeSource AncestorType={x:Type cs:Searcher}}}"
                   TextAlignment="Center"
                   TextWrapping="Wrap" />
        <Button Background="{DynamicResource ButtonBackground}"
                Click="ExportButton_Click"
                Content="Export"
                FontSize="16"
                FontWeight="Bold"
                Foreground="{DynamicResource ButtonForeground}"
                Grid.Row="10"
                Margin="5"
                Name="ExportButton"
                TabIndex="17" />
        <Button Background="{DynamicResource ButtonBackground}"
                Click="CloseButtonClicked"
                Content="Close"
                FontSize="20"
                FontWeight="Bold"
                Foreground="{DynamicResource ButtonForeground}"
                Grid.Row="11"
                HorizontalAlignment="Right"
                Margin="5"
                Name="CloseButton"
                TabIndex="18"
                Width="100" />
    </Grid>

    <Canvas Grid.Column="0"
            Grid.ColumnSpan="2"
            Grid.Row="0"
            Grid.RowSpan="4"
            Name="KeyboardPopupCanvas">
        <cs:KeyboardPopup x:Name="KeyboardPopup"
                          TimeOfDayMode="{Binding Path=TimeOfDayMode, RelativeSource={RelativeSource AncestorType={x:Type cs:Searcher}}}"
                          Title="Keyboard"
                          Visibility="Collapsed" />
    </Canvas>

</Grid>

Thanks for your help

Tony

Community
  • 1
  • 1
Tony Vitabile
  • 8,298
  • 15
  • 67
  • 123
  • Why not set up the `tabindex` so that the textbox is first and then each item you want accessed next when tab is pressed is next in order. This allows a user to fill out your fields in a logical order when pressing tab(as opposed to a random order). This would also make it so you dont have to specify the focus in the loaded event(as it should go to the first tabindex) – jzworkman Mar 30 '12 at 13:56
  • you know, that's probably what's happening. It's probably sending the focus to the lowest numbered tabindex. And it's doing it after I put the focus in the TextBox. Making the TextBox Tabindex 1 is probably the way to go. – Tony Vitabile Mar 30 '12 at 14:41
  • Remember to change all of the tabindexes to the order you want the user to fill them in(basically left to right, top to bottom) so that when someone interacts with your form(using keyboard only input) they have a good user experience. – jzworkman Mar 30 '12 at 15:07
  • Actually, I had to rearrange the controls and then I did exactly that. it's much nicer now. – Tony Vitabile Mar 30 '12 at 17:54

1 Answers1

2

Just so that people who view this question later will know, the solution I went with was to rearrange the fields on the form so that the field I wanted to have the focus initially was the first field on the form. WPF automatically gives the focus to the control with the lowest TabIndex. Which is why my control was losing the focus after I put it there in the Loaded event handler.

I suppose that if I didn't have any TabIndex field setters in the Xaml that this would never have happened. Live and learn.

Tony Vitabile
  • 8,298
  • 15
  • 67
  • 123
  • It's a few months later and while I haven't changed my code, it occurs to me that the problem I was having may have been where I was moving the focus. I was doing it in the `Loaded` event handler. It may have actually worked if I had put it in some other event, like the `ContentRendered` event. This might be worth experimenting with in the future. – Tony Vitabile Jul 17 '12 at 15:09