[WPF/xaml] 画面の要素を回転/拡大縮小/移動する(RenderTransformにMatrixTransform)


もくじ
https://qiita.com/tera1707/items/4fda73d86eded283ec4f

回転/拡大縮小/移動の関連記事

やること

xamlで画面に配置したものを、移動したり、拡大縮小、回転させたい。
以前の記事で、同じことをRenderTransformに、Transformクラスを継承したRotateTransformやScaleTransform、TranslateTransformをセットするというやり方で実現したが、今回はMatrixTransformをセットするやり方で実現してみたい。

経緯

Controlを拡大縮小や移動するだけなら前のやり方で全く問題なかったのだが、画像を出すアプリで、タッチパネルをフリックして画像を移動、またピンチイン/アウトして拡大縮小、をしたいときに、どうもMatrixTransformを使うのが常套らしい。

以前MatrixTransformを使うやり方がめんどくさそうで逃げてたので、この際一度MatrixTransformを触ってみることにした。

やり方

  1. xamlで、回転や拡大縮小したいControlにNameで名前を付ける
  2. 回転や拡大縮小したいところで、そのControlのRenderTransformをとしてとってくる
  3. とったMatrixTransformの拡大縮小用のメソッドを呼ぶ
  4. とったMatrixTransformを、ControlのRenderTransformにセットする

サンプル

xaml

MainWindow.xaml
<Window x:Class="WpfApp39.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"
        xmlns:local="clr-namespace:WpfApp39"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <Grid ShowGridLines="True">
            <Grid.ColumnDefinitions>
                <ColumnDefinition/><ColumnDefinition/><ColumnDefinition/>
            </Grid.ColumnDefinitions>
            <Grid.RowDefinitions>
                <RowDefinition/><RowDefinition/><RowDefinition/>
            </Grid.RowDefinitions>

            <!-- 動かしてみるためのボタン -->
            <Button Content="平行移動" Grid.Row="0" Grid.Column="0" Click="Button_Click"/>
            <Button Content="拡大縮小" Grid.Row="0" Grid.Column="1" Click="Button_Click_1"/>
            <Button Content="回転" Grid.Row="0" Grid.Column="2" Click="Button_Click_2"/>
            <Button Content="全部" Grid.Row="1" Grid.Column="2" Click="Button_Click_3"/>

            <!-- このGridを回転させる -->
            <Grid x:Name="MyGrid" Grid.Row="1" Grid.Column="1" Background="Pink" RenderTransformOrigin="0.5,0.5">
                <TextBlock Text="あ" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="50"/>
            </Grid>
        </Grid>
    </Grid>
</Window>

cs(コードビハインド)

MainWindow.cs
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;

namespace WpfApp39
{
    /// <summary>
    /// MainWindow.xaml の相互作用ロジック
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        // 平行移動
        private void Button_Click(object sender, RoutedEventArgs e)
        {
            Matrix matrix = (MyGrid.RenderTransform as MatrixTransform).Matrix;
            matrix.Translate(5, 5);
            MyGrid.RenderTransform = new MatrixTransform(matrix);
        }

        // 拡大縮小
        private void Button_Click_1(object sender, RoutedEventArgs e)
        {
            Matrix matrix = (MyGrid.RenderTransform as MatrixTransform).Matrix;
            matrix.Scale(1.1, 1.1);
            MyGrid.RenderTransform = new MatrixTransform(matrix);
        }

        // 回転
        private void Button_Click_2(object sender, RoutedEventArgs e)
        {
            Matrix matrix = (MyGrid.RenderTransform as MatrixTransform).Matrix;
            matrix.Rotate(20);
            MyGrid.RenderTransform = new MatrixTransform(matrix);
        }

        // 全部
        private void Button_Click_3(object sender, RoutedEventArgs e)
        {
            Matrix matrix = (MyGrid.RenderTransform as MatrixTransform).Matrix;
            matrix.Translate(5, 5);
            matrix.Scale(1.1, 1.1);
            matrix.Rotate(20);
            MyGrid.RenderTransform = new MatrixTransform(matrix);
        }
    }
}

before

after

メモ

  • 上記のようにすると、移動/拡大縮小/回転が実現できる。
  • xamlの方で、RenderTransformOriginに0.5,0.5をセットしているが、これをセットすると、Gridのど真ん中を中心(基準)に、回転や拡大が行われる。セットしてないと、Gridの左上基準になる。
  • 例ではmatrix.Scale()などを使っているが、本来やりたかったフリック・ピンチインアウトで移動・拡大縮小をするときは、動きの中心点を指定できるScaleAt()RotateAt()を使うらしい。(フリック・ピンチインアウトのイベントで、指の移動量と、2本指でピンチしたときの中心を採れるから、それをScaleAt()RotateAt()に渡してやると、ええ感じにできるらしい。)
  • MatrixTransformは、本当は「 アフィン変換行列をどうこう」みたいな難しいことをするためのものっぽいが、とりあえず簡単な使い方だけ今回は知っておく。

次は、フリック・ピンチインアウトで画像の移動・拡大縮小する方法を調べる。

コード

参照

Matrix 構造体
https://docs.microsoft.com/ja-jp/dotnet/api/system.windows.media.matrix?view=netframework-4.7.2