WPF の XAML には Clone メソッドがあって、Storyboard とか UI のタグをコピーできたのですが、WinRT の XAML には Clone がありません。継承関係とかすっきりしてメソッドの整理もされいるので、同じ XAML とはいえ挙動が異なる…のが微妙なところですが、まあ、すっきりした分 XAML の描画は高速になっているんだろうなッ!!! と実験してみたいものです。当時、非力…でもないマシンを使っても WPF アプリは結構重かったわけで、では、現在の PC ならばどうでしょうってのが疑問なところですが、描画として XAML と C++/CX の DirectX が直結しているのか否か?そのうえで、GPU は有効に使われているのか?(なんか、CPU のパワーだけを使っている感じがするので)ってのを確かめたうえで、XAML の描画部分を C# のみで頑張るか、C++/CX のパワーを使ったほうが(内部的に DirectX に直結しているという点で)を探っていきたいと思っています。
3Dのアクション系のゲームアプリのように描画速度に完全に依存する場合には、C++/CX と DirectX の組みわせは外せないところなのですが、花札ゲームのような、
- それぞれのアニメーション以外、あまり画面が動かない
- 3D ゲームのようにがっつり作るのではなく、手軽にリリースしたい(サンデープログラマー気分で)。
→ けれども、アニメーション部分は、それなりにリッチにしたい。
→ ロジック部分は、C# を活用するとか、描画じゃない部分をバージョンアップとか。
な形で、View と Logic を完全に分離させた上で、それぞれの速度(描画速度と開発速度)を追求したいということで。
それを踏まえたうえで、リッチな View と作ろうとすると、Blend を使ったデザインが欠かせないわけで、デザイナさまに作っていただいた XAML をいかに、きれにプログラムに組み入れていくのか?ってのが課題。いやいや、デザインするのは自分自身だったりするわけですがね。
■XamlReader.Load を使って、丸ごとコピーする
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | private void SbCloneClick( object sender, RoutedEventArgs e) { string xaml = @" <Image xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation"" HorizontalAlignment=""Left"" Height=""100"" VerticalAlignment=""Top"" Width=""64"" Source=""/Images/FC097-2.png"" Margin=""288,151,0,0""> </Image> " ; for ( int i = 0; i < 10; i++) { object obj = XamlReader.Load(xaml); UIElement el = obj as UIElement; Image img = obj as Image; img.Margin = new Thickness(70 * i, 100, 0, 0); grid.Children.Add(img); } } |
XamlReader.Load を使うときに注意しないといけないのが、
- ルートは単一のタグであること。
- xmlns で名前空間を指定しておく。
- x:Name=”…” のような名前を外しておく
- イベントハンドラは、後からプログラムで指定。
→ Xml の Load と同じなので、ルートタグはひとつ。
→ x の namespace が必須になるし、プログラムから参照できません。
→ FindName を使っても見つかられないので、意味ないし。
なところです。バインディングは、どうなるんだろう?今は試していません。
サンプルのコードでは、Image タグを10個作って、grid に追加しています。これぐらいならば new Image() で作っても手間は変わらないのですが、もうちょっと複雑な例があります。
■Storyboard を XamlReader.Load でコピーする
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | void SbClone() { string xaml = @" <Storyboard Name=""sbMove"" xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation"" > <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty=""(UIElement.RenderTransform).(CompositeTransform.TranslateX)"" Storyboard.TargetName=""pictAni""> <EasingDoubleKeyFrame KeyTime=""0"" Value=""180.597""/> <EasingDoubleKeyFrame KeyTime=""0:0:1"" Value=""182.09""/> </DoubleAnimationUsingKeyFrames> <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty=""(UIElement.RenderTransform).(CompositeTransform.TranslateY)"" Storyboard.TargetName=""pictAni""> <EasingDoubleKeyFrame KeyTime=""0"" Value=""-152.239""/> <EasingDoubleKeyFrame KeyTime=""0:0:1"" Value=""171.642""/> </DoubleAnimationUsingKeyFrames> </Storyboard> " ; object obj = XamlReader.Load(xaml); Storyboard sb = obj as Storyboard; // Storyboard.Target を書き換える foreach ( var tl in sb.Children) { Storyboard.SetTarget(tl, this .pict1); } } |
ある点からある点まで移動するためのアニメーションですが、これをプログラムで書き直すとちょっと手間ですね。複雑な Storyboard を Blend で作成した後に、それをちまちまとプログラムコードに直すのは避けたいところです。
なので、XAML から該当する Storyboard を「手動」でコピーしてきて、コードに貼り付けるって作業ならば、まあ、それなりに許容範囲かと。
ただ、これも問題があって、アニメーションさせる要素を指定するのを、Storyboard.SetTarget を使ってちまちまと書き換えないとダメなんですよね(SetTargetName を使っても名前が設定変更されないので、SetTarget じゃないとダメみたいです)。このあたり、Setter を使う方法もあるんでしょうが、Setter を使うということは、元の Storyboard の XAML に手をいれないといけなくなって、Storyboard を再修正したきの作業手順が多くなってしまうのが難点です。
なので、Storyboard に Clone がないならば、作ってしまおう、ってのが次。