虚拟键盘打开时以编程方式将控件滚动到视图中 [英] Programmatically scroll controls into view when virtual keyboard opens

查看:21
本文介绍了虚拟键盘打开时以编程方式将控件滚动到视图中的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个带有一组垂直文本框的页面.如果其中一个被聚焦,则所有这些都应该可见,即使显示屏幕键盘也是如此.它们的数量足以让它们全部放入键盘上方的可用空间中.当底部文本框获得焦点时,页面会自动向上滚动,以便所有这些都可见,但如果顶部文本框获得焦点,屏幕键盘会覆盖底部.

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:

  1. TextBox.GotFocus 事件中以编程方式将焦点更改为底部文本框并返回.
  2. TextBox.GotFocus 事件和 InputPane.Showing 事件中尝试设置 ScrollViewer 的垂直偏移:(a) 我包含的那个在 Grid 周围的页面中 (b) 在 Page 上方的可视树中,Windows 使用该页面自动将焦点控件显示在视图中.在这两种情况下,ScrollViewer 都不会对 ScrollToVerticalOffset 调用做出反应.
  1. In TextBox.GotFocus event programmatically changed focus to the bottom textbox and back.
  2. In 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.

我还查看了 示例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:

  1. 我必须将代码放在 InputPaneShowing 事件中.
  2. 我必须将它放在调度程序的回调中,以便仅在 Showing 事件处理程序已经返回后调用它.
  1. I had to put the code in the Showing event of InputPane.
  2. 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆