猿问

如何在 WPF 中使用捏合功能同时启用滚动和缩放?

我正在努力使触摸事件和操作在 WPF 项目中正常工作。我有一个包含图片的ScrollViewer,我想使用滑动手势水平和垂直滚动。此外,我想在捏合手势的中心放大/缩小。下面的代码实现了我的愿望,但是存在以下问题:

  • 有时滚动会很滞后;

  • 滚动在第一次尝试时不起作用,只有在第二次尝试相同的手势时才会起作用;

  • 第一次尝试时放大/缩小不起作用,仅当第二次尝试相同手势时才起作用。

我启用了IsManipulationEnabled并实现了放大/缩小功能的代码。但是,我无法将其与滚动功能结合起来(仅通过在ScrollViewer中设置PanningMode)。因此,我创建了一个继承自Image控件的自定义控件,并覆盖了OnTouchDownOnTouchUp事件处理程序。基本上,我在这些覆盖的处理程序中所做的就是计算屏幕上的触摸次数并启用/禁用操作。我还尝试设置ScrollViewerPanningMode,但它没有成功。

下面是 XAML:


<Grid>

        <ScrollViewer

            x:Name="ScrollViewerParent"

            HorizontalScrollBarVisibility="Auto"

            VerticalScrollBarVisibility="Auto"

            PanningMode="Both">

            <local:CustomImage 

                x:Name="MainImage"

                Source="{Binding Source={x:Static local:Constants.ImagePath}}"

                IsManipulationEnabled="True"

                ManipulationStarting="MainImage_ManipulationStarting"

                ManipulationDelta="MainImage_ManipulationDelta">

            </local:CustomImage>

        </ScrollViewer>

    </Grid>

这是背后的代码:


public partial class MainWindow : Window

{

        private void MainImage_ManipulationStarting(object sender, ManipulationStartingEventArgs e)

        {

            e.ManipulationContainer = ScrollViewerParent;

            e.Handled = true;

        }


        private void MainImage_ManipulationDelta(object sender, ManipulationDeltaEventArgs e)

        {

            var matrix = MainImage.LayoutTransform.Value;


            Point? centerOfPinch = (e.ManipulationContainer as FrameworkElement)?.TranslatePoint(e.ManipulationOrigin, ScrollViewerParent);


            if (centerOfPinch == null)

            {

                return;

        }

}



侃侃尔雅
浏览 98回答 1
1回答

ibeautiful

幸运的是,我设法找到了完美的解决方案。因此,如果有人正在解决类似的问题并需要一些帮助,我将发布答案。我做了什么:摆脱了自定义控件,因为它没有必要;创建一个统计触摸点数量的字段;实现了TouchDown事件处理程序,它将触摸点的数量增加 1(每次设备上有触摸向下手势时都会调用此方法);实现了TouchUp事件处理程序,它将触摸点的数量减 1(每次设备上有触摸向上手势时都会调用此方法);在Image_ManipulationDelta事件处理程序中,我检查触摸点的数量:如果触摸点数<2,则将平移值加上滚动条当前的偏移量,从而实现滚动;否则,计算捏合中心并应用缩放手势。这是完整的 XAML:&nbsp;<Grid&nbsp; &nbsp; &nbsp; &nbsp; x:Name="GridParent">&nbsp; &nbsp; &nbsp; &nbsp; <ScrollViewer&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; x:Name="ScrollViewerParent"&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; HorizontalScrollBarVisibility="Auto"&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; VerticalScrollBarVisibility="Auto"&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; PanningMode="Both">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <Image&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; x:Name="MainImage"&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Source="{Binding Source={x:Static local:Constants.ImagePath}}"&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; IsManipulationEnabled="True"&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; TouchDown="MainImage_TouchDown"&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; TouchUp="MainImage_TouchUp"&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ManipulationDelta="Image_ManipulationDelta"&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ManipulationStarting="Image_ManipulationStarting"/>&nbsp; &nbsp; &nbsp; &nbsp; </ScrollViewer>&nbsp; &nbsp; </Grid>这是上面讨论的完整代码:&nbsp; &nbsp; public partial class MainWindow : Window&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; private volatile int nrOfTouchPoints;&nbsp; &nbsp; &nbsp; &nbsp; private object mutex = new object();&nbsp; &nbsp; &nbsp; &nbsp; public MainWindow()&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; InitializeComponent();&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; DataContext = this;&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; private void Image_ManipulationStarting(object sender, ManipulationStartingEventArgs e)&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; e.ManipulationContainer = ScrollViewerParent;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; e.Handled = true;&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; private void Image_ManipulationDelta(object sender, ManipulationDeltaEventArgs e)&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; int nrOfPoints = 0;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; lock (mutex)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; nrOfPoints = nrOfTouchPoints;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (nrOfPoints >= 2)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; DataLogger.LogActionDescription($"Executed {nameof(Image_ManipulationDelta)}");&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; var matrix = MainImage.LayoutTransform.Value;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Point? centerOfPinch = (e.ManipulationContainer as FrameworkElement)?.TranslatePoint(e.ManipulationOrigin, ScrollViewerParent);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (centerOfPinch == null)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; var deltaManipulation = e.DeltaManipulation;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; matrix.ScaleAt(deltaManipulation.Scale.X, deltaManipulation.Scale.Y, centerOfPinch.Value.X, centerOfPinch.Value.Y);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; MainImage.LayoutTransform = new MatrixTransform(matrix);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Point? originOfManipulation = (e.ManipulationContainer as FrameworkElement)?.TranslatePoint(e.ManipulationOrigin, MainImage);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; double scrollViewerOffsetX = ScrollViewerParent.HorizontalOffset;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; double scrollViewerOffsetY = ScrollViewerParent.VerticalOffset;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; double pointMovedOnXOffset = originOfManipulation.Value.X - originOfManipulation.Value.X * deltaManipulation.Scale.X;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; double pointMovedOnYOffset = originOfManipulation.Value.Y - originOfManipulation.Value.Y * deltaManipulation.Scale.Y;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; double multiplicatorX = ScrollViewerParent.ExtentWidth / MainImage.ActualWidth;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; double multiplicatorY = ScrollViewerParent.ExtentHeight / MainImage.ActualHeight;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ScrollViewerParent.ScrollToHorizontalOffset(scrollViewerOffsetX - pointMovedOnXOffset * multiplicatorX);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ScrollViewerParent.ScrollToVerticalOffset(scrollViewerOffsetY - pointMovedOnYOffset * multiplicatorY);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; e.Handled = true;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; else&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ScrollViewerParent.ScrollToHorizontalOffset(ScrollViewerParent.HorizontalOffset - e.DeltaManipulation.Translation.X);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ScrollViewerParent.ScrollToVerticalOffset(ScrollViewerParent.VerticalOffset - e.DeltaManipulation.Translation.Y);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; private void MainImage_TouchDown(object sender, TouchEventArgs e)&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; lock (mutex)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; nrOfTouchPoints++;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; private void MainImage_TouchUp(object sender, TouchEventArgs e)&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; lock (mutex)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; nrOfTouchPoints--;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }}
随时随地看视频慕课网APP
我要回答