如何让我的 Rectangle 像对 mouse/pointer 事件那样对触摸事件做出反应?

How can I make my Rectangle react to touch events like it does for mouse/pointer events?

在我的 MainPage 上,我有一个 Stackpanel 充满了五颜六色的矩形,它们都以边距设置为 (0,5,0,5) 开头。我想允许用户仅水平移动这些矩形。由于矩形没有鼠标事件,我使用指针来实现这一点。流程是:用户点击 Rectangle 使其 select,光标改变以给用户视觉提示,用户向左或向右拖动 Rectangle。 (请注意,如果重要的话,Stackpanel 确实有一个垂直滚动查看器)。这是我的 C# 代码:

private void Rectangle_FirstClick(object sender, EventArgs e)
{
    // Give rectangle a white border to imply selection
    Rectangle myControl = sender as Rectangle;
    myControl.StrokeThickness = 1;
    myControl.Stroke = new SolidColorBrush(Color.FromArgb(255, 240, 240, 240));

    // Provide visual cue to mouse users by changing the pointer immediately
    Window.Current.CoreWindow.PointerCursor = new Windows.UI.Core.CoreCursor(Windows.UI.Core.CoreCursorType.SizeWestEast, 0);

    // Handle mouse leaving/re-entering the track piece
    myControl.PointerEntered += MyControl_PointerEntered;
    myControl.PointerExited += MyControl_PointerExited;

    // Handle the drag event
    myControl.PointerPressed += MyControl_PointerPressed;
    myControl.PointerReleased += MyControl_PointerReleased;
    myControl.PointerMoved += MyControl_PointerMoved;
}

这是各个事件处理程序

bool PossibleDragStart = false;
Point InitialDragPoint = new Point(0, 0);

private void MyControl_PointerExited(object sender, PointerRoutedEventArgs e)
{
    Window.Current.CoreWindow.PointerCursor = new Windows.UI.Core.CoreCursor(Windows.UI.Core.CoreCursorType.Arrow, 0);
}

private void MyControl_PointerEntered(object sender, PointerRoutedEventArgs e)
{
    Window.Current.CoreWindow.PointerCursor = new Windows.UI.Core.CoreCursor(Windows.UI.Core.CoreCursorType.SizeWestEast, 0);
}

private void MyControl_PointerPressed(object sender, PointerRoutedEventArgs e)
{
    PossibleDragStart = true;
    InitialDragPoint = e.GetCurrentPoint(sender as Rectangle).Position;
}

private void MyControl_PointerReleased(object sender, PointerRoutedEventArgs e)
{
    PossibleDragStart = false;
}

private void MyControl_PointerMoved(object sender, PointerRoutedEventArgs e)
{
    // If pointer pressed without release, and then moved, we are dragging
    if (PossibleDragStart)
    {
        Point CurrentDragPoint = e.GetCurrentPoint(AudioTracksRightContainer).Position;
        StatusBar.Text = CurrentDragPoint.X.ToString();

        // Calculate drag offset by subtracting Current Position from Initial Position
        double SegmentMargin = CurrentDragPoint.X - InitialDragPoint.X;

        // Move the Rectangle with the pointer drag
        Rectangle trackSegment = sender as Rectangle;
        trackSegment.Margin = new Thickness(SegmentMargin, 5, 0, 5);
    }
}

此代码非常适合鼠标,但当我尝试将其用于触摸时,我必须按住鼠标才能开始拖动,即便如此,矩形在保持原状之前也只移动了几个单位。我不确定行为为何不同。

此代码的另一个问题是,如果矩形足够窄以至于当我快速拖动时矩形跟不上光标,当光标离开矩形边界时它会停止拖动。比触摸不起作用小得多的问题,但还是有点烦人。

听起来 ScrollViewer 正在捕获触摸事件以进行自己的滚动。除了手动处理操作,您还可以使用 Xaml 的操作引擎来注册操作事件。这既更容易编码又更高效。它默认适用于触摸和鼠标。

<Rectangle Margin="5" Fill="Orange" Height="100" Width="200"
           ManipulationMode="TranslateX"
           ManipulationDelta="Rectangle_ManipulationDelta"
           >
    <Rectangle.RenderTransform>
        <CompositeTransform />
    </Rectangle.RenderTransform>
</Rectangle>

在 Rectangle_ManipulationDelta 方法中平移矩形:

private void Rectangle_ManipulationDelta(object sender, ManipulationDeltaRoutedEventArgs e)
{
    UIElement elem = sender as UIElement;
    CompositeTransform ct = elem.RenderTransform as CompositeTransform;

    ct.TranslateX += e.Delta.Translation.X;
}

如果您只需要翻译,您可以使用 TranslateTransform 而不是 CompositeTransform,或者您可以添加旋转和缩放。

有关使用手势和操作事件的更多信息,请参阅 Quickstart: Touch input (XAML)

我在我的博客条目 Where did all my gestures go? If you really want to handle the pointer events yourself I discuss how to disable the ScrollViewer during dragging. You can handle the case where the finger moves faster than the target by capturing the pointer 中讨论了 ScrollViewer 接管指针处理。如果您处理操作事件,则不需要这样做。