WPF UserControl中的缩放/捏合检测

时间:2014-09-16 06:18:44

标签: wpf touch zoom pinchzoom

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

<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>

2 个答案:

答案 0 :(得分:1)

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

如果您想手动执行此操作,我建议您查看此行为的自定义版本I've posted on Codeplex

特别是ManipulationDeltaHandler in this class

答案 1 :(得分:1)

 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;
        }
    }
}

用法:

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

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

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