Mikael Koskinen
Mikael Koskinen

Reputation: 12906

WinRT XAML and programmatically setting focus to TextBox - Why Focus doesn't stick?

My Windows 8 XAML page contains two controls: Image and TextBox. When the user doubletaps Image, I want to move the focus to TextBox so that the virtual keyboard is automatically displayed.

The problem: The TextBox control correctly receives the focus, but only for 0.1 seconds. The focus then moves to somewhere else and no keyboard is displayed.

Through the events I can see that GotFocus and and LostFocus events are raised for the TextBox. The Image control doesn't have other event handlers as it only handles the DoubleTapped event:

    private void CurrentPage_OnDoubleTapped(object sender, DoubleTappedRoutedEventArgs e)
    {
        e.Handled = true;
        this.PageNumberTextBox.Focus(FocusState.Keyboard);
    }

Why doesn't the focus "stick"? Where and why the focus goes?

Update:

With this very helpful helper I can see that the focus moves to ScrollViewer [Windows.UI.Xaml.Controls.Border]. I presume this is something which is built-in (maybe used by the RootFrame?) as I don't have any ScrollViewers added to the page and because this control seems to fill the whole screen.

So, the problem seems to be caused by event bubbling: Image-control is first to receive the event and then the control behind it. But why? Shouldn't e.Handled = true prevent this behavior?

Modifying the code to look like this doesn't help:

    private void CurrentPage_OnDoubleTapped(object sender, DoubleTappedRoutedEventArgs e)
    {
        e.Handled = true;
        //this.PageNumberTextBox.Focus(FocusState.Keyboard);
    }

After the doubletap, the mystery ScrollViewer has the focus.

Update 2:

The problem might be related to Image-control. I created the following spike:

<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
    <Grid.RowDefinitions>
        <RowDefinition/>
        <RowDefinition/>
    </Grid.RowDefinitions>

    <Image Grid.Row="0" DoubleTapped="UIElement_OnDoubleTapped" Tapped="UIElement_OnTapped"
           Source="http://upload.wikimedia.org/wikipedia/commons/1/1c/Squirrel_posing.jpg" Stretch="Fill"/>
    <TextBox x:Name="MyBox" Grid.Row="1"/>
</Grid>

The spike app is created using the Blank template. In code behind I set the e.Handled = true for both Tapped and DoubleTapped:

    private void UIElement_OnDoubleTapped(object sender, DoubleTappedRoutedEventArgs e)
    {
        e.Handled = true;
    }

    private void UIElement_OnTapped(object sender, TappedRoutedEventArgs e)
    {
        e.Handled = true;
    }

The problem: When I tap the Image, the focus is always given to this mystery ScrollViewer. Here's some screenshots:

  1. When I click the TextBox which takes the bottom half of the view, the focus correctly moves to the TextBox (the control with focus is highlighted and the control's name is displayed in top left):

Focus textbox

  1. When I click the Image at the top, the Image doesn't receive the focus. Instead, it's given to the mystery ScrollViewer, which seems to fill the whole screen:

Focus image

So even though I've set the Image to handle both Tapped and DoubleTapped, the Image control doesn't receive the focus.

Upvotes: 4

Views: 2848

Answers (1)

Peter Ritchie
Peter Ritchie

Reputation: 35881

I think your problem is the double-tap is within a series of events that end up changing the focus. What you could try is to "queue" a focus change by asynchronously calling the Focus method. For example:

Task.Factory.StartNew(
    () => Dispatcher.RunAsync(CoreDispatcherPriority.Low,
        () => PageNumberTextBox.Focus(FocusState.Keyboard)));

I know it looks a little stupid but what this does is to try to put the code that changes the focus after all the other events in the queue.

Upvotes: 3

Related Questions