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構文についてまとめる。
本題に入る前に、簡単に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
このコードを実行した結果として得られるXAMLコードは、以下のようなものになる。
<Point X="1" Y="2"
  xmlns="clr-namespace:Sample;assembly=SampleLibrary" />
逆に、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ファイル中に書かれているコードは、要約すると以下のようなものである。
それでは、XAMLの基礎について説明していこう。
Copyright© Digital Advantage Corp. All Rights Reserved.