Reputation: 271
I have a Popup with a Textbox and a Button control in it. When I click/tap anywhere inside the Popup, the Textbox doesn't lose focus. The only way to make the Textbox lose focus is to set focus on the Button. I want to be able to remove focus from the Textbox without having to close the Popup or clicking the button. This issue only occurs in a Popup. I used to have the controls in a Flyout, and the behavior there is when a user clicks outside the Textbox and anywhere inside the Flyout, the Textbox loses focus. Also when the Flyout opens, the Textbox would automatically get focus on Flyout opening.
I tested the different behaviors for how Textboxes losing focus in a new blank UWP project, and it's the same. Also tested behavior of Textbox directly in root-grid. This is the XAML from MainPage:
<Page x:Class="App1.MainPage"
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:local="using:App1"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<StackPanel Margin="0,40"
HorizontalAlignment="Center"
VerticalAlignment="Top"
Orientation="Horizontal">
<Button Margin="20,0"
Content="Popup button"
Tapped="Button_Tapped" />
<Button Margin="20,0" Content="Flyout button">
<Button.Flyout>
<Flyout>
<Grid Width="200">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBox VerticalAlignment="Center" />
<Button Grid.Column="1" Content="Test" />
</Grid>
</Flyout>
</Button.Flyout>
</Button>
</StackPanel>
<Popup x:Name="MyPopup"
Width="320"
Height="60"
IsLightDismissEnabled="True">
<Grid Width="320"
Height="60"
Background="WhiteSmoke"
Padding="12,0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBox VerticalAlignment="Center" />
<Button Grid.Column="1" Content="Test" />
</Grid>
</Popup>
<TextBox Grid.Row="1"
MinWidth="64"
MaxWidth="300"
Margin="0,40"
VerticalAlignment="Center" />
</Grid>
</Page>
And the event to open the Popup:
private void Button_Tapped(object sender, TappedRoutedEventArgs e)
{
MyPopup.IsOpen = true;
}
Upvotes: 1
Views: 1283
Reputation: 3324
The problem is that Grid
is not "focusable" because it does not derive from Control
. One way is that you place your Grid
inside a ContentControl
or ContentPresenter
.
The other way is a bit of a hack but you can set the focus programatically on the button when the Grid
inside the Popup
is tapped:
<Popup
x:Name="MyPopup"
Width="320"
Height="60"
IsLightDismissEnabled="True">
<Grid
x:Name="Grid"
Width="320"
Height="60"
Background="WhiteSmoke"
Tapped="Grid_OnTapped"
Padding="12,0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBox VerticalAlignment="Center" />
<Button
Grid.Column="1"
Content="Test" />
</Grid>
</Popup>
And the Tapped
handler in which you generally search for any focusable control that is not a TextBox
. If you don't have any you can place an invisible ContentControl
with Opacity=0.01
for example and this will then be the focus element:
private void Grid_OnTapped(object sender, TappedRoutedEventArgs e)
{
var grid = sender as Grid;
if(grid == null) return;
var controlToFocus = FindChild<Button>(grid);
controlToFocus.Focus(FocusState.Programmatic);
}
private static T FindChild<T>(DependencyObject parent) where T : DependencyObject
{
var childCount = VisualTreeHelper.GetChildrenCount(parent);
for (var i = 0; i < childCount; i++)
{
var elt = VisualTreeHelper.GetChild(parent, i);
if (elt is T) return (T)elt;
var result = FindChild<T>(elt);
if (result != null) return result;
}
return null;
}
Upvotes: 1