2

我对这个 WPF 世界有点陌生。而且我有点困惑为什么我的滚动视图正在消耗我的触摸事件。

我现在的情况是这样的:

我有这个带有 ItemsControl 的 ScrollViewer。在这个 ItemsControl 中,我使用 Wrappanel 来显示一些矩形。我的 ScrollViewer 应该可以垂直滚动以显示向下包裹的矩形。在这些矩形中的每一个上,我使用各种处理程序创建了一个 CustomBehaviour。这些处理程序之一是处理 LongPressGestures 的“创造性”方法。

问题如下,在我的长按被行为检测到之前,我的 ScrollViewer 正在其 PreviewTouchMove 处理程序中捕获我的 TouchDevice。

如何防止我的 ScrollViewer 过早捕获我的 TouchDevice?如何确保可以滚动 ScrollViewer 并执行 LongPress、DoubleClick(仍然有效)、SingleClick(仍然有效)和其他可能添加到此自定义行为的手势?

我在 stackoverflow 和 google 上发现了类似的问题,我只是没有弄清楚我的具体情况。

带有 CustomThumb 的东西<--此链接通过制作 CustomThumb 来解决问题。我可以以某种方式将其重新用于我的行为吗?通过在我的行为处理程序中及早捕获 TouchDevice?

如果一切都失败了。这个 ScrollViewer 和 CustomBehaviour 组合是否有替代方案?


编辑:

同时。我重试了 CustomThumb 方法。当 UIElements(具有该行为)位于 ScrollViewer 上时,我现在从我的 CustomBehaviour 得到了长按。但是 ScrollViewer 的滚动功能仍然不起作用。我添加的赏金也将奖励给帮助我使其再次正常工作的人(因为答案应该与此 CustomThumb 解决方案的方向相同)。

4

1 回答 1

4

我以前也有类似的问题。我不能同时使用滚动、触摸和样式。最后我开发了一个自定义的 ScrollViewer。它比您想象的要容易,因为您只需要观察/更改一些基本方法。

在您的情况下,您可以检查用户是否按下了 empy 表面或列表项。如果是列表项,则需要检查是短按(因此,touchup 也发生在 touchdown 之后)还是长按。

可以使用 PanningMode 配置滚动。它允许您用手指在整个用户控件上滚动。

这是我的滚动查看器版本。当用户按下按钮并随后打开时,它会关闭滚动模式。

public class ScrollViewerWithTouch : ScrollViewer   
{
      /// <summary>
      /// Original panning mode.
      /// </summary>
      private PanningMode panningMode;

  /// <summary>
  /// Set panning mode only once.
  /// </summary>
  private bool panningModeSet;

  /// <summary>
  /// Initializes static members of the <see cref="ScrollViewerWithTouch"/> class.
  /// </summary>
  static ScrollViewerWithTouch()
  {
     DefaultStyleKeyProperty.OverrideMetadata(typeof(ScrollViewerWithTouch), new FrameworkPropertyMetadata(typeof(ScrollViewerWithTouch)));
  }

  protected override void OnManipulationCompleted(ManipulationCompletedEventArgs e)
  {
     base.OnManipulationCompleted(e);

     // set it back
     this.PanningMode = this.panningMode;
  }

  protected override void OnManipulationStarted(ManipulationStartedEventArgs e)
  {
     // figure out what has the user touched
     var result = VisualTreeHelper.HitTest(this, e.ManipulationOrigin);
     if (result != null && result.VisualHit != null)
     {
        var hasButtonParent = this.HasButtonParent(result.VisualHit);

        // if user touched a button then turn off panning mode, let style bubble down, in other case let it scroll
        this.PanningMode = hasButtonParent ? PanningMode.None : this.panningMode;
     }

     base.OnManipulationStarted(e);
  }

  protected override void OnTouchDown(TouchEventArgs e)
  {
     // store panning mode or set it back to it's original state. OnManipulationCompleted does not do it every time, so we need to set it once more.
     if (this.panningModeSet == false)
     {
        this.panningMode = this.PanningMode;
        this.panningModeSet = true;
     }
     else
     {
        this.PanningMode = this.panningMode;
     }

     base.OnTouchDown(e);         
  }

  private bool HasButtonParent(DependencyObject obj)
  {
     var parent = VisualTreeHelper.GetParent(obj);

     if ((parent != null) && (parent is ButtonBase) == false)
     {
        return HasButtonParent(parent);
     }

     return parent != null;
  }
}
于 2013-11-11T15:12:38.687 回答