[WinRT] XAML タグを XmlReader.Load を使ってコピーする

list このエントリーをはてなブックマークに追加

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 を使って、丸ごとコピーする

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 を使うときに注意しないといけないのが、

  • ルートは単一のタグであること。
  •  → Xml の Load と同じなので、ルートタグはひとつ。

  • xmlns で名前空間を指定しておく。
  • x:Name=”…” のような名前を外しておく
  •  → x の namespace が必須になるし、プログラムから参照できません。

     → FindName を使っても見つかられないので、意味ないし。

  • イベントハンドラは、後からプログラムで指定。

なところです。バインディングは、どうなるんだろう?今は試していません。
サンプルのコードでは、Image タグを10個作って、grid に追加しています。これぐらいならば new Image() で作っても手間は変わらないのですが、もうちょっと複雑な例があります。

■Storyboard を XamlReader.Load でコピーする

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 がないならば、作ってしまおう、ってのが次。

カテゴリー: C#, WinRT パーマリンク