検索
連載

第2回 WPFとXAMLの関係とは? XAMLの基礎を学ぶ連載:WPF入門(1/3 ページ)

WPFアプリケーション開発において実質的にはXAMLに関する知識が必須。WPFとXAMLの関係性をコード例で分かりやすく紹介。XAML構文をまとめる。

Share
Tweet
LINE
Hatena
連載:WPF入門
業務アプリInsider/Insider.NET

powered by Insider.NET

「連載:WPF入門」のインデックス

連載目次

 前回説明したように、「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

List 1: ユーザー定義型のインスタンスをXAMLコードとして保存するサンプル・コード(上:C#、下:VB)
コンソール・アプリケーションとして作成する。ビルドするには、PresentationFrameworkアセンブリ、WindowsBaseアセンブリ、System.Xmlへの参照を追加する必要がある。

 このコードを実行した結果として得られるXAMLコードは、以下のようなものになる。

<Point X="1" Y="2"
  xmlns="clr-namespace:Sample;assembly=SampleLibrary" />

List 2: 上記のコードにおけるPointクラスのインスタンスをXAMLコード化した結果
「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

List 3: XAMLを使わないWPFアプリケーションの例(上:C#、下:VB)

 上記のコードは問題なくビルド可能で、実行するとFigure 1のようなウィンドウが起動する。


Figure 1: XAMLを使わないWPFアプリケーションの実行例

一般的なWPFアプリケーション

 前置きが長くなったが、一般的なWPFアプリケーションの場合を見てみよう。Visual Studioの[新しいプロジェクト]で「WPF アプリケーション」テンプレートを使ってWPFアプリケーション・プロジェクトを作成すると、Figure 2のような状態が得られる(この例では、プロジェクト名は「SampleWpfApplication」としている)。


Figure 2: Visual StudioでWPFアプリケーション・プロジェクトを作成した直後の状態

 ここで、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」になっていることが分かる。


Figure 3: XAMLのビルド・アクション

 (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.

       | 次のページへ
ページトップに戻る