第3回 XAMLコードから生成されるプログラム・コードを理解する ―― XAML(2): WPF固有機能の基礎 ――:連載:WPF入門(1/4 ページ)
XAMLコードから自動生成される中間生成物のプログラム・コード、依存関係プロパティとルーティング・イベントを解説。WPFの内部的な挙動を理解しよう。
powered by Insider.NET
前回は主に、WPFによらないXAMLの一般的な仕組みについて説明を行った。今回からはWPF固有の機能に踏み込んで説明していく。
まず、WPFの内部的な挙動の理解を深めてもらうため、XAMLコードから自動生成される中間生成物のプログラム・コード(C#/VB)について説明を行う。また、プログラムの起点となるApplicationクラス(System.Windows名前空間)に関する説明も行う(Applicationクラスと並んでWPFアプリケーションの基礎となるWindowクラスに関しては、「コントロール」の一種と見なせるため、次回以降、「コントロール」に関する回にて説明を行う)。
さらに、データ・バインディングなどの高度な機能を実現するための要となる「依存関係プロパティ」と「ルーティング・イベント」に関する説明を行う。
■XAMLコードから自動生成される中間生成物のプログラム・コード
前回からの再掲になるが、標準的なWPFアプリケーションの作りをもう一度見てみよう。Visual StudioのテンプレートからWPFアプリケーション・プロジェクトを作成すると、Figure 1に示すような状態が得られるはずだ。
前回は概要のみの説明だったが、今回はもう少し踏み込んで、XAMLコードから自動生成される中間生成物のプログラム・コード(.g.cs/.g.vbファイルなど。詳しくは第1回を参照)について説明していく。
●MainWindow.xamlファイルから生成されるプログラム・コード
MainWindow.xamlファイルの分離コードであるMainWindow.xaml.cs/MainWindow.xaml.vbファイル内に生成されるMainWindowクラスは、名前どおり、アプリケーション起動時に最初に開かれるメイン・ウィンドウで、その実体はWindowクラス(System.Windows名前空間)を継承したクラスである。MainWindowクラスはパーシャル・クラスとなっていて、MainWindow.xamlファイルから自動生成されるプログラム・コードと合わせて1つのクラスとなる。
Visual Studioのテンプレートから生成されたままのMainWindow.xamlファイル(+その分離コード)をビルド(=コンパイル)すると、List 1に示すようなプログラム・コードが(objフォルダ内に「MainWindow.g.cs/MainWindow.g.vb」などの名前で)自動生成される(見やすさを優先して、属性やコメントなどを一部削っている)。
using System.Windows;
using System.Windows.Markup;
namespace SampleWpfApplication
{
public partial class MainWindow : Window, IComponentConnector
{
private bool _contentLoaded;
public void InitializeComponent()
{
if (_contentLoaded) return;
_contentLoaded = true;
System.Uri resourceLocater = new System.Uri(
"/SampleWpfApplication;component/mainwindow.xaml",
System.UriKind.Relative);
System.Windows.Application.LoadComponent(
this, resourceLocater);
}
void IComponentConnector.Connect(int connectionId, object target)
{
this._contentLoaded = true;
}
}
}
Imports System.Windows
Imports System.Windows.Markup
Partial Public Class MainWindow
Inherits Window
Implements IComponentConnector
Private _contentLoaded As Boolean
Public Sub InitializeComponent() Implements IComponentConnector.InitializeComponent
If _contentLoaded Then
Return
End If
_contentLoaded = true
Dim resourceLocater As System.Uri = New System.Uri( _
"/WpfApplication1;component/mainwindow.xaml", _
System.UriKind.Relative)
System.Windows.Application.LoadComponent(
Me, resourceLocater)
End Sub
Sub System_Windows_Markup_IComponentConnector_Connect(ByVal connectionId As Integer, ByVal target As Object) Implements IComponentConnector.Connect
Me._contentLoaded = true
End Sub
End Class
上記のコードを見ると分かるように、Visual Studioテンプレートからの生成時の状態では、XAMLコードのロード以外には特に何も行っていない。
ここで、XAMLコードに記述を追加すると、自動生成されるプログラム・コードに以下のような変化が生じる。
- XAMLコード中でUI要素にName属性を付けると、同名のフィールドが追加され、IComponentConnector.Connectメソッド中での初期化が行われる
- XAMLコード中でイベント・ハンドラの登録を行うと、IComponentConnector.Connectメソッド中でイベント・ハンドラの追加が行われる
- <x:Code>要素を追加すると、要素内の記述がそのまま自動生成されたクラス内部にコピーされる
例えば、MainWindow.xamlファイルをList 2のように書き換えると、自動生成されるプログラム・コードにList 3に示すようなコードが追加される。
<Window x:Class="SampleWpfApplication.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<x:Code><![CDATA[
private void Button_Click(object sender, RoutedEventArgs e)
{
MessageBox.Show("test");
}
]]>
</x:Code>
<StackPanel>
<TextBlock Name="text1" Text="Sample" />
<Button Name="button1" Click="Button_Click" Content="OK" />
</StackPanel>
</Window>
VBの場合は、上記の<x:Code>要素内に記述しているC#のイベント・ハンドラの部分を下記のようにVBのコードに書き直す。
Private Sub Button_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
MessageBox.Show("test")
End Sub
internal System.Windows.Controls.TextBlock text1;
internal System.Windows.Controls.Button button1;
void IComponentConnector.Connect(int connectionId, object target)
{
switch (connectionId)
{
case 1:
this.text1 = ((System.Windows.Controls.TextBlock)(target));
return;
case 2:
this.button1 = ((System.Windows.Controls.Button)(target));
this.button1.Click +=
new System.Windows.RoutedEventHandler(this.Button_Click);
return;
}
this._contentLoaded = true;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
MessageBox.Show("test");
}
Friend WithEvents text1 As System.Windows.Controls.TextBlock
Friend WithEvents button1 As System.Windows.Controls.Button
Sub System_Windows_Markup_IComponentConnector_Connect(ByVal connectionId As Integer, ByVal target As Object) Implements IComponentConnector.Connect
If (connectionId = 1) Then
Me.text1 = CType(target,System.Windows.Controls.TextBlock)
Return
End If
If (connectionId = 2) Then
Me.button1 = CType(target,System.Windows.Controls.Button)
AddHandler Me.button1.Click, _
New System.Windows.RoutedEventHandler( _
AddressOf Me.Button_Click)
Return
End If
Me._contentLoaded = true
End Sub
Private Sub Button_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
MessageBox.Show("test")
End Sub
XAMLコードに記述した<x:Code>要素は、HTMLでいうところの<script>タグによるスクリプト・コードの埋め込みと同じ感覚で利用できるが、実際のところWPFアプリケーション開発ではあまり利用されない。WPFの場合、プログラム・コードは分離コードの中に記述するのが一般的である。
また、XAMLコード中の属性構文で指定した値がプロパティの場合は、(InitializeComponentメソッド内で呼び出されている)LoadComponentメソッド内で自動的に読み出してもらえるが(すなわち、プログラム・コードの自動生成に頼らない、XAML自体の仕様)、その値がイベントの場合には、上記のようなプログラム・コードの追加が必要となる。
続いて、App.xamlファイルから生成されるプログラム・コードについて説明する。
Copyright© Digital Advantage Corp. All Rights Reserved.