UWP ScrollViewer意外行为

时间:2018-04-07 23:40:18

标签: c# xaml uwp scrollviewer

在为 UWP 平台开发应用时,我遇到了一个意外行为的情况。当我在一个页面上显示太多内容时,我利用 ScrollViewer 控件,这应该可以解决这个问题。

控件允许滚动内容,但它处理输入的方式不自然。当控件获得单击,以便单击 ScrollViewer 中没有可聚焦控件时,焦点将传递给其内容中的第一个可聚焦控件。这实际上意味着 ScrollViewer 滚动回到顶部,这不是我不期望的行为。

我希望 ScrollViewer 保留当前位置,就像网页一样。如果要点击空白处,网页不会滚动回第一个可聚焦控件。另一个类似的例子是网格 Stackpanel 在点击时不会将焦点传递给其中一个孩子。

下面是一些演示上述行为的xaml代码,只需创建一个新的 UWP项目并将其放置在生成的 MainPage.xaml 的网格中:

<ScrollViewer Height="400"> <!-- Unexpected and unnatrual behavior -->
    <StackPanel Width="250" Background="DarkGray" Padding="10"> <!-- With Content Height > ScrollViewer Height -->
        <TextBlock Text="Unnatural scroll behavior" FontWeight="Bold"/>
        <TextBox Text="Some focusable control"/>
        <TextBlock Height="800" Text="On focus => pass focus to first available => scroll to the top" TextWrapping="Wrap"/>
        <TextBox Text="Some focusable control"/>
    </StackPanel>
</ScrollViewer>

我确实提出了一个解决方案,但这似乎很奇怪,这将是解决当前问题的正确方法:

<ScrollViewer Height="400">
    <!-- Corrected behaviour, but extra ContentControl. Easily forgotten -->
    <ContentControl>
        <StackPanel Width="250" Background="Gray" Padding="10">
            <!-- With Content Height > ScrollViewer Height -->
            <TextBlock Text="Corrected scroll behavior" FontWeight="Bold"/>
            <TextBox Text="Some focusable control"/>
            <TextBlock Height="800" Text="On focus => no scroll" TextWrapping="Wrap"/>
            <TextBox Text="Some focusable control"/>
        </StackPanel>
    </ContentControl>
</ScrollViewer>

这很有效,但总是记得添加 ContentControl 非常烦人,这就是为什么我会以更好的方式发布实现我的解决方案的答案。

问题仍然存在:有没有更好的方法来解决这个问题?

1 个答案:

答案 0 :(得分:0)

通过创建处理 ContentControl 的自定义 UserControl ,以更加开发人员友好的方式实施我的解决方案。

Scroller.xaml:

<UserControl
    x:Class="Controls.Scroller"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    d:DesignHeight="300"
    d:DesignWidth="400">

    <ScrollViewer Name="ScrollerControl" Height="{x:Bind Height, Mode=TwoWay}" Width="{x:Bind Width, Mode=TwoWay}">
        <ContentControl Content="{x:Bind ScrollContent}"/>
    </ScrollViewer>

</UserControl>

Scroller.xaml.cs:

using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Markup;

namespace Controls
{
    [ContentProperty(Name = "ScrollContent")]
    public sealed partial class Scroller : UserControl
    {
        public static readonly DependencyProperty ScrollContentProperty = DependencyProperty.Register("ScrollContent", typeof(object), typeof(object), new PropertyMetadata(new Grid()));

        public ScrollViewer ScrollViewer { get { return ScrollerControl; } }
        public object ScrollContent { get { return GetValue(ScrollContentProperty); } set { SetValue(ScrollContentProperty, value); } }

        public Scroller()
        {
            DataContext = this;
            this.InitializeComponent();
        }
    }
}

用法:

首先将以下行添加到Page的xaml:

xmlns:cont="using:Controls"

然后按以下方式使用控件:

<cont:Scroller Height="400" x:Name="ScrollControl">
    <!-- Place any content in here -->
    <!-- The content below is just for example -->
    <StackPanel Width="250" Background="DarkGray" Padding="10">
        <TextBlock Text="Corrected scroll behaviour" FontWeight="Bold"/>
        <TextBox Text="Some focusable control"/>
        <TextBlock Height="800" Text="On focus => no scroll" TextWrapping="Wrap"/>
        <TextBox Text="Some focusable control"/>
    </StackPanel>
</cont:Scroller>

请注意,x:Name必须用于引用代码中的控件。此外,如果您想访问 ScrollViewer ,请使用

ScrollControl.ScrollViewer