虚拟键盘打开时,以编程方式将控件滚动到视图中



我有一个带有一组垂直文本框的页面。如果其中一个聚焦,则即使显示屏幕键盘,它们也应该可见。它们的数量足够多,以至于它们都适合键盘上方的可用空间。当底部文本框聚焦时,页面会自动向上滚动,以便所有文本框都可见,但如果顶部文本框聚焦,屏幕键盘将覆盖底部文本框。

这是我页面的简化示例:

<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 个项目的列表:

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()
};
}

我已经尝试了几种方法,但没有成功:

  1. TextBox.GotFocus事件中,以编程方式将焦点更改为底部文本框并返回。
  2. TextBox.GotFocus事件和InputPane.Showing事件中尝试设置ScrollViewer的垂直偏移量:(a) 我包含在Grid周围页面中的那个 (b) Windows 用于自动显示焦点控件的Page上方的可视化树中的那个。在这两种情况下,ScrollViewer都不会对ScrollToVerticalOffset调用做出反应。

我还查看了此问题中建议的示例,但它对屏幕键盘的反应不同,而不是通过滚动页面。

多亏了Cyprient的回答,我终于设法让它工作了。我从我的问题中追求选项 2.a。

需要添加UpdateLayout()调用,但是当我将其放入GotFocus事件处理程序中时,它仅在虚拟键盘已打开后才起作用。为了使它在键盘仍然打开时第一次工作,我必须进行两项更改:

  1. 我不得不将代码放在InputPaneShowing事件中。
  2. 我必须将其放在调度程序的回调中,以便仅在Showing事件处理程序返回后才调用它。

这是最终代码:

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的引用的帮助程序函数,因为否则不会显示焦点控件:

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;
}

有时,当您使用 ScrollToVerticalOffset 时,ScrollViewer 不会自行刷新。 解决方法包括调用滚动查看器。UpdateLayout() 在滚动后。它在几种情况下对我有用。

最新更新