Reputation: 17865
I have a page with a vertical set of textboxes. If one of them is focused, all of them should be visible, even if the onscreen keyboard is displayed. There are just enough of them that all of them fit in the available space above the keyboard. When the bottom textbox is focused, the page gets automatically scrolled up so that all of them are visible, but if the top textbox is focused, the onscreen keyboard covers the bottom one.
This is a simplified example of my page:
<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
<ItemsControl ItemsSource="{Binding List}" Margin="120 140 0 0">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" Margin="0 10 0 0">
<TextBox Text="{Binding Text, Mode=TwoWay}" />
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
DataContext
contains a list of 10 items:
public class Item
{
public string Text { get; set; }
}
public class ViewModel
{
public List<Item> List { get; set; }
}
public MainPage()
{
this.InitializeComponent();
DataContext = new ViewModel
{
List = Enumerable.Range(0, 10).Select(i => new Item { Text = i.ToString() }).ToList()
};
}
I've already tried a couple of approaches, all without success:
TextBox.GotFocus
event programmatically changed focus to the bottom textbox and back.TextBox.GotFocus
event and InputPane.Showing
event tried setting the vertical offset of a ScrollViewer
: (a) the one I included in the page around the Grid
(b) the one in the visual tree above the Page
that Windows uses to automatically bring the focused control in view. In both cases the ScrollViewer
doesn't react to ScrollToVerticalOffset
calls.I've also looked at the sample suggested in this question but it reacts to onscreen keyboard differently, not by scrolling the page.
Upvotes: 3
Views: 6630
Reputation: 17865
Thanks to Cyprient's answer I finally managed to get this to work. I pursued option 2.a from my question.
Adding UpdateLayout()
call was required, but when I put it in the GotFocus
event handler it only worked after the virtual keyboard was already opened. To make it work the first time when the keyboard was still opening, I had to make two changes:
Showing
event of InputPane
.Showing
event handler had already returned.Here's the final code:
public MainPage()
{
this.InitializeComponent();
DataContext = new ViewModel
{
List = Enumerable.Range(0, 10).Select(i => new Item { Text = i.ToString() }).ToList()
};
var inputPane = InputPane.GetForCurrentView();
inputPane.Showing += InputPane_Showing;
}
private async void InputPane_Showing(InputPane sender, InputPaneVisibilityEventArgs args)
{
await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
var parentScrollViewer = FindParent<ScrollViewer>(this.pageRoot);
parentScrollViewer.VerticalScrollMode = ScrollMode.Enabled;
parentScrollViewer.ScrollToVerticalOffset(65);
parentScrollViewer.UpdateLayout();
});
}
Here's the helper function I'm using to get the reference to the same ScrollViewer
which is used when the page contents gets scrolled automatically because the focused control would not be shown otherwise:
public static T FindParent<T>(FrameworkElement reference)
where T : FrameworkElement
{
FrameworkElement parent = reference;
while (parent != null)
{
parent = parent.Parent as FrameworkElement;
var rc = parent as T;
if (rc != null)
{
return rc;
}
}
return null;
}
Upvotes: 8
Reputation: 1998
Sometimes the ScrollViewer does not refresh itself when you are using ScrollToVerticalOffset. The workaround consists in calling scrollviewer.UpdateLayout() after scrolling. It worked for me in several cases.
Upvotes: 3