0

私はThumbクラスを使用して、ユーザーがキャンバス上で画像をドラッグアンドドロップできるようにしています。右ボタンが押されたら、ユーザーが画像を回転できるようにしたいと思います。回転は画像の中心を中心に行われます。私は次のXAMLコードを持っています

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

そして、このコードの背後にある

    bool isMouseDown = false;
    Point pos;
    double lastAngle = 0;

    private void Canvas_MouseDown(object sender, MouseButtonEventArgs e)
    {
        isMouseDown = true;
        lastAngle = rotateTransform.Angle;
        pos = Mouse.GetPosition(canvas);
    }   

    private void Canvas_MouseUp(object sender, MouseButtonEventArgs e)
    {
        isMouseDown = false;
    }

    private void Canvas_MouseMove(object sender, MouseEventArgs e)
    {
        if (!isMouseDown) return;

        var curPos = Mouse.GetPosition(canvas);
        rotateTransform.Angle = lastAngle + (pos.Y - curPos.Y);
    }

    private void myRoot_DragDelta(object sender, DragDeltaEventArgs e)
    {
        translateTransform.X += e.HorizontalChange;
        translateTransform.Y += e.VerticalChange; 
    }

画面上で画像をドラッグアンドドロップし、画像を少し回転させるだけで機能します(どの方向にも50度で問題ないようです)。ただし、それ以上に操作すると、画像が画面上を予期せず動き始めます。

変換を別のコントロールに移動しようとしましたが、それらを混同しないようにしていますが、許容できる結果は得られていません。

コードを希望どおりに動作させるにはどうすればよいですか?

更新:これは私の狂気を駆り立てています。代わりにMatrixTransformationを使用するようにコードとXAMLを変更しました

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

私の考えでは、これは機能するはずです。まず、グラフィックをオフセットに移動するよりも回転させます。期待どおりに動作しません。画像を回転させますが、マウスを動かし続けると不思議なことにスパイラル状に外側に移動します。私が何をしても、どのような順序で変換を実行しても、機能しません。

4

2 に答える 2

1

ここでルート要素として機能できるはずなので、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>

そして、これが背後にあるコードです:

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);
    }
}
于 2012-06-04T20:17:43.203 に答える
0

デフォルトである座標系の中心ではなく、オブジェクトの中心を中心に回転することをRotateTransformに指示する必要があります。これを行うには、RotateTransformのCenterXプロパティとCenterYプロパティをオブジェクトの中心に設定します。

于 2012-06-04T17:47:25.803 に答える