WPF UserControl 中的缩放/捏合检测

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/25861840/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-13 12:32:20  来源:igfitidea点击:

Zoom/Pinch detection in a WPF UserControl

wpftouchzoompinchzoom

提问by Aman

I want to know how can I detect a Zoom/pinch gesture made on UserControl? Following is my XAML code. How can i detect this in "Grid_OnManipulationDelta" or "Grid_OnManipulationCompleted" methods? Thanx for the help in advance.

我想知道如何检测 UserControl 上的缩放/捏合手势?以下是我的 XAML 代码。我如何在“Grid_OnManipulationDelta”或“Grid_OnManipulationCompleted”方法中检测到这一点?提前感谢您的帮助。

<UserControl x:Class="HCMainWPF.Views.MainView" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:views="clr-namespace:HCMainWPF.Views" mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="300" Name="ZMainView">
    <Canvas x:Name="grid">
        <Canvas.RenderTransform>
            <ScaleTransform x:Name="zoom" ScaleX="1" ScaleY="1" />
        </Canvas.RenderTransform>
        <Canvas.Triggers>
            <EventTrigger RoutedEvent="Grid.ManipulationCompleted">
                <EventTrigger.Actions>
                    <BeginStoryboard>
                        <Storyboard>
                            <DoubleAnimation Duration="00:00:02" From="320" Storyboard.TargetName="ZMainView"
                        Storyboard.TargetProperty="Height"  To="960"/>
                            <DoubleAnimation Duration="00:00:02" From="270" Storyboard.TargetName="ZMainView"
                        Storyboard.TargetProperty="Width" To="810"/>
                            <DoubleAnimation Duration="00:00:02" From="1" Storyboard.TargetName="zoom"
                        Storyboard.TargetProperty="ScaleX" To="3"/>
                            <DoubleAnimation Duration="00:00:02" From="1" Storyboard.TargetName="zoom"
                        Storyboard.TargetProperty="ScaleY" To="3"/>
                        </Storyboard>
                    </BeginStoryboard>
                </EventTrigger.Actions>
            </EventTrigger>
        </Canvas.Triggers>
        <Grid Height="280" Width="280" IsManipulationEnabled="True"
            ManipulationStarting="Grid_OnManipulationStarting"
            ManipulationDelta="Grid_OnManipulationDelta" 
            ManipulationCompleted="Grid_OnManipulationCompleted">
            <Grid.RowDefinitions>
                <RowDefinition Height="1.66*"/>
                <RowDefinition Height="1.66*"/>
                <RowDefinition Height="1.66*"/>
                <RowDefinition Height="1.66*"/>
                <RowDefinition Height="1.66*"/>
                <RowDefinition Height="1.66*"/>
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="3.33*"/>
                <ColumnDefinition Width="3.33*"/>
                <ColumnDefinition Width="3.33*"/>
            </Grid.ColumnDefinitions>
        </Grid>
    </Canvas>
</UserControl>

回答by olitee

In short, yes. The quickest way to get up and running with a pinch/zoom gesture is to attach the 'TranslateZoomRotateBehavior' to the usercontrol or element you want to control. This will allow you to use single and multitouch events to control the pan, scale and rotation of an element.

简而言之,是的。使用捏/缩放手势启动和运行的最快方法是将“TranslateZoomRotateBehavior”附加到您要控制的用户控件或元素。这将允许您使用单点和多点触控事件来控制元素的平移、缩放和旋转。

If you want to do this manually, then I suggest you have a look at a custom version of this behaviour I've posted on Codeplex.

如果您想手动执行此操作,那么我建议您查看我在 Codeplex 上发布的此行为的自定义版本。

In particular, the ManipulationDeltaHandler in this class.

特别是这个类中ManipulationDeltaHandler

回答by Andreas

 public class GestureDetector
{
    private readonly uint _pixelPerCm = 38;
    private bool _isGestureDetected = false;

    public bool IsPanningAllowed { get; private set; }
    public bool IsScalingAllowed { get; private set; }
    public bool IsRotatingAllowed { get; private set; }

    public GestureDetector(FrameworkElement uiElement)
    {
        IsPanningAllowed = false;
        IsScalingAllowed = false;
        IsRotatingAllowed = false;

        uiElement.ManipulationStarted += (sender, args) =>
        {
            IsPanningAllowed = true;
        };

        double scale = 0.0d;
        double rot = 0.0d;

        uiElement.ManipulationDelta += (sender, args) =>
        {
            const double MIN_SCALE_TRIGGER = 0.05;
            const int MIN_ROTATIONANGLE_TRIGGER_DEGREE = 10;
            const int MIN_FINGER_DISTANCE_FOR_ROTATION_CM = 2;

            var manipulatorBounds = Rect.Empty;
            foreach (var manipulator in args.Manipulators)
            {
                manipulatorBounds.Union(manipulator.GetPosition(sender as IInputElement));
            }

            var distance = (manipulatorBounds.TopLeft - manipulatorBounds.BottomRight).Length;
            var distanceInCm = distance /_pixelPerCm;

            scale += 1-(args.DeltaManipulation.Scale.Length / Math.Sqrt(2));

            rot += args.DeltaManipulation.Rotation;

            if (Math.Abs(scale) > MIN_SCALE_TRIGGER && Math.Abs(rot) < MIN_ROTATIONANGLE_TRIGGER_DEGREE)
            {
                ApplyScaleMode();
            }

            if (Math.Abs(rot) >= MIN_ROTATIONANGLE_TRIGGER_DEGREE && distanceInCm > MIN_FINGER_DISTANCE_FOR_ROTATION_CM)
            {
                ApplyRotationMode();
            }
        };

        uiElement.ManipulationCompleted += (sender, args) =>
        {
            scale = 0.0d;
            rot = 0.0d;
            IsPanningAllowed = false;
            IsScalingAllowed = false;
            IsRotatingAllowed = false;
            _isGestureDetected = false;
        };
    }

    private void ApplyScaleMode()
    {
        if (!_isGestureDetected)
        {
            _isGestureDetected = true;
            IsPanningAllowed = true;
            IsScalingAllowed = true;
            IsRotatingAllowed = false;
        }
    }

    private void ApplyRotationMode()
    {
        if (!_isGestureDetected)
        {
            _isGestureDetected = true;
            IsPanningAllowed = true;
            IsScalingAllowed = true;
            IsRotatingAllowed = true;
        }
    }
}

Usage:

用法:

 private void uielement_ManipulationDelta(object sender, ManipulationDeltaEventArgs e)
    {
        {
            if (_gestureDetector.IsPanningAllowed)
            {
               // Translate
            }
        }

        {
            if (_gestureDetector.IsScalingAllowed)
            {
               // Scale
            }
        }

        {
            if (_gestureDetector.IsRotatingAllowed)
            {
                // Rotate
            }
        }
    }