Spook
Spook

Reputation: 25919

WPF, focusing element on window show

I'm trying to set focus to specific element on window show. The window is just a search/replace window with tabs; when user chooses "Search", search tab is activated and search textbox should receive focus. Similarly, when user chooses "Replace", replace tab is activated and replace textbox should receive focus.

Since window is non-modal, I reuse it and hide instead of closing. The problem is that the focus is not received properly. Say:

Upon opening window, basing on user choice, I call one of the following methods:

public void ChooseReplaceTab()
{
    tcTabs.SelectedItem = tReplace;
    FocusManager.SetFocusedElement(this, tbReplaceSearch);
    tbReplaceSearch.Focus();
}

public void ChooseSearchTab()
{
    tcTabs.SelectedItem = tSearch;
    FocusManager.SetFocusedElement(this, tbSearchSearch);
    tbSearchSearch.Focus();
}

Search window doesn't have anything fancy, just a bunch of tabs, textboxes, radios and buttons:

<Window x:Class="Dev.Editor.SearchReplaceWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:Dev.Editor"
        xmlns:p="clr-namespace:Dev.Editor.Resources;assembly=Dev.Editor.Resources"
        xmlns:t="clr-namespace:Dev.Editor.BusinessLogic.Types.Search;assembly=Dev.Editor.BusinessLogic"
        mc:Ignorable="d"
        Title="{x:Static p:Strings.SearchWindow_Title}" SizeToContent="WidthAndHeight" ResizeMode="NoResize" Closing="HandleWindowClosing">
    <TabControl x:Name="tcTabs" Margin="{StaticResource DialogWindowPadding}">

        <!-- Search -->

        <TabItem x:Name="tSearch" Header="{x:Static p:Strings.SearchWindow_SearchTab}" >
            <GroupBox Header="{x:Static p:Strings.SearchWindow_SearchTab}" Padding="4">
                <StackPanel Orientation="Horizontal">
                    <StackPanel Orientation="Vertical">
                        <Grid>
                            <Grid.RowDefinitions>
                                <RowDefinition Height="Auto" />
                            </Grid.RowDefinitions>
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="100" />
                                <ColumnDefinition Width="250" />
                            </Grid.ColumnDefinitions>

                            <Label Grid.Row="0" Grid.Column="0" Content="{x:Static p:Strings.SearchWindow_SearchedText}"/>
                            <TextBox x:Name="tbSearchSearch" Grid.Row="0" Grid.Column="1" HorizontalAlignment="Stretch" Text="{Binding Search, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
                        </Grid>

                        <GroupBox Header="{x:Static p:Strings.SearchWindow_SearchOptions}" Padding="4">
                            <StackPanel Orientation="Vertical">
                                <CheckBox Margin="{StaticResource DialogItemsVMargin}" Content="{x:Static p:Strings.SearchWindow_CaseSensitive}" 
                                          IsChecked="{Binding CaseSensitive, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
                                <CheckBox Margin="{StaticResource DialogItemsVMargin}" Content="{x:Static p:Strings.SearchWindow_OnlyFullWords}" 
                                          IsChecked="{Binding WholeWordsOnly, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
                                <CheckBox Content="{x:Static p:Strings.SearchWindow_SearchBackwards}" 
                                          IsChecked="{Binding SearchBackwards, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
                            </StackPanel>
                        </GroupBox>
                        <GroupBox Header="{x:Static p:Strings.SearchWindow_SearchMode}" Padding="4">
                            <StackPanel Orientation="Vertical">
                                <RadioButton Margin="{StaticResource DialogItemsVMargin}" Content="{x:Static p:Strings.SearchWindow_SearchModeNormal}" 
                                             IsChecked="{Binding SearchMode, Converter={StaticResource RadioToEnumConverter}, ConverterParameter={x:Static t:SearchMode.Normal}}"/>
                                <RadioButton Margin="{StaticResource DialogItemsVMargin}" Content="{x:Static p:Strings.SearchWindow_SearchModeExtended}" 
                                             IsChecked="{Binding SearchMode, Converter={StaticResource RadioToEnumConverter}, ConverterParameter={x:Static t:SearchMode.Extended}}"/>
                                <RadioButton Content="{x:Static p:Strings.SearchWindow_SearchModeRegex}" 
                                             IsChecked="{Binding SearchMode, Converter={StaticResource RadioToEnumConverter}, ConverterParameter={x:Static t:SearchMode.RegularExpressions}}"/>
                            </StackPanel>
                        </GroupBox>
                    </StackPanel>
                    <StackPanel Orientation="Vertical" Margin="10,0,0,0">
                        <Button Content="{x:Static p:Strings.SearchWindow_FindNext}" Width="150" Margin="{StaticResource DialogItemsVMargin}" Command="{Binding FindNextCommand}" />
                        <Button Content="{x:Static p:Strings.SearchWindow_Close}" Width="150" Command="{Binding CloseCommand}" />
                    </StackPanel>
                </StackPanel>
            </GroupBox>
        </TabItem>

        <TabItem x:Name="tReplace" Header="{x:Static p:Strings.SearchWindow_ReplaceTab}">
            <GroupBox Header="{x:Static p:Strings.SearchWindow_ReplaceTab}" Padding="4">
                <StackPanel Orientation="Horizontal">
                    <StackPanel Orientation="Vertical">
                        <Grid>
                            <Grid.RowDefinitions>
                                <RowDefinition Height="Auto" />
                                <RowDefinition Height="Auto" />
                            </Grid.RowDefinitions>
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="100" />
                                <ColumnDefinition Width="250" />
                            </Grid.ColumnDefinitions>

                            <Label Margin="{StaticResource DialogItemsVMargin}" Grid.Row="0" Grid.Column="0" Content="{x:Static p:Strings.SearchWindow_SearchedText}"/>
                            <TextBox x:Name="tbReplaceSearch" Margin="{StaticResource DialogItemsVMargin}" Grid.Row="0" Grid.Column="1" HorizontalAlignment="Stretch" 
                                     Text="{Binding Search, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />

                            <Label Grid.Row="1" Grid.Column="0" Content="{x:Static p:Strings.SearchWindow_ReplaceWith}" />
                            <TextBox Grid.Row="1" Grid.Column="1" HorizontalAlignment="Stretch" 
                                     Text="{Binding Replace, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
                        </Grid>

                        <GroupBox Header="{x:Static p:Strings.SearchWindow_SearchOptions}" Padding="4">
                            <StackPanel Orientation="Vertical">
                                <CheckBox Margin="{StaticResource DialogItemsVMargin}" Content="{x:Static p:Strings.SearchWindow_CaseSensitive}" 
                                          IsChecked="{Binding CaseSensitive, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
                                <CheckBox Margin="{StaticResource DialogItemsVMargin}" Content="{x:Static p:Strings.SearchWindow_OnlyFullWords}" 
                                          IsChecked="{Binding WholeWordsOnly, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
                                <CheckBox Content="{x:Static p:Strings.SearchWindow_SearchBackwards}" 
                                          IsChecked="{Binding SearchBackwards, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
                            </StackPanel>
                        </GroupBox>
                        <GroupBox Header="{x:Static p:Strings.SearchWindow_SearchMode}" Padding="4">
                            <StackPanel Orientation="Vertical">
                                <RadioButton Margin="{StaticResource DialogItemsVMargin}" Content="{x:Static p:Strings.SearchWindow_SearchModeNormal}" 
                                             IsChecked="{Binding SearchMode, Converter={StaticResource RadioToEnumConverter}, ConverterParameter={x:Static t:SearchMode.Normal}}"/>
                                <RadioButton Margin="{StaticResource DialogItemsVMargin}" Content="{x:Static p:Strings.SearchWindow_SearchModeExtended}" 
                                             IsChecked="{Binding SearchMode, Converter={StaticResource RadioToEnumConverter}, ConverterParameter={x:Static t:SearchMode.Extended}}"/>
                                <RadioButton Content="{x:Static p:Strings.SearchWindow_SearchModeRegex}" 
                                             IsChecked="{Binding SearchMode, Converter={StaticResource RadioToEnumConverter}, ConverterParameter={x:Static t:SearchMode.RegularExpressions}}"/>
                            </StackPanel>
                        </GroupBox>
                    </StackPanel>
                    <StackPanel Orientation="Vertical" Margin="10,0,0,0">
                        <Button Content="{x:Static p:Strings.SearchWindow_FindNext}" Width="150" Margin="{StaticResource DialogItemsVMargin}" Command="{Binding FindNextCommand}" />
                        <Button Content="{x:Static p:Strings.SearchWindow_Replace}" Width="150" Margin="{StaticResource DialogItemsVMargin}" Command="{Binding ReplaceCommand}"/>
                        <Separator Margin="{StaticResource DialogItemsVMargin}" />
                        <Button Content="{x:Static p:Strings.SearchWindow_ReplaceAll}" Width="150" Margin="{StaticResource DialogItemsVMargin}" Command="{Binding ReplaceAllCommand}"/>
                        <CheckBox Content="{x:Static p:Strings.SearchWindow_InSelection}" Margin="{StaticResource DialogItemsVMargin}" 
                                  IsEnabled="{Binding SelectionAvailable}" IsChecked="{Binding ReplaceAllInSelection, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
                        <Separator Margin="{StaticResource DialogItemsVMargin}" />
                        <Button Content="{x:Static p:Strings.SearchWindow_Close}" Width="150" Command="{Binding CloseCommand}"></Button>
                    </StackPanel>
                </StackPanel>
            </GroupBox>
        </TabItem>
    </TabControl>
</Window>

What should I do to properly set focus to specific element upon calling those methods?

Upvotes: 1

Views: 861

Answers (1)

Presi
Presi

Reputation: 827

You can try something like this:

Dispatcher.BeginInvoke(
    DispatcherPriority.ContextIdle,
    new Action(delegate()
    {
        tbSearchSearch.Focus();
    }));

From this link: Alternative to set focus from within the Enter event

Upvotes: 3

Related Questions