第2回 WPFとXAMLの関係とは? XAMLの基礎を学ぶ:連載:WPF入門(1/3 ページ)
WPFアプリケーション開発において実質的にはXAMLに関する知識が必須。WPFとXAMLの関係性をコード例で分かりやすく紹介。XAML構文をまとめる。
powered by Insider.NET
前回説明したように、「XAML(Extensible Application Markup Language)」と呼ばれる宣言的言語がWPFアプリケーション開発の中核となっている。もちろん(XAMLを使わない)C#やVB(Visual Basic)などのプログラミング言語だけを用いたWPFアプリケーション開発も可能ではあるが、XAMLの利用にはさまざまな利点があり、実質的にはWPFアプリケーション開発においてXAMLに関する知識が必須であるといえる。
そこで、今回から数回にわたってXAMLに関する解説を行っていく。今回は、まず、WPFとXAMLの関係性についてと、XAMLの基本的な部分(特に、WPFによらないXAML固有の部分)について解説する。また本稿の最後では、XAML構文についてまとめる。
■WPFとXAMLの関係性
本題に入る前に、簡単にXAMLの実態について触れておこう。
●XAML=「CLRオブジェクトのインスタンス生成」
これまで「WPFアプリケーションの視覚的な部分はXAMLを使って記述する」と説明してきた。しかし、「XAMLはWPFのためだけのものか?」というと、そうではない。実のところ、XAMLというのは、「CLRにおけるオブジェクトのインスタンス(以降、CLRオブジェクト)を生成するためのマークアップ言語」である。従って、WPF以外にも、例えばWF(Windows Workflow Foundation)でも、ワークフローの記述にXAMLを利用している。
●CLRオブジェクトとXAMLコードの双方向変換
C#/VBコードによりユーザーが定義した型は、XAML形式でシリアライズ/デシリアライズすることが可能である。つまり、「C#/VBコードによるCLRオブジェクトのインスタンス生成」は「XAMLコード」として保存できる。
例えば以下のC#/VBコードは、ユーザー定義のPointクラス(=CLRオブジェクト)をXAMLコードにシリアライズするサンプル・プログラムである。
using System.IO;
using System.Windows.Markup;
namespace Sample
{
public class Point
{
public int X { get; set; }
public int Y { get; set; }
}
}
class Program
{
static void Main(string[] args)
{
var x = new Sample.Point { X = 1, Y = 2 };
using (var stream = File.Open("test.xaml", FileMode.Create))
XamlWriter.Save(x, stream);
}
}
Imports System.IO
Imports System.Windows.Markup
Namespace Sample
Public Class Point
Public Property X As Integer
Public Property Y As Integer
End Class
End Namespace
Module Program
Sub Main()
Dim x = New Sample.Point With {.X = 1, .Y = 2}
Using stream = File.Open("test.xaml", FileMode.Create)
XamlWriter.Save(x, stream)
End Using
End Sub
End Module
コンソール・アプリケーションとして作成する。ビルドするには、PresentationFrameworkアセンブリ、WindowsBaseアセンブリ、System.Xmlへの参照を追加する必要がある。
このコードを実行した結果として得られるXAMLコードは、以下のようなものになる。
<Point X="1" Y="2"
xmlns="clr-namespace:Sample;assembly=SampleLibrary" />
「SampleLibrary」の部分には、実際にはPointクラスが定義されているアセンブリ名が入る。
逆に、XAMLコードからCLRオブジェクトにデシリアライズするには、XamlReader.Loadメソッドを用いる。
●XAMLを使わないWPFアプリケーション
また、XAMLで書けるものは、原理的にC#/VBなどの任意の.NET言語だけで書くこともできる。WPFの場合も例外ではなく、あまり一般的ではないが、C#/VBなどの.NET言語のみでWPFアプリケーションを作成可能である。
例えば、Visual Studioの[新しいプロジェクト]ダイアログでWPFアプリケーションを作成した後、最初からプロジェクトに含まれているApp.xamlファイルやMainWindow.xamlファイルなどを一度すべて削除して、MainWindow.cs/MainWindow.vbファイルを新規作成し、そのファイルに以下のようなC#/VBコードを記述してみてほしい。
using System;
using System.Windows;
using System.Windows.Controls;
public class MainWindow : Window
{
public MainWindow()
{
this.Content =
new Grid
{
Children = {
new StackPanel {
Children = {
new Menu { Items =
{ new MenuItem { Header = "メニュー" } } },
new Button { Content = "ボタン" },
new CheckBox { Content = "チェックボックス" },
new ComboBox { Items =
{ "コンボボックス" }, SelectedIndex = 0 },
new RadioButton { Content = "ラジオボタン" },
new Slider(),
new ListBox { Items = {
"リストボックス項目1",
"リストボックス項目2",
}}}}}};
}
[STAThread]
static void Main(string[] args)
{
var app = new Application();
app.Run(new MainWindow
{ Title = "サンプル", Width = 300, Height = 300, });
}
}
Imports System.Windows
Imports System.Windows.Controls
Public Class MainWindow
Inherits Window
Public Sub New()
Dim panel = New StackPanel
Dim menuCtrl = New Menu
menuCtrl.Items.Add(New MenuItem With {.Header = "メニュー"})
panel.Children.Add(menuCtrl)
panel.Children.Add(New Button With {.Content = "ボタン"})
panel.Children.Add(New CheckBox With
{.Content = "チェックボックス"})
Dim comboCtrl = New ComboBox With {.SelectedIndex = 0}
comboCtrl.Items.Add("コンボボックス")
panel.Children.Add(comboCtrl)
panel.Children.Add(New RadioButton With
{.Content = "ラジオボタン"})
panel.Children.Add(New Slider())
Dim listCtrl = New ListBox
listCtrl.Items.Add("リストボックス項目1")
listCtrl.Items.Add("リストボックス項目2")
panel.Children.Add(listCtrl)
Dim gridCtrl = New Grid
gridCtrl.Children.Add(panel)
Me.Content = gridCtrl
End Sub
<STAThread()>
Shared Sub Main()
Dim app = New Application()
app.Run(New MainWindow With
{.Title = "サンプル", .Width = 300, .Height = 300})
End Sub
End Class
上記のコードは問題なくビルド可能で、実行するとFigure 1のようなウィンドウが起動する。
●一般的なWPFアプリケーション
前置きが長くなったが、一般的なWPFアプリケーションの場合を見てみよう。Visual Studioの[新しいプロジェクト]で「WPF アプリケーション」テンプレートを使ってWPFアプリケーション・プロジェクトを作成すると、Figure 2のような状態が得られる(この例では、プロジェクト名は「SampleWpfApplication」としている)。
ここで、WPFに不慣れな人は以下の2点を疑問に思うかもしれない。
(1)Mainメソッドがない
(2)どこにも定義が見当たらないInitializeComponentというメソッドを呼び出している
前回説明したように、WPFでは、XAMLコードからBAMLコードとC#コードを生成している(VBのプロジェクト・テンプレートを使った場合には、当然、BAMLコードとVBコードが生成される)。MainやInitializeComponentなどのメソッドは、XAMLコードから自動生成されたC#コードの中で定義されている。
このXAMLコードからのBAMLコードおよびC#コードの生成は、Visual Studio(正確には付属のビルド・ツールであるMSBuild)が担っている。Figure 3に示すように、XAMLファイルのプロパティを表示すると、[ビルド アクション]が「Page」になっていることが分かる。
(MainWindow.xamlファイルに対する)Pageビルド・アクションの中間生成物となるBAMLコードおよびC#コードは、プロジェクト・フォルダの下のobjフォルダの中に、それぞれMainWindow.bamlおよびMainWindow.g.csというファイル名で出力されている。一度ファイルの中身を見てみるのもいいだろう。
同様に、App.xamlファイルに対しても、App.bamlおよびApp.g.csというファイルが生成されているはずだ。生成された.g.csファイル中に書かれているコードは、要約すると以下のようなものである。
- Mainメソッド内でAppクラスのインスタンスを生成し、そのRunメソッドを実行する(起動時に表示されるウィンドウは、App.xamlファイルで<Application>タグのStartupUri属性に設定されたMainWindow.xamlファイルのもの)
- MainWindow.xamlファイル内でName属性付きで書かれたUI要素をMainWindowクラスのメンバ変数として定義(※WPFウィンドウ上にUI要素を配置した場合)
- MainWindowクラスのInitializeComponentメソッド内でBAMLコードをロードする
それでは、XAMLの基礎について説明していこう。
Copyright© Digital Advantage Corp. All Rights Reserved.