e.IsInertial 几乎总是错误的 WPF
e.IsInertial almost always false WPF
我的 WPF 应用程序有以下 XAML,我正在从 UWP 转换它:
<ScrollViewer Name="scv_main" Grid.Row="2" ScrollViewer.VerticalScrollBarVisibility="Auto"
PanningMode="VerticalFirst">
<TextBlock Name="txbl_display" Grid.Row="2" Foreground="White"
FontFamily="Lucida Console" FontSize="22" Text="{Binding Path=ContentPath, Mode=OneWay,
UpdateSourceTrigger=PropertyChanged}" Padding="20" TextWrapping="Wrap"
IsManipulationEnabled="True" ManipulationDelta="manipulationDeltaHandler"/>
</ScrollViewer>
我发现,事件处理程序的 e.IsInertial
始终为假。
我以为可能是 ScrollViewer 处理惯性事件,但是当我删除 ScrollViewer 时,我仍然无法让任何惯性事件通过。我也试过将 ManipulationDelta 放在 ScrollViewer 上,结果相同。
我的最终目标是希望 ScrollViewer 在非惯性移动时滚动,但让我控制在惯性滑动时发生的情况。
我在移植到 WPF 的 UWP 应用程序中管理了这个效果,如下所示:
<TextBlock ... ManipulationMode="All" ManipulationDelta="TextBlock_ManipulationDelta/>"
然后在代码隐藏中:
if (e.IsInertial) // inertial = swipe, rather than slide
{
// X-Translation - change contents of textblock
if (e.Cumulative.Translation.X <= -500) //500 is the threshold value, where you want to trigger the swipe right event
{
showNext();
e.Complete();
}
else if (e.Cumulative.Translation.X >= 500)
{
showPrevious();
e.Complete();
}
// Y translation - move the scrollbar
else if (e.Cumulative.Translation.Y <= -500)
{
scv_main.ChangeView(null, scv_main.VerticalOffset + (-1 * e.Cumulative.Translation.Y), null);
e.Complete();
}
else if (e.Cumulative.Translation.Y >= 500)
{
scv_main.ChangeView(null, Math.Min(scv_main.VerticalOffset + (-1 * e.Cumulative.Translation.Y), 0), null);
e.Complete();
}
}
else // slide,rather than swipe - scroll as the finger moves
{
if (e.Delta.Translation.Y != 0)
{
scv_main.ChangeView(null, scv_main.VerticalOffset + (-1 * e.Delta.Translation.Y), null);
}
}
但我不能在 WPF 中重复这种行为。有什么想法吗?
---更新---
后来我发现,通过从右上角向左下角划一个大弧线,在屏幕全屏的情况下,我几乎可以触发一个 e.IsInertial = True
事件。发生这种情况时,ManipulationDelta
事件会被触发两次 - 第一次是 e.IsInertial = false
,第二次是 e.IsInertial = true
。我不确定为什么会这样;无论如何,这不是我要找的行为。
还有人有更多想法吗?我尝试过各种方法,包括将面板放在所有内容之上并将操作处理程序放在上面;但我仍然遇到同样的问题。
我正在使用 Visual Studio 2017 和 Windows 10。我正在编码和测试的设备是 Microsoft Surface Book
似乎正在发生的是,非惯性运动先发生;然后一旦完成,惯性就会发射。我在事件中放置了一些输出,然后在滑动时得到了以下信息:
ManipulationStarting Fired
ManipulationDelta e.IsInertial = False. X,Y:-5.14288330078125,-1.14288330078125
ManipulationDelta e.IsInertial = False. X,Y:-16.5714111328125,0
ManipulationDelta e.IsInertial = False. X,Y:-16.5714111328125,0
ManipulationDelta e.IsInertial = False. X,Y:-89.1428833007813,1.14288330078125
ManipulationDelta e.IsInertial = False. X,Y:-224,2.28570556640625
ManipulationDelta e.IsInertial = False. X,Y:-224,2.28570556640625
ManipulationDelta e.IsInertial = False. X,Y:-384.571441650391,4
ManipulationDelta e.IsInertial = False. X,Y:-622.285705566406,4
ManipulationDelta e.IsInertial = False. X,Y:-622.285705566406,4
ManipulationDelta e.IsInertial = False. X,Y:-622.285705566406,4
ManipulationDelta e.IsInertial = False. X,Y:-732.571411132813,6.28570556640625
ManipulationDelta e.IsInertial = False. X,Y:-732.571411132813,6.28570556640625
ManipulationDelta e.IsInertial = False. X,Y:-732.571411132813,6.28570556640625
ManipulationDelta e.IsInertial = False. X,Y:-732.571411132813,6.28570556640625
ManipulationInertiaStarting Fired
在那之后,我没有再触发任何增量。那么消耗它们的是什么?为什么我先得到非惯性的?
我发现实现这种工作的一种方法是将 PanningMode="VerticalFirst"
更改为 PanningMode="None"
。然后自己处理滚动(这似乎是 UWP 版本正在做的事情)......但我仍然必须摆脱 "e.IsInertial" 检查。所以在我的事件处理程序获取它们之前,某些东西导致惯性增量被消耗
为确保操作流程按预期工作,您需要处理更多操作事件并做出相应反应。这是来自 MS (Input overview - Touch and manipulations) 的概述,但一般来说,您通常希望:
- 处理 ManipulationStarting 并为您的操作设置适当的操作容器。
- handle ManipulationStarted 如果您想存储一些数据,例如您自己计算的操作来源。
- 在用户按下手指时处理 Delta
- handle InertiaStarting - 在这里你应该设置减速度值。
- 在用户抬起手指时处理 Delta(惯性)- 根据我的经验,只有在指定惯性值时才会收到这些事件。
- 如果您需要知道输入过程何时何地完成,请处理 ManipulationCompleted。
来自您的 post 我不确定您是否知道这一点,但 InertiaStarting 只会在 用户抬起手指 (s) 时发生。然后 - 如果您 在正确处理 InertiaStarting 时设置值 - 您将获得更多的 ManipulationDeltas 传入(带有惯性标志)。
After that, I don't get any more deltas firing. So what's consuming them; and why am I getting non-inertial ones first?
您已经通过调用 complete 完成了操作过程,因为下面的 if 检查已经完成!所以 'engine' 已经跳过了它本来会触发的所有其他事件并完成了操作过程:
if (e.Cumulative.Translation.X <= -500)
{
showNext();
e.Complete();
}
操作完成后,您当然不会再收到任何事件。
我的 WPF 应用程序有以下 XAML,我正在从 UWP 转换它:
<ScrollViewer Name="scv_main" Grid.Row="2" ScrollViewer.VerticalScrollBarVisibility="Auto"
PanningMode="VerticalFirst">
<TextBlock Name="txbl_display" Grid.Row="2" Foreground="White"
FontFamily="Lucida Console" FontSize="22" Text="{Binding Path=ContentPath, Mode=OneWay,
UpdateSourceTrigger=PropertyChanged}" Padding="20" TextWrapping="Wrap"
IsManipulationEnabled="True" ManipulationDelta="manipulationDeltaHandler"/>
</ScrollViewer>
我发现,事件处理程序的 e.IsInertial
始终为假。
我以为可能是 ScrollViewer 处理惯性事件,但是当我删除 ScrollViewer 时,我仍然无法让任何惯性事件通过。我也试过将 ManipulationDelta 放在 ScrollViewer 上,结果相同。
我的最终目标是希望 ScrollViewer 在非惯性移动时滚动,但让我控制在惯性滑动时发生的情况。
我在移植到 WPF 的 UWP 应用程序中管理了这个效果,如下所示:
<TextBlock ... ManipulationMode="All" ManipulationDelta="TextBlock_ManipulationDelta/>"
然后在代码隐藏中:
if (e.IsInertial) // inertial = swipe, rather than slide
{
// X-Translation - change contents of textblock
if (e.Cumulative.Translation.X <= -500) //500 is the threshold value, where you want to trigger the swipe right event
{
showNext();
e.Complete();
}
else if (e.Cumulative.Translation.X >= 500)
{
showPrevious();
e.Complete();
}
// Y translation - move the scrollbar
else if (e.Cumulative.Translation.Y <= -500)
{
scv_main.ChangeView(null, scv_main.VerticalOffset + (-1 * e.Cumulative.Translation.Y), null);
e.Complete();
}
else if (e.Cumulative.Translation.Y >= 500)
{
scv_main.ChangeView(null, Math.Min(scv_main.VerticalOffset + (-1 * e.Cumulative.Translation.Y), 0), null);
e.Complete();
}
}
else // slide,rather than swipe - scroll as the finger moves
{
if (e.Delta.Translation.Y != 0)
{
scv_main.ChangeView(null, scv_main.VerticalOffset + (-1 * e.Delta.Translation.Y), null);
}
}
但我不能在 WPF 中重复这种行为。有什么想法吗?
---更新---
后来我发现,通过从右上角向左下角划一个大弧线,在屏幕全屏的情况下,我几乎可以触发一个 e.IsInertial = True
事件。发生这种情况时,ManipulationDelta
事件会被触发两次 - 第一次是 e.IsInertial = false
,第二次是 e.IsInertial = true
。我不确定为什么会这样;无论如何,这不是我要找的行为。
还有人有更多想法吗?我尝试过各种方法,包括将面板放在所有内容之上并将操作处理程序放在上面;但我仍然遇到同样的问题。
我正在使用 Visual Studio 2017 和 Windows 10。我正在编码和测试的设备是 Microsoft Surface Book
似乎正在发生的是,非惯性运动先发生;然后一旦完成,惯性就会发射。我在事件中放置了一些输出,然后在滑动时得到了以下信息:
ManipulationStarting Fired
ManipulationDelta e.IsInertial = False. X,Y:-5.14288330078125,-1.14288330078125
ManipulationDelta e.IsInertial = False. X,Y:-16.5714111328125,0
ManipulationDelta e.IsInertial = False. X,Y:-16.5714111328125,0
ManipulationDelta e.IsInertial = False. X,Y:-89.1428833007813,1.14288330078125
ManipulationDelta e.IsInertial = False. X,Y:-224,2.28570556640625
ManipulationDelta e.IsInertial = False. X,Y:-224,2.28570556640625
ManipulationDelta e.IsInertial = False. X,Y:-384.571441650391,4
ManipulationDelta e.IsInertial = False. X,Y:-622.285705566406,4
ManipulationDelta e.IsInertial = False. X,Y:-622.285705566406,4
ManipulationDelta e.IsInertial = False. X,Y:-622.285705566406,4
ManipulationDelta e.IsInertial = False. X,Y:-732.571411132813,6.28570556640625
ManipulationDelta e.IsInertial = False. X,Y:-732.571411132813,6.28570556640625
ManipulationDelta e.IsInertial = False. X,Y:-732.571411132813,6.28570556640625
ManipulationDelta e.IsInertial = False. X,Y:-732.571411132813,6.28570556640625
ManipulationInertiaStarting Fired
在那之后,我没有再触发任何增量。那么消耗它们的是什么?为什么我先得到非惯性的?
我发现实现这种工作的一种方法是将 PanningMode="VerticalFirst"
更改为 PanningMode="None"
。然后自己处理滚动(这似乎是 UWP 版本正在做的事情)......但我仍然必须摆脱 "e.IsInertial" 检查。所以在我的事件处理程序获取它们之前,某些东西导致惯性增量被消耗
为确保操作流程按预期工作,您需要处理更多操作事件并做出相应反应。这是来自 MS (Input overview - Touch and manipulations) 的概述,但一般来说,您通常希望:
- 处理 ManipulationStarting 并为您的操作设置适当的操作容器。
- handle ManipulationStarted 如果您想存储一些数据,例如您自己计算的操作来源。
- 在用户按下手指时处理 Delta
- handle InertiaStarting - 在这里你应该设置减速度值。
- 在用户抬起手指时处理 Delta(惯性)- 根据我的经验,只有在指定惯性值时才会收到这些事件。
- 如果您需要知道输入过程何时何地完成,请处理 ManipulationCompleted。
来自您的 post 我不确定您是否知道这一点,但 InertiaStarting 只会在 用户抬起手指 (s) 时发生。然后 - 如果您 在正确处理 InertiaStarting 时设置值 - 您将获得更多的 ManipulationDeltas 传入(带有惯性标志)。
After that, I don't get any more deltas firing. So what's consuming them; and why am I getting non-inertial ones first?
您已经通过调用 complete 完成了操作过程,因为下面的 if 检查已经完成!所以 'engine' 已经跳过了它本来会触发的所有其他事件并完成了操作过程:
if (e.Cumulative.Translation.X <= -500)
{
showNext();
e.Complete();
}
操作完成后,您当然不会再收到任何事件。