Я пытаюсь использовать 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 отключено, когда вращение включено, или не поддерживается вообще.