もくじ
→https://qiita.com/tera1707/items/4fda73d86eded283ec4f
Storyboard関連
- [WPF/xaml] xaml+C#で当番決めのためのルーレットを作る
- [WPF/xaml]Storyboardでアニメーションをつくる
- [WPF/xaml]Storyboardでアニメーションをつくる2(TargetPropertyの階層的な指定)
やりたいこと
以前、Storyboardでアニメーションをつくる方法を勉強したが、その中の「DoubleAnimationUsingKeyFrames」でTargetPropertyを指定している部分の、
<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)
とか書いても動くのは動く。
自分なりの結論
<DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="slider" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(TranslateTransform.X)">
上記のStoryboard.TargetPropertyの書き方は、省略をせずに、階層的にプロパティを書いたものだった。
別の例
別の例として、背景の色を時間を追って変化させたいときに、下記のようにColorAnimationUsingKeyFrames を書いたとする。
<ColorAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="BackgroundBorder" Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)">
この中のStoryboard.TargetPropertyは、
- 対象に含まれている、
-
Background
にセットされているもの(SolidColorBrush
)の、 -
Color
をターゲットプロパティにする。
ということ。省略して書くと、
<ColorAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="BackgroundBorder" Storyboard.TargetProperty="Background.Color">
となる。またこの場合も、対象(ここではBackgroundBorderという名前のBorder)のBackgroundがあらかじめ設定されていないと例外で落ちる。
<!-- ここで、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
がセットされている」**というのは、個人的には下記のように書くとイメージが湧きやすかった。
<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
>「プロパティの設定」