I'm creating an XML Form Reader. Each of the control types are User Controls. However when the user taps somewhere on the form that isn't a focused control (i.e. TextBlock), the form jumps focus to the first focusable control in the page. (i.e. TextBox)
This scrolls the page to the top (usually), taking the user away from what they were just working on.
I have tried a lot of different things around the focus events but have hit a wall on how to solve this.
What would be the best way to handle this ? Any hints or tips would be greatly appreciated.
Thanks
EDIT (more info)
The "MASTER" page has a StackPanel
<StackPanel x:Name="pnlFormMain" ScrollViewer.BringIntoViewOnFocusChange="False"/>
For each control in the xml form, a UserControl is added to the stackpanel.
<UserControl.Resources>
<Storyboard x:Name="Show">
<DoubleAnimation Duration="0:0:0.6" To="1" Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="_WidgetMaster" d:IsOptimized="True"/>
</Storyboard>
<Storyboard x:Name="Hide">
<DoubleAnimation Duration="0" To="0" Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="_WidgetMaster" d:IsOptimized="True"/>
</Storyboard>
</UserControl.Resources>
<Grid x:Name="grdInput" ScrollViewer.BringIntoViewOnFocusChange="False">
<Grid.RowDefinitions>
<RowDefinition Height="auto" />
<RowDefinition Height="auto" />
<RowDefinition Height="auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid Grid.Column="0" Grid.Row="0" ScrollViewer.BringIntoViewOnFocusChange="False">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto" />
<ColumnDefinition Width="auto" />
</Grid.ColumnDefinitions>
<!-- label -->
<TextBlock x:Name="lblLabel" Text="Label" Grid.Column="0" VerticalAlignment="Center" Margin="3,6,5,5" TextWrapping="Wrap" />
<!-- HINT -->
<Ellipse x:Name="ellHint" Height="25" Width="25" Grid.Column="1" StrokeThickness="2" Stroke="LightBlue" Margin="5,0,5,0" Tapped="Hint_Tapped" VerticalAlignment="Center">
<Ellipse.Fill>
<ImageBrush ImageSource="ms-appx:///XForms/Assets/information.png" />
</Ellipse.Fill>
</Ellipse>
</Grid>
<Frame x:Name="control" Grid.Column="1" Grid.Row="0" />
<TextBlock x:Name="lblConstraintMessage" Grid.Row="2" Grid.ColumnSpan="99" FontSize="10" VerticalAlignment="Center"
HorizontalAlignment="Right" Margin="0,0,5,0" Visibility="Collapsed" />
</Grid>
The same UserControl
is used for almost all controls. And the input for that control is a second UserControl
that goes into the Frame
near the bottom.
(e.g.)
<Grid x:Name="grdInput">
<TextBox x:Name="txtInput" Text="" Grid.Row="0" Grid.Column="1" Margin="15,0,0,0" LostFocus="txtInput_LostFocus" KeyDown="txtInput_KeyDown" TextAlignment="Right" />
<Border x:Name="brdrValuePlaceholder" Background="Transparent" BorderThickness="0,0,0,1" BorderBrush="{ThemeResource TextControlBorderBrush}" HorizontalAlignment="Stretch"
Height="{ThemeResource TextControlThemeMinHeight}" Visibility="Collapsed">
<TextBlock x:Name="lblInput" Text="" Grid.Row="0" Grid.Column="1" Margin="0,0,5,0" Tapped="lblInput_Tapped" TextAlignment="Right" HorizontalAlignment="Stretch"/>
</Border>
</Grid>
The LostFocus
event there just sets a value in the database
Other controls on the master page is a Popup
and a ProgressRing
Along with a header bar.
EDIT 2
I have tried to do what I can with making the StackPanel
unfocusable, and storing the previously focused control, but can get them to work as hoped.
I have put the source up on GitHub, I am new to GitHub, so if I need to do anything more, please let me know. The code is a bit older, but has the same problem. There is also a Android and iOS application in the solution, but only the UWP project has the issue.
The bounty is still alive, and will be awarded if anyone can help. Thanks
Maybe it is focusing on the stackpanel itself?
Have dialog box popup or a textstring in the page itself to show what is always focused. That way you can see if the stacklayout is becoming focused.
Another possibility is that if you tap off, it is returning focus to the first element on the stacklayout (what it saw as tapped).
It's not trivial to recreate your exact scenario. However, there should be several possible solutions to your problem.
The first thing that comes to my mind is to intercept the Preview*keyboard/mouse events within your form.
Handled=true
to prevent the KeyDown or MouseDown event from being processed further if a non-user control is clicked. A markup extension could be helpful too.Another approach could be to mark all no-user input UI elements as Focusable=false
in the XAML, e.g.
<XY Focusable="False">
...
</XY>
or disable
them all together.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With