C# 旋转变换与平移变换的结合
我使用Thumb类让用户在画布上拖放图像。当按下右键时,我希望用户能够旋转图像。旋转以图像中心为基础。我有以下XAML代码C# 旋转变换与平移变换的结合,c#,wpf,transform,rotatetransform,C#,Wpf,Transform,Rotatetransform,我使用Thumb类让用户在画布上拖放图像。当按下右键时,我希望用户能够旋转图像。旋转以图像中心为基础。我有以下XAML代码 <Grid> <Canvas Background="Red" Grid.RowSpan="2" x:Name="canvas" PreviewMouseRightButtonUp="Canvas_MouseUp" PreviewMouseMove="Canvas_MouseMove">
<Grid>
<Canvas Background="Red" Grid.RowSpan="2" x:Name="canvas"
PreviewMouseRightButtonUp="Canvas_MouseUp"
PreviewMouseMove="Canvas_MouseMove">
<UserControl MouseRightButtonDown="Canvas_MouseDown" RenderTransformOrigin="0.5,0.5">
<Thumb Name="myRoot" DragDelta="myRoot_DragDelta">
<Thumb.Template>
<ControlTemplate>
<Grid>
<Image Source="/WpfApplication1;component/someImage.png" />
<Rectangle Stroke="#FF0061CE" StrokeThickness="1" Width="230" Height="250" />
</Grid>
</ControlTemplate>
</Thumb.Template>
</Thumb>
<UserControl.RenderTransform>
<TransformGroup>
<RotateTransform x:Name="rotateTransform" />
<TranslateTransform x:Name="translateTransform" />
</TransformGroup>
</UserControl.RenderTransform>
</UserControl>
</Canvas>
</Grid>
如果我只在屏幕周围拖放图像,并稍微旋转图像(在任何方向上50度似乎都可以),它就会工作。然而,如果对其进行更多的操作,图像就会在屏幕上不可预测地移动
我尝试将转换移动到不同的控件,以避免混淆它们,但没有收到可接受的结果
我怎样才能让我的代码表现得像我想要的那样
更新:这让我发疯。我已经更改了代码和XAML,改为使用MatrixTransformation
private void Canvas_MouseMove(object sender, MouseEventArgs e)
{
if (!isMouseDown) return;
var curPos = Mouse.GetPosition(canvas);
angle = (lastAngle + (pos.Y - curPos.Y)) % 360;
UpdateMatrixTransform();
}
private void myRoot_DragDelta(object sender, DragDeltaEventArgs e)
{
posX += e.HorizontalChange;
posY += e.VerticalChange;
UpdateMatrixTransform();
}
void UpdateMatrixTransform()
{
Matrix m = new Matrix();
m.Rotate(angle);
m.OffsetX = posX;
m.OffsetY = posY;
matrixT.Matrix = m;
}
在我看来,这应该是可行的:首先,旋转图形,然后将其移动到偏移位置。它不像我期望的那样工作。它旋转图像,但如果我继续移动鼠标,它会以螺旋的方式奇怪地向外移动。无论我做什么,以什么顺序执行转换,它都不会工作 您必须告诉RotateTransform您要围绕对象的中心而不是坐标系的中心旋转,这是默认设置。为此,请将RotateTransform的CenterX和CenterY属性设置为对象的中心。我不确定为什么要使用UserControl来包裹Thumb,因为它应该可以充当此处的根元素。下面是一个解决方案,它包括放弃使用TranslateTransform,而是使用Canvas.Left和Canvas.Top属性: 编辑:更新答案 以下是XAML:
<Canvas x:Name="canvas">
<Thumb Name="myRoot"
Canvas.Left="0" Canvas.Top="0"
DragDelta="myRoot_DragDelta"
MouseMove="myRoot_MouseMove"
MouseDown="myRoot_MouseDown"
MouseUp="myRoot_MouseUp">
<Thumb.Template>
<ControlTemplate>
<Grid RenderTransformOrigin="0.5, 0.5">
<Rectangle Fill="AliceBlue"
Stroke="#FF0061CE"
StrokeThickness="1"
Width="100" Height="100"/>
<Grid.RenderTransform>
<RotateTransform x:Name="rotateTransform" />
</Grid.RenderTransform>
</Grid>
</ControlTemplate>
</Thumb.Template>
</Thumb>
</Canvas>
我以为我是通过在用户控件上设置renderTransferMorigin=“0.5,0.5”来实现的?请检查:@Gilad我不确定这个链接对我有什么帮助,你能给我一个提示吗?尝试交换转换的顺序。它应该先平移,然后旋转。@Moozhe我这样做了,但是它会围绕画布的左上角点旋转,而不是图像的原点(我将RenderTransferMorigin设置为0.5,0.5)。我尝试了你的代码,虽然旋转部分看起来有点缓慢,但它还是工作了,至少在我的机器上,它没有我希望的那么顺利。这不是理想的方式。我会看看我是否能写一个更好的例子。我也看到了我在我的版本中看到的同样奇怪的行为。一旦旋转超过90度,当再次拖动时,它开始表现出奇怪的行为(复制:拖动到中间,旋转180度,而不是向任何方向拖动)。拇指在变换时不报告正确的增量值。拇指应该高于视觉树中的变换(其内容可以变换)。我会发布我的代码。
<Canvas x:Name="canvas">
<Thumb Name="myRoot"
Canvas.Left="0" Canvas.Top="0"
DragDelta="myRoot_DragDelta"
MouseMove="myRoot_MouseMove"
MouseDown="myRoot_MouseDown"
MouseUp="myRoot_MouseUp">
<Thumb.Template>
<ControlTemplate>
<Grid RenderTransformOrigin="0.5, 0.5">
<Rectangle Fill="AliceBlue"
Stroke="#FF0061CE"
StrokeThickness="1"
Width="100" Height="100"/>
<Grid.RenderTransform>
<RotateTransform x:Name="rotateTransform" />
</Grid.RenderTransform>
</Grid>
</ControlTemplate>
</Thumb.Template>
</Thumb>
</Canvas>
public partial class TestWindow : Window
{
public TestWindow()
{
InitializeComponent();
}
Point? lastPosition = null;
RotateTransform rotateTransform;
private void myRoot_MouseDown(object sender, MouseButtonEventArgs e)
{
lastPosition = null;
if (e.ChangedButton == MouseButton.Right)
myRoot.CaptureMouse();
}
private void myRoot_MouseUp(object sender, MouseButtonEventArgs e)
{
if (e.ChangedButton == MouseButton.Right)
myRoot.ReleaseMouseCapture();
}
private void myRoot_MouseMove(object sender, MouseEventArgs e)
{
if (e.RightButton == MouseButtonState.Pressed)
{
Point curPosition = Mouse.GetPosition(myRoot);
if (lastPosition != null)
{
Point centerPoint = new Point(myRoot.ActualWidth / 2, myRoot.ActualWidth / 2);
if (rotateTransform == null)
rotateTransform = (RotateTransform)myRoot.Template.FindName("rotateTransform", myRoot);
rotateTransform.Angle = Math.Atan2(curPosition.Y - centerPoint.Y, curPosition.X - centerPoint.X) * 100;
}
lastPosition = curPosition;
e.Handled = true;
}
}
private void myRoot_DragDelta(object sender, System.Windows.Controls.Primitives.DragDeltaEventArgs e)
{
Canvas.SetLeft(myRoot, Canvas.GetLeft(myRoot) + e.HorizontalChange);
Canvas.SetTop(myRoot, Canvas.GetTop(myRoot) + e.VerticalChange);
}
}