[WPF/xaml]Storyboardでアニメーションをつくる2(TargetPropertyの階層的な指定)


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

Storyboard関連
- [WPF/xaml] xaml+C#で当番決めのためのルーレットを作る
- [WPF/xaml]Storyboardでアニメーションをつくる
- [WPF/xaml]Storyboardでアニメーションをつくる2(TargetPropertyの階層的な指定)

やりたいこと

以前、Storyboardでアニメーションをつくる方法を勉強したが、その中の「DoubleAnimationUsingKeyFrames」でTargetPropertyを指定している部分の、

a.xaml
<DoubleAnimationUsingKeyFrames BeginTime="00:00:00"  Storyboard.TargetName="slider" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(TranslateTransform.X)">

の「(UIElement.RenderTransform).(TransformGroup.Children)[0].(TranslateTransform.X)」の部分が、どういうことを書いているのか実はよくわかってなかった。
この際はっきりさせたい。

以前のコードはこちら参照
https://qiita.com/tera1707/items/a7fcdd95fc3120ae3c8b

調べた時に見たサイト

こちらに、知りたいことはすべて書いてあった。

アニメーション(WPF)(++C++)
https://ufcpp.net/study/dotnet/wpf_xamlani.html
>「TergetProperty を階層的に指定」
>「TergetProperty で配列的にアクセス」

書いてあったが、見るだけでは勉強にならないので、自分なりの理解を書いてみようと思う。

自分なりの理解

別の書き方

Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(TranslateTransform.X)"

Storyboard.TargetProperty="RenderTransform.Children[0].X"
は、同じことを表している。

②を省略せずに正しく書くと、①の書き方になる。

②の意味合い

②は、日本語でいうと、下記のようなことを表している。

  • 対象(ここではRectangle(名前はslider))に含まれている、
  • RenderTransformにセットされているもの(Childrenの0番目)の、
  • Xをターゲットプロパティにする。

②で省略していること

②の書き方では。いろいろと省略されていることがある。

  • RenderTransformは正しく言うと、UIElementクラスで定義されているメンバRenderTransformである。
  • Childrenは正しく言うと、TransformGroupクラスで定義されているメンバChildrenである。
  • Xは正しく言うと、TranslateTransformクラスで定義されているメンバXである。

①の意味合い

で、書き方としては、省略しているものを省略無しで正しく書こうとするとカッコ()を付けるようなので、

  • RenderTransform → (UIElement.RenderTransform)
  • Children     → (TransformGroup.Children)
  • X         → (TranslateTransform.X)

となり、それぞれをつなげると、つまり①の内容になる。

21/05/30追記
★カッコを付けるのは、下記のためかも。

添付プロパティにバインドするには、添付プロパティをかっこで囲みます。 たとえば、添付プロパティ DockPanel.Dock にバインドする構文は Path=(DockPanel.Dock) です。

前提

①または②のように書くと、Storyboardは動いてくれるのだが、前提として対象のRectangle(名前はslider)のRenderTransformに、

「TranslateTransform」をセットした「TransformGroup」がセットされてないと、例外で動かなかった。これは、"RenderTransform.Children[0].X"の中の右半分、「.Children[0].X」が存在しなかったからと思われる。

自分で意図してセットしないと、RectangleのRenderTransformにはなにも入っていないので、Storyboardでターゲットプロパティとして指定するためには、「Storyboard動作時に」TranslateTransformが入ったTransformGroupがセットされていることが前提となる。
(セットしてなくても、アプリ起動時には落ちない。Storyboard動作時に落ちる。)

(UIElement.RenderTransform)の「UIElement」はどこから来た?

今回のstoryboardのターゲットはRectangleで、そのRectangleは「UIElement」を継承してできている。

Rectangle Class
https://docs.microsoft.com/ja-jp/dotnet/api/system.windows.shapes.rectangle?view=netframework-4.8

UIElementクラスで「RenderTransform」は定義されいているので、「(UIElement.RenderTransform)」と書く。

※ためしに、(UIElement.RenderTransform)のところを(FrameworkElement.RenderTransform)とか(Shape.RenderTransform)とか書いても動くのは動く。

自分なりの結論

a.xaml
<DoubleAnimationUsingKeyFrames BeginTime="00:00:00"  Storyboard.TargetName="slider" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(TranslateTransform.X)">

上記のStoryboard.TargetPropertyの書き方は、省略をせずに、階層的にプロパティを書いたものだった。

別の例

別の例として、背景の色を時間を追って変化させたいときに、下記のようにColorAnimationUsingKeyFrames を書いたとする。

a.xaml
<ColorAnimationUsingKeyFrames  BeginTime="00:00:00"  Storyboard.TargetName="BackgroundBorder" Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)">

この中のStoryboard.TargetPropertyは、

  • 対象に含まれている、
  • Backgroundにセットされているもの(SolidColorBrush)の、
  • Colorをターゲットプロパティにする。

ということ。省略して書くと、

a.xaml
<ColorAnimationUsingKeyFrames  BeginTime="00:00:00"  Storyboard.TargetName="BackgroundBorder" Storyboard.TargetProperty="Background.Color">

となる。またこの場合も、対象(ここではBackgroundBorderという名前のBorder)のBackgroundがあらかじめ設定されていないと例外で落ちる。

この書き方をAttributeSyntaxというらしい.xaml
<!-- ここで、Background="Gray"がないとStoryboard実行時に落ちる -->
<Border Name="BackgroundBorder" CornerRadius="2" Height="28" Width="60" BorderBrush="White" BorderThickness="2" Background="Gray"/>

Background="Gray"は、Border のBackgroundに、グレー色のSolidColorBrushがセットされている、ということを示す。
(xamlが勝手にそういうことをしてくれている)

それがないと落ちてしまうのは、Storyboardが変化させようとするColorを持っているSolidColorBrushが存在しないからだと思われる。

Background="Gray"は、Border のBackgroundに、グレー色のSolidColorBrushがセットされている」というのは、個人的には下記のように書くとイメージが湧きやすかった。

この書き方を「PropertyElementSyntax」というらしい.xaml
<Border Name="BackgroundBorder" CornerRadius="2" Height="28" Width="60" BorderBrush="White" BorderThickness="2">
    <Border.Background>
        <SolidColorBrush Color="Gray"/>   <!-- ←これがないと、storyboardが設定するものがなくて落ちてしまう。 -->
    </Border.Background>
</Border>

参照

アニメーション(WPF)(++C++)
https://ufcpp.net/study/dotnet/wpf_xamlani.html
>「TergetProperty を階層的に指定」
>「TergetProperty で配列的にアクセス」

XAML の基本構造(WPF)
Attribute SyntaxとかProperty Element Syntaxとか
https://ufcpp.net/study/dotnet/wpf_xamlbasic.html?key=attribute#attribute
>「プロパティの設定」