虚拟键盘打开时以编程方式将控件滚动到视图中 [英] Programmatically scroll controls into view when virtual keyboard opens
问题描述
我有一个带有一组垂直文本框的页面.如果其中一个被聚焦,则所有这些都应该可见,即使显示屏幕键盘也是如此.它们的数量足以让它们全部放入键盘上方的可用空间中.当底部文本框获得焦点时,页面会自动向上滚动,以便所有这些都可见,但如果顶部文本框获得焦点,屏幕键盘会覆盖底部.
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
包含 10 个项目的列表:
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
事件中以编程方式将焦点更改为底部文本框并返回. - 在
TextBox.GotFocus
事件和InputPane.Showing
事件中尝试设置ScrollViewer
的垂直偏移:(a) 我包含的那个在Grid
周围的页面中 (b) 在Page
上方的可视树中,Windows 使用该页面自动将焦点控件显示在视图中.在这两种情况下,ScrollViewer
都不会对ScrollToVerticalOffset
调用做出反应.
- In
TextBox.GotFocus
event programmatically changed focus to the bottom textbox and back. - In
TextBox.GotFocus
event andInputPane.Showing
event tried setting the vertical offset of aScrollViewer
: (a) the one I included in the page around theGrid
(b) the one in the visual tree above thePage
that Windows uses to automatically bring the focused control in view. In both cases theScrollViewer
doesn't react toScrollToVerticalOffset
calls.
我还查看了 示例 在 this question 中建议,但它对屏幕键盘的反应不同,而不是通过滚动页面.
I've also looked at the sample suggested in this question but it reacts to onscreen keyboard differently, not by scrolling the page.
推荐答案
感谢 Cyprient 的回答,我终于设法让它工作了.我从我的问题中选择了选项 2.a.
Thanks to Cyprient's answer I finally managed to get this to work. I pursued option 2.a from my question.
添加 UpdateLayout()
调用是必需的,但是当我将它放在 GotFocus
事件处理程序中时,它仅在虚拟键盘已经打开后才起作用.为了让它在键盘仍然打开时第一次工作,我必须进行两项更改:
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:
- 我必须将代码放在
InputPane
的Showing
事件中. - 我必须将它放在调度程序的回调中,以便仅在
Showing
事件处理程序已经返回后调用它.
- I had to put the code in the
Showing
event ofInputPane
. - I had to put it in a callback for the dispatcher so that it was called only after the
Showing
event handler had already returned.
这是最终代码:
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();
});
}
这是我用来获取对同一 ScrollViewer
的引用的辅助函数,该函数在页面内容自动滚动时使用,因为否则不会显示焦点控件:
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;
}
这篇关于虚拟键盘打开时以编程方式将控件滚动到视图中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!