[WPF] Soft Keyboard Shows, Then Hides, in Popup Window

garry 96 Reputation points
2020-06-25T21:01:46.047+00:00

My WPF application is targeting .NET Core 3.1. It runs on Win10 laptops and Surface Pro tablets (in tablet mode). The tablet is running Win10 Update 1909.

The app has a popup window for the user to enter a Username and Password. When the user taps on the Username field, the soft keyboard pops up, then immediately closes. But the field now has focus (can see the cursor in it). Tapping on the field again causes the keyboard to be shown and stay visible. The same thing happens when the user then taps on the Password field. The same bad behavior happens on all my Popup windows with TextBoxes.

It seems that only TextBoxes on Popup windows have the issue. The soft keyboard appears to work OK with TextBoxes in my main window. Sadly, my application has several Popup windows that prompt the user for text input and this issue is extremely user-hostile.

Any/all help would be appreciated...

Windows Presentation Foundation
Windows Presentation Foundation
A part of the .NET Framework that provides a unified programming model for building line-of-business desktop applications on Windows.
2,688 questions
{count} votes

Accepted answer
  1. garry 96 Reputation points
    2020-06-26T11:24:08.243+00:00

    Thanks for that code. As it turns out, all I apparently need to add to the "show" event handler is:

             var source = (HwndSource)PresentationSource.FromVisual(popup.Child);
             SetFocus(source.Handle);
    

    The Task.Yield() calls had no effect. Plus, I don't necessarily want to force the focus to a TextBox when the window opens.

    But the real question is: why do I need to use a WIN32 function to force focus to popup.Child? What is going on under the hood (or not going on) that this work-around addresses? I'd like to understand why this is needed.

    And is this considered a bug in .NET Core 3.1 that will be addressed in a future update? Seems to me that all the developer should have to do is just set "isOpen" to true and everything "should just work".

    Thanks again for the work-around. Looking forward to your reply as to what is going on under the hood...


1 additional answer

Sort by: Most helpful
  1. garry 96 Reputation points
    2020-06-26T10:26:47.097+00:00

    Here is a bare-bones program that demonstrates the issue, except that the soft keyboard doesn't "show then hide" (like my real app), it just never shows up at all. The main window has the Username and Password fields to demonstrate that the keyboard works with TextBoxes in a main window. Display the same two fields (I copy/pasted the XAML) and the keyboard never shows up at all.

    The XAML:

    <Window x:Class="WpfKeyboardTest.MainWindow"
            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:WpfKeyboardTest"
            mc:Ignorable="d"
            Title="MainWindow" Height="450" Width="800" FontSize="20">
        <Grid HorizontalAlignment="Center" VerticalAlignment="Center">
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="Auto" />
                <RowDefinition Height="Auto" />
            </Grid.RowDefinitions>
    
            <StackPanel Grid.Row="0" Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0,0,0,20">
                <Label  Content="First Name:"  Margin="0,0,10,0"/>
                <TextBox Text="" TextWrapping="Wrap" Width="250" />
            </StackPanel>
    
            <StackPanel Grid.Row="1" Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center">
                <Label Content="Last Name:"  Margin="0,0,10,0"/>
                <TextBox Text="" TextWrapping="Wrap" Width="250" />
            </StackPanel>
    
            <Button Grid.Row="2" Content="Show Popup" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0,20,0,0" Padding="5" Click="onClick" />
    
            <Popup x:Name="TestPop"  Placement="Center" > 
                    <Grid HorizontalAlignment="Center" VerticalAlignment="Center" Background="White" Margin="3">
                        <Grid.RowDefinitions>
                            <RowDefinition Height="Auto"/>
                            <RowDefinition Height="Auto" />
                            <RowDefinition Height="Auto" />
                        </Grid.RowDefinitions>
    
                        <StackPanel Grid.Row="0" Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="10">
                            <Label  Content="First Name:"  Margin="0,0,10,0"/>
                            <TextBox Text="" TextWrapping="Wrap" Width="250" />
                        </StackPanel>
    
                        <StackPanel Grid.Row="1" Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="10">
                            <Label Content="Last Name:"  Margin="0,0,10,0"/>
                            <TextBox Text="" TextWrapping="Wrap" Width="250" />
                        </StackPanel>
    
                        <Button Grid.Row="2" Content="Hide Popup" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="20" Padding="5" Click="onSubmit"/>
    
                    </Grid>
            </Popup>
        </Grid>
    </Window>
    

    And here is the code behind that simply shows/hides the popup window:

    using System.Windows;
    
    namespace WpfKeyboardTest
    {
        /// <summary>
        /// Interaction logic for MainWindow.xaml
        /// </summary>
        public partial class MainWindow : Window
        {
            public MainWindow()
            {
                InitializeComponent();
            }
    
            private void onClick(object sender, RoutedEventArgs e)
            {
                TestPop.IsOpen = true;
            }
    
            private void onSubmit(object sender, RoutedEventArgs e)
            {
                TestPop.IsOpen = false;
            }
        }
    }
    
    0 comments No comments