UWP ScrollViewer 意外行为
UWP ScrollViewer unexpected behavior
在为 UWP 平台开发应用程序时,我遇到了一个意外行为案例。当我在一页上显示太多内容时,我利用了 ScrollViewer 控件,它应该可以解决这个问题。
该控件允许滚动内容,但它处理输入的方式不自然。当控件被 Clicked 时,ScrollViewer 中没有可聚焦的控件被单击,Focus传递给其内容中的第一个可聚焦控件。这实际上意味着 ScrollViewer 滚动回顶部,这不是我不希望的行为。
我希望 ScrollViewer 保持当前位置,就像网页一样。如果单击空白位置,网页不会滚动回第一个可聚焦控件。另一个类似的例子是 Grid 或 Stackpanel 在单击时不会将焦点传递给其中一个子项。
下面是演示上述行为的一些 xaml 代码,只需创建一个新的 UWP 项目 并将其放在生成的 [ 的网格中=50=]:
<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 很烦人,这就是为什么我会 post 一个以更好的方式实现我的解决方案的答案.
问题仍然存在:有没有更好的方法来解决这个问题?
我的解决方案通过创建处理 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();
}
}
}
用法:
首先将以下行添加到主页的 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
在为 UWP 平台开发应用程序时,我遇到了一个意外行为案例。当我在一页上显示太多内容时,我利用了 ScrollViewer 控件,它应该可以解决这个问题。
该控件允许滚动内容,但它处理输入的方式不自然。当控件被 Clicked 时,ScrollViewer 中没有可聚焦的控件被单击,Focus传递给其内容中的第一个可聚焦控件。这实际上意味着 ScrollViewer 滚动回顶部,这不是我不希望的行为。
我希望 ScrollViewer 保持当前位置,就像网页一样。如果单击空白位置,网页不会滚动回第一个可聚焦控件。另一个类似的例子是 Grid 或 Stackpanel 在单击时不会将焦点传递给其中一个子项。
下面是演示上述行为的一些 xaml 代码,只需创建一个新的 UWP 项目 并将其放在生成的 [ 的网格中=50=]:
<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 很烦人,这就是为什么我会 post 一个以更好的方式实现我的解决方案的答案.
问题仍然存在:有没有更好的方法来解决这个问题?
我的解决方案通过创建处理 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();
}
}
}
用法:
首先将以下行添加到主页的 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