ManipulationDeltaEvents - Как по-разному масштабировать по осям X и Y? - PullRequest
0 голосов
/ 27 мая 2020

Я пытаюсь использовать ManipulationDeltaEvents для управления прямоугольником в окне WPF - масштабирование, перевод и поворот через события касания. Я использую пошаговое руководство Microsoft , которое использует эти сгенерированные события для изменения MatrixTransform, в результате чего компонент переводится, поворачивается и масштабируется, что отлично работает.

Загвоздка в том, что я также хочу иметь возможность «прижать sh» компонент - применяя разный масштаб к каждой из осей прямоугольников, в зависимости от того, где произошел жест сжатия. (Например, если я зажму прямоугольник по вертикали, он станет более плоским; если я зажму прямоугольник по горизонтали, он станет тоньше).

В примере Microsoft есть смысл сказать:

         // Resize the Rectangle.  Keep it square
         // so use only the X value of Scale.
         rectsMatrix.ScaleAt(e.DeltaManipulation.Scale.X,
                             e.DeltaManipulation.Scale.X,
                             e.ManipulationOrigin.X,
                             e.ManipulationOrigin.Y);

... но изменение аргументов на ScaleAt (... Scale.X, ... Scale.Y) не имеет никакого эффекта - масштаб всегда идентичен по осям X и Y - потому что e.DeltaManipulation.Scale.X и e.DeltaManipulation.Scale.Y всегда имеют одно и то же значение.

Есть ли у вас какие-нибудь предложения, как легко добавить эту функцию? Мне нравится простота, с которой ManipulationDeltaEventArgs работает для преобразований перемещения и вращения ... Мне просто не хватает чего-то, что позволяет ему асимметрично масштабировать элемент управления.

Вот пошаговое руководство:

<Window x:Class="Touchy.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800"        
        WindowState="Maximized"
        ManipulationStarting="Window_ManipulationStarting"
        ManipulationDelta="Window_ManipulationDelta"
       >
    <Window.Resources>

        <!--The movement, rotation, and size of the Rectangle is 
        specified by its RenderTransform.-->
        <MatrixTransform x:Key="InitialMatrixTransform">
            <MatrixTransform.Matrix>
                <Matrix OffsetX="200" OffsetY="200"/>
            </MatrixTransform.Matrix>
        </MatrixTransform>

    </Window.Resources>

    <Canvas>
        <Rectangle Fill="Red" Name="manRect"
                 Width="200" Height="200" 
                 RenderTransform="{StaticResource InitialMatrixTransform}"
                 IsManipulationEnabled="true" />
    </Canvas>
</Window>

И в кодовой части:

using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Shapes;

namespace Touchy
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }
        void Window_ManipulationStarting(object sender, ManipulationStartingEventArgs e)
        {
            e.ManipulationContainer = this;
            e.Handled = true;
        }

        void Window_ManipulationDelta(object sender, ManipulationDeltaEventArgs e)
        {

            // Get the Rectangle and its RenderTransform matrix.
            Rectangle rectToMove = e.OriginalSource as Rectangle;
            Matrix rectsMatrix = ((MatrixTransform)rectToMove.RenderTransform).Matrix;

            // Rotate the Rectangle.
            rectsMatrix.RotateAt(e.DeltaManipulation.Rotation,
                                 e.ManipulationOrigin.X,
                                 e.ManipulationOrigin.Y);

            // Resize the Rectangle.  Keep it square
            // so use only the X value of Scale.
            rectsMatrix.ScaleAt(e.DeltaManipulation.Scale.X,
                                e.DeltaManipulation.Scale.Y,
                                e.ManipulationOrigin.X,
                                e.ManipulationOrigin.Y);

            // Move the Rectangle.
            rectsMatrix.Translate(e.DeltaManipulation.Translation.X,
                                  e.DeltaManipulation.Translation.Y);

            // Apply the changes to the Rectangle.
            rectToMove.RenderTransform = new MatrixTransform(rectsMatrix);

            Rect containingRect =
                new Rect(((FrameworkElement)e.ManipulationContainer).RenderSize);

            Rect shapeBounds =
                rectToMove.RenderTransform.TransformBounds(
                    new Rect(rectToMove.RenderSize));

            // Check if the rectangle is completely in the window.
            // If it is not and intertia is occuring, stop the manipulation.
            if (e.IsInertial && !containingRect.Contains(shapeBounds))
            {
                e.Complete();
            }

            e.Handled = true;
        }

        void Window_InertiaStarting(object sender, ManipulationInertiaStartingEventArgs e)
        {

            // Decrease the velocity of the Rectangle's movement by
            // 10 inches per second every second.
            // (10 inches * 96 pixels per inch / 1000ms^2)
            e.TranslationBehavior.DesiredDeceleration = 10.0 * 96.0 / (1000.0 * 1000.0);

            // Decrease the velocity of the Rectangle's resizing by
            // 0.1 inches per second every second.
            // (0.1 inches * 96 pixels per inch / (1000ms^2)
            e.ExpansionBehavior.DesiredDeceleration = 0.1 * 96 / (1000.0 * 1000.0);

            // Decrease the velocity of the Rectangle's rotation rate by
            // 2 rotations per second every second.
            // (2 * 360 degrees / (1000ms^2)
            e.RotationBehavior.DesiredDeceleration = 720 / (1000.0 * 1000.0);

            e.Handled = true;
        }
    }
}

РЕДАКТИРОВАТЬ: Оказывается, это может быть невозможно с помощью ManipulationDeltaEvents. Я нашел этот ответ , который предполагает, что независимое масштабирование по осям X и Y отключено, когда вращение включено, или не поддерживается вообще.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...