nuits.jp blog

C#, Xamarin, WPFを中心に書いています。Microsoft MVP for Development Technologies。

WPFのRenderTransformとLayoutTransformの違いについて

WPFのTransformクラスには画面要素を変形するためのいくつかの機能が用意されており、拡大縮小なんかを簡単に実現することができます。
仕事がら、これを使って画像ビューアなんかを良く作っているのですが、うっかりしていて少しハマったのでメモを残しておきます。

Transformクラスには以下の4つのサブクラスがあり、画面要素を容易に変形させることができます。

クラス 振る舞い
RotateTransform 回転
ScaleTransform 拡大縮小
SkewTransform 傾き制御
ScaleTransform 画面内の座標移動

これらは、各画面要素の子要素としてRenderTransformか、LayoutTransformを宣言し、その子要素として設定することで提供されます。
この時、RenderTransformを利用するか、LayoutTransformを利用するかで振る舞いが変わります。
MSDNのそれぞれの記述を比較してみると以下の通りになります。

クラス 振る舞い
RenderTransform 描画変換では、レイアウト サイズや描画サイズの情報は再生成されません。
LayoutTransform RenderTransform とは対照的に、LayoutTransform はレイアウトの結果に影響します。

ちょっと分かり難いですが、結果を見ればすぐわかります。

まずはTransformしないケースです。

<ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
    <Image Source="Resources/image.png" Stretch="None"/>
</ScrollViewer>

ScrollViewer内に画面より大きな画像を配置します。
表示結果は以下のようになります。

f:id:nuitsjp:20160729174343p:plain

画像が大きいため、スクロールバーが表示されているのが見て取れます。
では次に、LayoutTransformを利用して画面内に画像が収まるように縮小します。

<ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
    <Image Source="Resources/image.png" Stretch="None">
        <Image.LayoutTransform>
            <ScaleTransform ScaleX="0.2" ScaleY="0.2"/>
        </Image.LayoutTransform>
    </Image>
</ScrollViewer>

こんな感じでTransformを適用します。
動作結果はこんな感じです。

f:id:nuitsjp:20160729174605p:plain

想定通りですね。
画面内に画像が収まり、スクロールバーも非表示になっています。

では、RenderTransformだとどうなるでしょう?

<ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
    <Image Source="Resources/image.png" Stretch="None">
        <Image.RenderTransform>
            <ScaleTransform ScaleX="0.2" ScaleY="0.2"/>
        </Image.RenderTransform>
    </Image>
</ScrollViewer>

実行結果はこうなります。

f:id:nuitsjp:20160729175107p:plain

ちょっと違和感がありますね。
スクロールバーが表示されており、「縮小される前の画像サイズと同じだけ」実際にスクロールできてしまいます。

つまりRenderTransformは次の特徴を持っているわけです。

  • レイアウト決定後に変形が適用されるため、依存する画面要素が再配置されない
  • その代わり、高速に動作する

なんとなしに、RenderTransformを利用していて、ちょっと何でだったか気が付かずにはまりました。

と言う分けで今日はここまで。 それではまた!