Visual Studio 2008 Express Editionの本を読んでいて、ときどき「WPF(Windows Presentation Foundation)アプリケーション」だとか「XAML(eXtensible Application Markup Language)」なる用語は目に留まってはいた。ただ、それほど興味はなった。
それと言うのも、「要するに、見栄えを良くする、というだけの話だろう」と思っていたからだ。従来のWindowsの画面描画は2Dが基本になっていて、Windows Vista以降では3Dが基本(?)になっている。WPFでは、この新しい方の描画方法が使える。プログラミング入門書には、ラベルに角度をつけたり、テキストに陰をつけたり、ボタンの色をグラデーションにしたり、画像をスキュー(skew)させたり…、といった例がよく載っている。正直、そんなことはプログラミングの本質(と僕が考えているもの)とは関係ないので興味がなかったのだ。
XAMLは、画面の要素(ラベルだとかボタンだとか)を記述するマークアップ言語で、HTMLに似ている(HTMLにプログラミング要素を追加したもの?)。WEBアプリケーションの世界では、画面のデザインを行うグラフィックデザイナーと、プログラムの動作ロジックを記述するプログラマーの共同作業になるので、画面のデザインの記述をXAMLとして独立させてしまうことで作業の効率化を図る、という趣旨なのだと思う。そういうものが、WEBアプリケーションだけでなくWindowsアプリケーションの世界にも押し寄せてきた、そんな感じの理解。
ところが、先日『
基礎Visual Basic 2008』(羽山博(著) 2008年 インプレスジャパン)を眺めていて、驚くことを知った。全てではないだろうが、これまでプログラムとして書かれていたものが、XAMLとして記述できるようなのだ。
例えば、画面にラベル(lblMessage)を1つ、ボタン(btnRotate)を1つ配置し、各種プロパティを設定すると、以下のような「Windows1.xaml」というファイルが作られる。
※ 以下の例では、半角の「<」「>」を全角の「<」「>」に変更しています。また、半角スペースを全角スペースに置き換えている箇所があるので、そのままではコピー&ペーストしても動きません。
<Window x:Class="Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="200" Width="300">
<Grid>
<Label Height="28" Margin="98,48,99,0" Name="lblMessage"
VerticalAlignment="Top" HorizontalAlignment="Center">
Hello! WPF!
</Label>
<Button Height="23" HorizontalAlignment="Left"
Margin="45,0,0,27" Name="btnRotate"
VerticalAlignment="Bottom" Width="75" IsDefault="True">
回転(_R)
</Button>
</Grid>
</Window>
で、従来のやり方だと、ボタンをクリックしたときの処理は「Window1.xaml.vb」というファイルの方に記述する。
Imports System.Windows.Media.Animation
Class Window1
Private Sub btnRotate_Click(ByVal sender As System.Object,
ByVal e As System.Windows.RoutedEventArgs)
Handles btnRotate.Click
Dim rt As RotateTransform = New RotateTransform()
lblMessage.RenderTransformOrigin = New Point(0.5, 0.5)
lblMessage.RenderTransform = rt
Dim anim As DoubleAnimation = New DoubleAnimation()
anim.From = 0
anim.To = 360
anim.Duration = New Duration(TimeSpan.FromMilliseconds(3000))
Me.RegisterName("rotate", rt)
Storyboard.SetTargetName(anim, "rotate")
Storyboard.SetTargetProperty(anim, New
PropertyPath("(RotateTransform.Angle)"))
Dim stb As Storyboard = New Storyboard()
stb.Children.Add(anim)
stb.Begin(lblMessage)
End Sub
End Class
これで、ボタンをクリックすると、画面中央の「Hello! PMF!」というラベルが回転するようになる。
ちなみに、同じことをVisual Basicではなく、Visual C#でやろうとすると、
using System;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Animation;
namespace WpfApplication1 {
public partial class Window1 : Window {
public Window1() {
InitializeComponent();
}
private void btnRotate_Click(object sender, RoutedEventArgs e) {
RotateTransform rt = new RotateTransform();
lblMessage.RenderTransformOrigin = new Point(0.5, 0.5);
lblMessage.RenderTransform = rt;
DoubleAnimation anim = new DoubleAnimation();
anim.From = 0;
anim.To = 360;
anim.Duration = new Duration(TimeSpan.FromMilliseconds(3000));
this.RegisterName("rotate", rt);
Storyboard.SetTargetName(anim, "rotate");
Storyboard.SetTargetProperty(anim, new
PropertyPath("(RotateTransform.Angle)"));
Storyboard stb = new Storyboard();
stb.Children.Add(anim);
stb.Begin(lblMessage);
}
}
}
と、(当然だが)C#の文法に沿ってコードを書き直さなければならない。
この「Window1.xaml」と「Window1.xaml.vb」(あるいは「Window1.xaml.cs」)を2つのファイルに分けずに、全て「Window1.xaml」の方に記述してしまえるのである。つまり、
<Window x:Class="Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="200" Width="300">
<Grid>
<Label Height="28" Margin="98,48,99,0" Name="lblMessage"
VerticalAlignment="Top" HorizontalAlignment="Center"
RenderTransformOrigin="0.5,0.5">
<Label.RenderTransform>
<RotateTransform x:Name="rotate" />
</Label.RenderTransform>
Hello! WPF!
</Label>
<Button Height="23" HorizontalAlignment="Left"
Margin="45,0,0,27" Name="btnRotate"
VerticalAlignment="Bottom" Width="75" IsDefault="True">
<Button.Triggers>
<EventTrigger RoutedEvent="Button.Click">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetName="rotate"
Storyboard.TargetProperty="(RotateTransform.Angle)"
From="0.0" To="360.0" Duration="0:0:3" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Button.Triggers>
回転「(_R)
</Button>
</Grid>
</Window>
こうなる。
これが僕にとって衝撃だったのは、まず、Visual BasicとVisual C#で全く同じ記述のファイルが1つだけあれば良い、という点。そして何よりも、「Windows1.xaml.vb」(あるいは「Window1.xaml.cs」)に記述されているコードが、「ボタンをクリックしたときに行う処理」を(オブジェクトをガンガン使ってはいるものの、基本的には)「手続き指向」的に記述したものであり、1行目から順に実行されていくものであるのに対して、「Window1.xaml」に記述されているコードが、同じことを「ボタン自身の振る舞い」として、処理の(時間的な意味での)順序に依存しないかたちで記述されている点である。つまり、処理を「オブジェクト指向」的に記述することにより、「Windows1.xaml」からは「時間性」が消え失せてしまっているのである。
プログラミングの面倒臭さの一因は、「処理の順序」を守らねばならないことだと思う。ところが、「Window1.xaml」の記述を見ると、「概念的な上下関係」という次元は「ネスト構造における位置」として記述されているものの、「処理の順序」という次元が奇麗に消されている。
XAMLのプログラム例を初めて見たときは、そのあまりのインデントの深さに正直ウンザリしただけだったのだが、そこに(通常上から下に流れる)
「時間軸」が存在していないことに気づいたとき、見え方が全く変わってしまった。プログラミング言語が大きく変わっていく瞬間を目にしたように思う。

2