• 検索結果がありません。

グラフィックス 目次

N/A
N/A
Protected

Academic year: 2021

シェア "グラフィックス 目次"

Copied!
45
0
0

読み込み中.... (全文を見る)

全文

(1)

■ 第1 回 愈々WPF の時代。WPF の習得を始めよう ■

WPF(Windows Presentation Foundation)は、.NET Framework に含まれるプレゼンテーション層 技術(GUI 開発ライブラリ)で有る。

WPF はバージョン 3.0 以降の.NET Framework に標準搭載されて居る。其れより前の GUI 開発ライブ ラリで有るWindows フォームが、単に Win32 API をマネージコードでラップした物で有るのに対して、 WPF はマネージコードで新たに実装された GUI 開発ライブラリで有り、豊かなユーザー体験を提供す る先進的なGUI 開発基盤で有る(詳細後述)。

.NET Framework が 3.0、3.5、4 とバージョンアップし、WPF は既に 3 世代目を迎える。此れ迄 Windows フォームからの移行が中々進まなかったWPF だが、標準で提供される機能も増え、Visual Studio に依 る開発サポートも充実し、実用するのに必要充分な環境が漸く整った。愈々WPF の時代が遣って来た と謂っても過言では無いだろう。 其処で、本稿を通じて、是非共WPF を学んで欲しい。今回は、WPF の概要に付いて説明する。 ■ WPF の特徴と利点 グラフィックスハードウェア WPF は、コアの部分にグラフィックスハードウェアを活用したベクターベースのレンダリングエンジ ンを採用して居る。ベクターベースで有る為、UI 要素にスムーズな拡大・縮小/回転を掛ける事が出来 る。亦、ハードウェアアクセラレーションに依り、CPU への負担を最小限に抑えて居る。 コントロール、メディア、文書の統合 WPF は、ボタンやリストボックス等のコントロール、ラスター画像やベクターグラフィックス、頂点 メッシュを用いた3D 描画、動画等のメディア、リッチテキスト等の整形済み文書に対して、統一的な 開発機能を提供する。夫々に別個のプログラミングモデルを覚える必要が無い丈では無く、例えば、ボ タンの中に動画を表示すると謂った組み合わせも簡単に行える。 UI カスタマイズの柔軟性 既存のGUI 開発ライブラリでは、ボタン等の UI 要素をカスタマイズするにしても、サイズや背景色の 変更程度の機能しか持って居ない物も多い。 此れに対してWPF では、例えば任意の形状のボタンを作成したり、背景に動画を流したり、動的に回 転や拡大・縮小を行ったりと謂った非常に柔軟なカスタマイズが可能で有る。 観た目(外観デザイン)とロジックの分離

WPF では XAML(Extensible Application Markup Language)と呼ばれる、XML 形式の宣言的言語 を用いてユーザーインターフェイスを記述する。観た目(外観デザイン)に関する部分を XAML 言語

W

(2)

で記述し、ロジックを C#言語等を用いて記述する事で、アプリケーションの観た目に関する部分をロ ジックから完全に切り離す構造に成って居る。此れは、ビジュアルデザイナーとロジック開発者との協 業を意識した物で有る。 ■ プログラミングモデル WPF では、以下の様なプログラミングモデルに基づいた開発を行う事に成る。 ・XAML コード+分離コード ・ツリー構造のUI 要素 ・データバインディング プログラミングモデルに関して、1 つ特筆す可き事が有る。クロスプラットフォームな RIA(Rich Internet Application)開発環境で有る Silverlight も WPF と同じプログラミングモデルに基づいて居 ると謂う点だ。WPF と Silverlight では、流石にソースコードの丸々コピーで動くと謂う事は無いが、 プログラミングモデルにさえ慣れ親しんで了えば相互の移植は簡単で有る。 其れでは、此等の詳細付いて説明して行く事にする。 XAML コード+分離コード 前述した通り、WPF では、XAML 言語と、C#等のプログラミング言語を用いてアプリケーションを開 発する。XAML 言語で記述した観た目の部分に加えて、ロジックが必要な場合には、Figure 1 に示す 様に、C#等で記述する(「分離コード」と呼ぶ)。 Figure 1: XAML コード+(C#等の)分離コード XAML コードと、其れに付随する(C#等の)分離コードは、ビルド時に 1 つのクラスに合成され(部 分クラスと謂う機能を用いて居る)、コンパイルされる。例として、Page1 と謂う名前のビューを作っ た場合、ビルド時の流れはFigure 2 の様に成る。

(3)

Figure 2: XAML コード+(C#等の)分離コードのビルドの流れ

図中に登場するBAML は Binary Application Markup Language と呼ばれる物で、ファイルサイズの 縮小と読み込み負荷の軽減を目的としてXAML コードをバイナリ化した物で有る。BAML コードはリ ソースとして実行可能ファイル(.exe ファイル)に埋め込まれる。 亦、中間生成物の.g.cs ファイルは、XAML コード内で定義した UI 要素(ボタンやテキストボックス等) を(C#等の)分離コード側から参照する為のコードや、BAML コードを読み込む為のコードを含んで 居る。 此の様な、XAML コードと(C#等の)分離コードを分ける事には以下の利点が有る。 1.ビジュアルデザイナー向けのツールを用いた外観デザインが容易 2.UI 要素の階層が深く成った場合に、(一般的なプログラミング言語よりも)階層構造を把握し易い 3.Web 開発で一般的に用いられて居る HTML+JavaScript に似た感覚でアプリケーションを開発可能 4.C#の様なプログラミング言語では書けない、或いは、書き難い記述が容易 1 と 2 は XML 形式を用いる事に依る利点で有る。XML のコードはツールでの解析が容易で有り、亦、 階層的なデータ構造を取り扱うのに向いて居る。3 に関して、Web 開発に於ける HTML+JavaScript の流行は「観た目とロジックの分離が容易で有る」と謂う利点が支持されたと謂う側面が有る。WPF のXAML+分離コード(C#等)と謂う構成は此の流れを汲む物だ。4 に関しては、詳細は後述する事に 成るが、依存関係プロパティやデータバインディングと呼ばれる機能が此れに該当する。 続いて、ツリー構造のUI 要素を説明する。 ツリー構造のUI 要素 Figure 3 に模式的に表す様に、WPF の UI 要素はツリー構造に依り構築される。

(4)

Figure 3: ツリー構造の UI 要素 此の例では、Canvas 要素を入れ子にして居るが、WPF ではボタン等のコントロールの中身も入れ子に する事が出来る。例えば、ボタンの中に動画を配置したり、コンボボックスの中にボタンを並べたりす る事も可能だ。 此の様なWPF のツリー構造の UI 要素では、要素の親子関係に依って以下の様な事が起こる。 ・平行移動や回転等の変形は、親要素からの相対位置に基づいて、子要素諸共行われる ・添付プロパティと謂う仕組みを用いて、要素自身ではなく、親要素が使う情報を持てる ・FontSize 等、一部のプロパティは親要素から値を継承する(包含継承)

先ず、Figure 4 に平行移動の例を示す。亦、Figure 4 の平行移動に加えて、回転も掛けた物を Figure 5 に示す(簡便性の為、回転に関係の無いプロパティは省略)。孰れも、位置指定(Canvas.Left 属性や Canvas.Top 属性等)は親要素からの相対指定と成って居る。亦、回転は子要素共々行われて居る事が 解る。

(5)

Figure 5: UI 要素の回転

此処で、Figure 4 の例に注目して欲しい。入れ子に成った Canvas 要素や Rectangle 要素が Canvas.Top 属性とCanvas.Left 属性を持って居る事に気付くだろう。此等の属性値は、要素自身ではなく、1 段上 の親に当たるCanvas 要素が使用する。此の親 Canvas 要素は、座標を指定して任意の位置に子要素を 配置する為のコンテナだが、其の子要素の座標指定は子要素にCanvas.Left 属性と Canvas.Top 属性を 付与する事で行う。 此の様な、自分自身ではなく、親要素が使用する値を子要素に付与する為の仕組みを「添付プロパティ」 (Attached Property)と呼ぶ。通常の意味での(詰まり.NET のクラスの)プロパティでは、此の仕組 みを素直に実現する事は出来ない。 勿論、総てのUI 要素が Left プロパティ及び Top プロパティを持つ事でも可能では有るが、然うして了 うと、Canvas 要素を利用しない場合に無駄なデータを持つ事に成って了う。其処で WPF では、添付 プロパティや後述するデータバインディングを実現する為の機能として「依存関係プロパティ」 (Dependency Property)と謂う仕組みを持って居る。依存関係プロパティの詳細に付いては次回以降 で説明する事に成るが、簡単に謂うと、一種の辞書構造を用いて値を保持する仕組みで有る。 扨て、最後に、値の包含継承に付いて説明して置く。HTML コードを書いた事が有るなら解るだろうが、 HTML では親要素に書いた属性値が子要素に継承される事が有る。例えば、body 要素に対して style 属性やfont 属性でフォントサイズを指定すると、body 要素内の総ての要素のフォントサイズが変化す る。 WPF でも此の様な仕組みを採用して居り、FontSize プロパティ等、一部のプロパティ値を(プロパテ ィ定義時の指定次第で)親要素から継承する様に成って居る。オブジェクト指向に於ける「継承」(ク ラスの継承)と区別する為に、此れを「包含継承」と呼ぶ。 データバインディング WPF では、ビュー(データの表示)とモデル(データの不整合が無いかの検証や、データベース等へ のデータの永続化)を分離する為の仕組みとして、データバインディングと謂う機能を提供して居る。 データバインディングでは、ビュー側には「此処に此のデータを表示し度い」と謂う様な目印丈を入れ、 実際のデータは外部から与える事に成る。

(6)

Figure 6: データ・バインディングの例

Figure 6 に例示する様に、XAML コード内で、属性値に「{Binding}」と謂う記述を行う。実際に表示 し度いデータは、DataContext と謂うプロパティを介して渡す事に成る。例えば、上記の例の場合、 DataContext プロパティに渡された Point 型データの X プロパティと Y プロパティの値を、Button 要 素のContent 属性に結び付ける。値の結び付けはリフレクションを用いて行われて居り、DataContext には任意の型を渡す事が出来る。 此の仕組みを旨く利用すれば、ビューとモデルの接点はDataContext プロパティの只 1 点而巳と成り、 疎結合が実現出来る。亦、ビューの内部には一切ロジックを持つ必要が無い(即ち、ビューの分離コー ド内にはロジック用のコードを一切書かない)。 詳細は次回以降の説明と成るが、モデル側で、データの更新通知や、ユーザーから入力されたデータの 妥当性検証を行う仕組みが提供されて居る(INotifyPropertyChanged インターフェイスや依存関係プ ロパティと謂う仕組み等を用いる)。 Figure 7 にデータの更新通知の例を示す。此の例では、X や Y の値はテキストボックスとスライダコン トロールで共有されて居て、片方の値が変更されると即座に他方に値の変更が通知され、ビューに変更 が反映される。亦、X と Y の値の変化と連動して、X+Y の値の変化も即座にビューに反映される。 Figure 7: データの更新通知の例

(7)

此処で、WPF の UI 要素を幾つか紹介して置く(詳細は次回以降説明する)。WPF の UI 要素には、大 まかに分類するとTable 1 の様な物が有る。

種類 説明 UI 要素の例

コントロール ボタンやリストボックス等のコントロ

ール類 Button、TextBox 、ComboBox

コンテナ 子要素の配置を決める為に用いる StackPanel 、 WrapPanel 、 DockPanel 、 Canvas、Grid シェイプ ベクターグラフィックスを描画する為 の要素 Rectangle、Ellipse、Path メディア 静止画や動画等 Image、MediaElement ドキュメント 文書整形 RichTextBox Table 1: WPF の UI 要素の分類 標準コントロール WPF では、標準で様々なコントロールが用意されて居る。Figure 8 に幾つか代表的な物を示す。 ウィンドウ左側に有るのは、上から順にMenu、Button、CheckBox、ComboBox、RadioButton、Slider、 ListBox、StatusBar コントロールで有る。亦、.NET Framework 4 で新たに追加されたコントロール も幾つか有り、Figure 8 の右側に有る Calendar コントロールも其の 1 つだ。

Figure 8:標準コントロールの例

其の他にも、.NET Framework 4 で、待望の DataGrid コントロールが追加された。WPF ではデータ バインディングとデータテンプレートの仕組みが強力で、ListView と謂うコントロールを用いる事で柔 軟なデータ表示が可能だった。併し、開発の仕易さと謂う観点から謂うと ListView コントロールは少 し面倒で、Windows フォームに於ける DataGrid コントロールの様なドラッグ&ドロップ開発の容易な コントロールが待ち望まれて居た。其のDataGrid コントロールが WPF にも追加された訳で有る。 Figure 9 に DataGrid コントロールの利用例を示す。此処では、SQL Server にサンプルとして付いて 来るNorthwind データベースの Customers テーブルの内容を DataGrid コントロールで表示して居る。

(8)

Figure 9:DataGrid コントロールの例 WPF Toolkit 標準コントロール以外にも、WPF Toolkit と謂う形で幾つかのコントロールが提供されて居る。WPF Toolkit は開発途中のコントロールを一早く開発者が試せる様に、マイクロソフトが CodePlex と謂うサ イトに於いてオープンソースとして提供して居る物で有る。 WPF Toolkit に含まれて居るコントロールは、安定した物から順に.NET の標準ライブラリに取り入れ られて行く。前述のDataGrid コントロールや Calendar コントロールも、元々は WPF Toolkit の一部 として提供されて居た物が.NET Framework 4 で標準コントロールに採用された物だ。 現在、WPF Toolkit として而巳提供されて居るコントロールには、グラフ表示の為のチャートコントロ ール等が有る。 コンテナ WPF では UI 要素の配置を柔軟に制御する為に、幾つかのコンテナコントロールが用意されて居る。標 準では、以下の様なコンテナが有る。 ・StackPanel:要素を縦又は横に並べて配置する ・WrapPanel:HTML のインライン要素と同じ様に、画面の幅に合わせて自動的に折り返す ・DockPanel:UI 要素を上下左右に貼り付ける形で配置する ・Grid:UI 要素を格子状に配置する ・Canvas:UI 要素を、座標や幅・高さの値を明示的に指定して配置する シェイプ 本稿の冒頭で説明した様に、WPF ではコアの部分にベクターベースのグラフィックエンジンを採用し て居る。コントロールがベクターベースで描画されて居るのは勿論、プリミティブなベクターグラフィ

(9)

ックスを表示する為のUI 要素も提供されて居る。例えば、長方形を描画する Rectangle 要素や、楕円 を描画するEllipse 要素等が有る。 メディア WPF では静止画を表示する為の Image コントロールや、動画や音声を再生する為の MediaElement コントロールが標準で提供されて居る。此等は、他のUI 要素と統合されて居て、混在させて使ったり、 他のUI 要素の中に表示したりと謂った事も簡単に実現出来る。亦、WPF が標準で提供する変形機能を 用いて、動画を拡大・縮小、回転すると謂った事も可能だ。 ドキュメント WPF は Figure 10 に示す様な文書整形機能も標準で備えて居る。 Figure 10:WPF の文書整形機能 次回からはXAML に付いて基礎から詳しく説明する予定だ。

(10)

■ 第2 回 WPF と XAML の関係 ~ XAML の基礎を学ぶ ■

前回説明した様に、XAML(Extensible Application Markup Language)と呼ばれる宣言的言語が WPF アプリケーション開発の中核と成って居る。勿論(XAML を使わない)C#や 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 コード にシリアライズするサンプルプログラムで有る。 Visual Basic 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}

(11)

XamlWriter.Save(x, stream) End Using End Sub End Module Visual C# 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); } } List 1:ユーザー定義型のインスタンスを XAML コードとして保存するサンプルコード ※ コンソールアプリケーションとして作成する。ビルドするには、PresentationFramework アセンブ リ、WindowsBase アセンブリ、System.Xml への参照を追加する必要が有る。 此のコードを実行した結果として得られるXAML コードは、以下の様な物に成る。 <Point X="1" Y="2" xmlns="clr-namespace:Sample;assembly=SampleLibrary" />

List 2:上記のコードに於ける Point クラスのインスタンスを XAML コード化した結果

※ SampleLibrary の部分には、実際には Point クラスが定義されて居るアセンブリ名が入る。 逆に、XAML コードから CLR(Common Language Runtime)オブジェクトにデシリアライズするに は、XamlReader.Load メソッドを用いる。

XAML を使わない WPF アプリケーション

亦、XAML で書ける物は、原理的に C#/VB 等の任意の.NET 言語丈で書く事も出来る。WPF の場合も 例外ではなく、余り一般的ではないが、C#/VB 等の.NET 言語而巳で WPF アプリケーションを作成可 能で有る。

(12)

例えば、Visual Studio の[新しいプロジェクト]ダイアログで WPF アプリケーションを作成した後、 最初からプロジェクトに含まれて居るApp.xaml ファイルや MainWindow.xaml ファイル等を一度総て 削除して、MainWindow.cs/MainWindow.vb ファイルを新規作成し、其のファイルに以下の様な C#/VB コードを記述して観て欲しい。 Visual Basic 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 Visual C# using System; using System.Windows; using System.Windows.Controls; public class MainWindow : Window {

(13)

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, }); }

}

List 3:XAML を使わない WPF アプリケーションの例

(14)

一般的な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」に成って居る事が解る。

(15)

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 の基礎に付いて説明して行く。 ■ XAML の基礎 此処では、特にWPF に依存しない「インスタンス生成用のマークアップ言語」としての XAML を中心 に説明する。 XAML の XML 要素/属性と、対応する CLR オブジェクト 詳細に付いて話す前に先ず、XAML コードと、其れと粗等価の CLR オブジェクトを生成する C#/VB

(16)

コードに付いて幾つかの例を挙げる事で、大まかなイメージを掴んで貰い度い。List 4~List 10 に其の 例を示す。

ユーザー定義クラスのインスタンス生成例

List 4 は、(XAML コードに於ける<Point>要素から)ユーザー定義クラス「Point」のインスタンス(CLR オブジェクト)が生成される例で有る。

XAML

<Point X="1" Y="2"

xmlns="clr-namespace:Sample;assembly=SampleLibrary" /> Visual Basic

Dim obj = New Sample.Point With {

.X = 1, .Y = 2 }

Visual C#

var obj = new Sample.Point { X = 1, Y = 2 }; List 4: ユーザー定義クラスのインスタンス生成例 大まかに謂うと、以下の様な対応関係に成る。 ・XML 名前空間(xmlns 属性) = CLR 名前空間 + アセンブリ情報 ・XML 要素名 = CLR クラス名 ・XML 属性 = CLR オブジェクトのプロパティ値設定(属性構文) System.Uri クラスのインスタンス生成例

次のList 5 は、(XAML コードに於ける<Uri>要素から)Uri クラス(System 名前空間)のインスタン ス(=CLR オブジェクト)が生成される例で有る。

XAML

<Uri xmlns="clr-namespace:System;assembly=System"> http://www.atmarkit.co.jp/</Uri>

Visual Basic

Dim converter = New System.UriTypeConverter()

Dim obj = converter.ConvertFrom("http://www.atmarkit.co.jp/") ' ↑System.Uri クラス(=<Uri>要素)には

' <TypeConverter(GetType(UriTypeConverter))>属性が付いて居る Visual C#

var converter = new System.UriTypeConverter();

(17)

// ↑System.Uri クラス(=<Uri>要素)には

// [TypeConverter(typeof(UriTypeConverter))]属性が付いて居る List 5: System.Uri クラスのインスタンス生成例

XAML コード中の各要素の文字列は、CLR クラスに付与された TypeConverter 属性の値に基づいて変 換処理が行われる。例えばList 5 の XAML コードに有る<Uri>要素の文字列は、Uri クラスに付与され たTypeConverter 属性の UriTypeConverter に基づき、C#や VB コードに於ける Uri クラスのインス タンス(CLR オブジェクト)に変換される。

System.Windows.Controls.Button クラスのインスタンス生成例

List 6 は、(XAML コードに於ける<Button>要素から)Button クラス(System.Windows.Controls 名 前空間)のインスタンス(CLR オブジェクト)が生成される例で有る。 XAML <Button xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" FontSize="20" Background="Blue"> ボタン </Button> Visual Basic ' Button クラス(の親クラスで有る ContentControl クラス)には ' [ContentProperty("Content")]属性が付いて居る。

Dim obj = New Button With {

.Content = "ボタン", .FontSize = 20,

.Background = New SolidColorBrush(Colors.Blue) } ' ↑BrushConverter.ConvertFrom("Blue") の結果 ' Background プロパティの型で有る Brush クラスには

' <TypeConverter(GetType(BrushConverter))>]属性が付いて居る Visual C#

var obj = new Button {

Content = "ボタン",

// ↑Button クラス(の親クラスで有る ContentControl クラス)には // [ContentProperty("Content")]属性が付いて居る

FontSize = 20,

Background = new SolidColorBrush(Colors.Blue), // ↑BrushConverter.ConvertFrom("Blue") の結果。 // Background プロパティの型で有る Brush クラスには // [TypeConverter(typeof(BrushConverter))]属性が付いて居る }; List 6: System.Windows.Controls.Button クラスのインスタンス生成例 List 6 を見ると解る様に、WPF 関連のクラスに関しては、XML 名前空間の宣言に逐一「CLR 名前空

(18)

間 + ア セ ン ブ リ 情 報 」 を 記 述 す る 必 要 は な く 、 WPF 専 用 の XML 名 前 空 間 「http://schemas.microsoft.com/winfx/2006/xaml/presentation」が用意されて居るので、代わりに此 れを宣言すれば良い。 亦、CLR クラスに ContentProperty 属性を付ける事で、其の属性に指定されたプロパティは、 <Button Content="ボタン" /> の様に属性ではなく、 <Button>ボタン</Button> の様に要素のテキストセレクションとして記述出来る。 複雑なプロパティ値を持つインスタンス生成例

次のList 7 も、(XAML コードに於ける<Button>要素から)Button クラス(System.Windows.Controls 名前空間)のインスタンス(CLR オブジェクト)が生成される例で有る。此の例では、先程の List 6 の場合よりも複雑なプロパティを持って居る。 XAML <Button xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"> <Button.Background>

<LinearGradientBrush StartPoint="0,0" EndPoint="1,1"> <LinearGradientBrush.GradientStops>

<GradientStop Color="White" Offset="0" /> <GradientStop Color="Blue" Offset="1" /> </LinearGradientBrush.GradientStops> </LinearGradientBrush> </Button.Background> ボタン </Button> Visual Basic

Dim obj = New Button With {

.Content = "ボタン",

.Background = New LinearGradientBrush With {

.StartPoint = New Point With {.X = 0, .Y = 0}, .EndPoint = New Point With {.X = 1, .Y = 1},

.GradientStops = New GradientStopCollection From {

New GradientStop With {.Color = Colors.White, .Offset = 0}, New GradientStop With {.Color = Colors.Blue, .Offset = 1} }

} }

(19)

Visual C#

var obj = new Button {

Content = "ボタン",

Background = new LinearGradientBrush {

StartPoint = new Point { X = 0, Y = 0 }, EndPoint = new Point { X = 1, Y = 1 }, GradientStops =

{

new GradientStop { Color = Colors.White, Offset = 0 }, new GradientStop { Color = Colors.Blue, Offset = 1 }, } } }; List 7: 複雑なプロパティ値を持つインスタンス生成例 文字列からの型変換では生成し難い様な複雑なプロパティ値を指定し度い場合、XML 属性ではなく、 XML 要素の形でプロパティ値を代入する事も可能で有る(此れはプロパティ要素構文と呼ばれる。List 7 の XAML コードでは、<Button.Background>要素等が其の例)。 マークアップ拡張を使ったプロパティ値設定の例

List 8 は、(XAML コードに於ける<TextBlock>要素から)TextBlock クラス(System.Windows.Controls 名前空間)のインスタンス(CLR オブジェクト)が生成される例で有る。 XAML <TextBlock xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Foreground="{x:Static Member=SystemColors.HighlightTextBrush}" Background="{x:Static Member=SystemColors.HighlightBrush}" Text="text" /> Visual Basic

Dim obj = New TextBlock With { .Text = "text", .Foreground = SystemColors.HighlightTextBrush, .Background = SystemColors.HighlightBrush } ' ↑実際には、以下の様なクラスのインスタンスが作られた上で、 ' 其のインスタンスの ProvideValue メソッドが呼ばれた結果、 ' 静的メンバが取得される '

'Dim extension As New StaticExtension With '{

' .Member = "SystemColors.HighlightBrush" '}

(20)

Visual C#

var obj = new TextBlock { Text = "text", Foreground = SystemColors.HighlightTextBrush, Background = SystemColors.HighlightBrush, }; // ↑実際には、以下の様なクラスのインスタンスが作られた上で、 // 其のインスタンスの ProvideValue メソッドが呼ばれた結果、 // 静的メンバが取得される //

// var extension = new StaticExtension // { // Member = "SystemColors.HighlightBrush" // }; List 8: マークアップ拡張を使ったプロパティ値設定の例 属性構文を使って複雑なインスタンスを生成する為に、マークアップ拡張と呼ばれる機能も提供されて 居る。XML 属性の値として、{ } で囲った記述を行うと、一度 MarkupExtension クラスを継承したク ラス(List 8 の例では StaticExtension クラス)のインスタンスが生成され、其のインスタンスの ProvideValue メソッドの戻り値がプロパティの値として設定される。List 8 の例では、何等かのクラス の静的プロパティを読み出す為のマークアップ拡張で有るx:Static を利用して居る。 リストのインスタンス生成例

List 9 は 、( XAML コ ー ド に 於 け る <StackPanel> 要 素 か ら ) StackPanel ク ラ ス (System.Windows.Controls 名前空間)のインスタンス(CLR オブジェクト)が生成される例で有る。 XAML <StackPanel xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"> <Button Content="ボタン 1" /> <Button Content="ボタン 2" /> <Button Content="ボタン 3" /> </StackPanel> Visual Basic

Dim obj As New StackPanel

obj.Children.Add(New Button With {.Content = "ボタン 1"}) obj.Children.Add(New Button With {.Content = "ボタン 2"}) obj.Children.Add(New Button With {.Content = "ボタン 3"}) ' ↑StackPanel クラス(の親クラスで有る Panel クラス)には ' [ContentProperty("Children")]属性が付いて居る

Visual C#

var obj = new StackPanel {

Children =

// ↑StackPanel クラス(の親クラスで有る Panel クラス)には // [ContentProperty("Children")]属性が付いて居る

(21)

{

new Button { Content = "ボタン 1" }, new Button { Content = "ボタン 2" }, new Button { Content = "ボタン 3" }, }

};

List 9: リストのインスタンス生成例

StackPanel ク ラ ス の Children プ ロ パ テ ィ の 型 は UIElementCollection ク ラ ス (System.Windows.Controls 名前空間)だが、此の様な IList インターフェイスを実装するクラスや配 列の場合、<UIElementCollection>と謂う様なリストを表すタグを 1 段省略出来る。実際に List 9 では、 <UIElementCollection>タグが省略され、複数の<Button>要素が<StackPanel>タグの中に直接記述さ れて居る。

添付プロパティを持つインスタンス生成例

List 10 は、(XAML コードに於ける<Canvas>要素から)Canvas クラス(System.Windows.Controls 名前空間)のインスタンス(CLR オブジェクト)が生成される例で有る。

XAML <Canvas

xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" Width="100" Height="100">

<Button Content="ボタン" Canvas.Left="10" Canvas.Top="50" /> </Canvas>

Visual Basic

Dim button = New Button With {.Content = "ボタン"}

Canvas.SetLeft(button, 10)

Canvas.SetTop(button, 50)

Dim obj As New Canvas With { .Width = 100, .Height = 100 } obj.Children.Add(button) ' ↑Canvas クラス(の親クラスで有る Panel クラス)には ' [ContentProperty("Children")]属性が付いて居る Visual C#

var button = new Button { Content = "ボタン" };

Canvas.SetLeft(button, 10);

Canvas.SetTop(button, 50);

var obj = new Canvas {

Width = 100, Height = 100,

(22)

Children = { button } // ↑Canvas クラス(の親クラスで有る Panel クラス)には // [ContentProperty("Children")]属性が付いて居る }; List 10: 添付プロパティを持つインスタンス生成例 添付プロパティ(前回説明した様に、自分自身ではなく、親要素で用いる値を保持する為の機構)は「ク ラス名.Set プロパティ名」と謂う名前の静的メソッド呼び出しとして解釈される。List 10 の赤字の部 分が、添付プロパティで有る。 以上、XAML コードの XML 要素と、其れに対応する CLR オブジェクトの例を示した。 分離コードの利用例 此処迄はXAML 単体で書ける仕様だったが、下記の記述例(C#/VB)では MSBuild を通すのが必須に 成る。List 11 に其の例を示す。 XAML <Grid xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Class="Sample.MyGrid"> <Button x:Name="button1" Content="ボタン" Click="button1_Click" /> </Grid> Visual Basic Namespace Sample Class MyGrid Inherits Grid

Private Sub button1_Click(ByVal sender As System.Object, _ ByVal e As System.Windows.RoutedEventArgs) MessageBox.Show("ボタンが押されました") End Sub End Class End Namespace Visual C# using System.Windows.Controls; using System.Windows; namespace Sample {

public partial class MyGrid : Grid {

(23)

public MyGrid() {

InitializeComponent(); }

void button1_Click(object sender, System.Windows.RoutedEventArgs e) { MessageBox.Show("ボタンが押されました"); } } } List 11: 分離コードの利用例 「http://schemas.microsoft.com/winfx/2006/xaml」と謂う XML 名前空間は、(WPF に限らない)XAML 全般に使う特別なスキーマを定義する。x:Class 属性や x:Name 属性も其の一種で、x:Class 属性には分 離コードで実装するクラス名を、x:Name 属性にはフィールド名を指定する。

亦、プロパティと同様に、イベントに対しても「Click="button1_Click"」と謂う様な、XML 属性を使 った記述が可能で有る。其処で記述したメソッド名のイベントハンドラは、分離コード内で定義する必 要が有る。

List 10 及び List 11 の組み合わせた C#/VB 而巳のコード

List 11 の例の MyGrid クラスと粗同等の物を C#/VB 丈で記述すると、List 12 の様に成る。 Visual Basic

Namespace Sample Class MyGrid1 Inherits Grid

Friend button1 As Button

Public Sub New() InitializeComponent()

button1 = New Button With {.Content = "ボタン"} AddHandler button1.Click, AddressOf button1_Click End Sub

Private Sub button1_Click(ByVal sender As System.Object, _ ByVal e As System.Windows.RoutedEventArgs) MessageBox.Show("ボタンが押されました") End Sub End Class End Namespace Visual C# using System.Windows.Controls;

(24)

using System.Windows; namespace Sample {

public partial class MyGrid : Grid {

internal Button button1;

public MyGrid() {

button1 = new Button { Content = "ボタン" }; button1.Click += button1_Click;

}

void button1_Click(object sender, System.Windows.RoutedEventArgs e) {

MessageBox.Show("ボタンが押されました"); }

} }

List 12: List 10 及び List 11 の組み合わせと粗同等のコード

分離コードを用いたWPF アプリケーション作成に関して、詳細は次回以降で説明する。 最後に、此れ迄の例で出て来た構文に付いて纏めて置く。 ■ XAML 構文のまとめ XML 名前空間 XML 名前空間には、以下の様に CLR 名前空間とアセンブリ名に関する情報を書く。 xmlns:ns="clr-namespace:CLR 名前空間名;assembly=アセンブリ名" 以後、<ns:クラス名>と謂う様な XML 要素を書く事で、対応する CLR オブジェクトのインスタンスを 生成出来る(当然乍クラス名は、記述したアセンブリに含まれる CLR 名前空間のクラスでなければ成 らない)。 但し、WPF の場合には関連するクラスが様々な名前空間に亘って定義されて居るが、此等を逐一 XML 名前空間に書く必要は無く、以下の様なWPF 専用の XML 名前空間を 1 つ書く丈で構わない。 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 亦、XAML 固有の機能を使う為に、通常は以下の XML 名前空間も併せて記述する。 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

(25)

属性構文 XAML コード中の XML 属性は、CLR オブジェクトのプロパティ若しくはイベントへの値の代入とし て解釈される(属性構文(attribute syntax)と呼ぶ)。プロパティの場合、XML 属性値(文字列)か ら所望の型への変換は、以下の手順で行われる。 1.先ず、CLR オブジェクトのプロパティに TypeConverter 属性が付いて居るか何うかを調べ、付い て居る場合は此の属性情報に基づいた型コンバータを使って、ConvertFrom メソッドに依り値を 生成する 2.プロパティの次に、プロパティの型に対してTypeConverter 属性が付いて居るか何うかを調べ、同 様に此の情報に基づいて値を生成する イベントの場合には、分離コード内に其のイベントハンドラと成るメソッドが定義されて居る必要が有 る。 プロパティ要素構文 文字列からの変換が困難で有る様な複雑なインスタンスを生成する場合は、XML 属性の代わりに、子 要素としてプロパティ値を設定する事も出来る(プロパティ要素構文(property element syntax)と呼 ぶ)。プロパティ要素構文では、<型名.プロパティ名>と謂う形の XML 要素を記述する。 属性構文とプロパティ要素構文とで得られる結果は同じで、例えば、List 13 の 2 つの Button 要素は同 じ構造のインスタンスを生成する(値を文字列丈で書ける場合には属性構文、然うでない場合にプロパ ティ要素構文の利用が推奨される)。 <Button Background="Blue" /> <Button> <Button.Background>Blue</Button.Background > </Button> List 13: 属性構文(上)とプロパティ要素構文(下) マークアップ拡張 プロパティ要素構文に加えて、属性構文を用いて複雑なインスタンスを生成する手段として、マークア ップ拡張(markup extension)と呼ばれる機能が有る。詳細は次回以降で解説する事に成るが、データ バインディングを行う為のBinding マークアップ拡張が其の代表例だ(List 14)。 <StackPanel xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" Width="100"> <Slider Name="slider" />

<TextBox Text="{Binding ElementName=slider, Path=Value}" /> </StackPanel>

List 14: Binding マークアップ拡張

※ データバインディングに依り、スライダコントロールの値(Value プロパティの値)がテキストボッ クスに反映される。

(26)

マークアップ拡張では、XML 属性中に { } で囲った記述を書くと、対応するマークアップ拡張クラス のインスタンス生成と、其の ProvideValue メソッド呼び出しを通してプロパティの値が設定される。 List 14 の場合、List 15 に示す様な Binding クラスのインスタンスが生成され、Binding.ProvideValue メソッド内でデータバインディングの処理が行われる。

Visual Basic

Dim binding = New System.Windows.Data.Binding With {

.ElementName = "slider",

.Path = new PropertyPath("Value") }

Visual C#

var binding = new System.Windows.Data.Binding {

ElementName = "slider",

Path = new PropertyPath("Value"), };

List 15: List 14 の XAML コードに対応する Binding クラスのインスタンスを生成するコード マークアップ拡張クラスは自作する事も出来る。

・マークアップ拡張クラスは、MarkupExtension クラス(System.Windows.Markup 名前空間)を継 承する必要が有る

・名前の末尾にExtension が付く場合、XAML コード中では Extension の部分を省略出来る(例えば ArrayExtension は Array と記述出来る。猶、一般的なクラスの命名規則としては、Extension を付 ける。Binding クラス(System.Windows.Data 名前空間)は此の例には当て嵌らない)。

コンテンツプロパティとXML 要素の省略

XAML には、XAML コードの可読性を向上させる為、XML 要素の省略機構が幾つか存在する。其の 1 つがコンテンツプロパティ(content property)で、クラスに対して ContentProperty 属性が付いて居 る場合、其の情報に基づいてXML 要素の省略が可能に成る。

例えば、Button クラスの場合、親クラスで有る ContentControl クラスに[ContentProperty("Content")] 属性が付いて居る為、<Button.Content>要素を省略出来る。即ち、List 16 に示す 2 つの<Button>要 素は同じ意味に成る。 <Button> <Button.Content>ボタン</Button.Content> </Button> <Button> ボタン </Button> List 16: コンテンツプロパティに於ける XML 要素の省略

(27)

コレクション型の省略 プロパティ要素構文で、プロパティの値がコレクションの場合、コレクションに相当するXML 要素を 省略する事が出来る。例えば、StackPanel クラス等の Children プロパティ(コンテンツプロパティに 設定されて居る)の型はUIElementCollection と謂うコレクションクラスで有る為、省略可能で有る。 List 17 に示す 2 つの<StackPanel>要素は同じ意味に成る。 <StackPanel> <StackPanel.Children> <UIElementCollection> <Button Content="ボタン 1" /> <Button Content="ボタン 2" /> </UIElementCollection> </StackPanel.Children> </StackPanel> <StackPanel> <Button Content="ボタン 1" /> <Button Content="ボタン 2" /> </StackPanel> List 17: コレクション型の省略(上:省略無し、下:省略有り) 省略可能と成るのは以下の孰れかの場合で有る。 ・IList インターフェイス(ジェネリック版/非ジェネリック版共に)を実装するクラス ・IDictionary インターフェイス(ジェネリック版/非ジェネリック版共に)を実装するクラス(此の場 合、子要素にx:Key 属性が必須と成る) ・配列 今1 つ、IAddChild インターフェイスに依るコレクション型要素の省略も可能で有るが、過去の互換性 の為丈に有り、新規に利用する事は無いだろう。 添付プロパティ 繰り返しに成るが、XAML には、自分自身ではなく親要素で用いる値を保持する為の機構として添付プ ロパティ(attached property)と謂う機能が存在する。例えば<Button Canvas.Left="10" />と謂う様 に、XML 属性名に「型名.添付プロパティ名」を指定する。此の様な添付プロパティの値の設定は、「型 名.Set 添付プロパティ名」と謂う名前の静的メソッド呼び出しとして解釈される。前記の Canvas.Left の例であれば、Canvas.SetLeft(button, 10)と謂う様なメソッド呼び出しに成る。 因みに、WPF の内部的には、次回以降で説明する依存関係プロパティ(dependency property)と謂う 物を用いて添付プロパティを実装して居る。Canvas.SetLeft メソッドの例で謂うと、内部的には List 18 に示す様な実装に成って居る。 Visual Basic

Public Class Canvas

Public Shared ReadOnly LeftProperty As DependencyProperty = ' 詳細は省略

(28)

Public Shared Sub SetLeft(ByVal element As DependencyObject, ByVal value As Double) element.SetValue(LeftProperty, value)

End Sub End Class Visual C#

public class Canvas {

public static readonly DependencyProperty LeftProperty = // 詳細は省略

public static void SetLeft(DependecyObject element, double value) { element.SetValue(LeftProperty, value); } } List 18: Canvas.SetLeft メソッドの実装 添付プロパティと同様に、イベントに関しても親子間でのイベントの伝搬を行うルーティングイベント (routed event)と謂う機能が有り、添付プロパティと同様に、「型名.イベント名="イベントハンドラ"」 と謂う書き方が出来る。ルーティングイベントに付いては次回以降で説明を行う。 XML 形式 XAML の記述には XML 形式を用いる為、XML 形式を使う上での注意点が其の儘 XAML にも当て嵌ま る。 ・「<」「>」「&」「"」等の文字は其の儘では利用出来ない ・夫々、「&lt;」「&gt;」「&amp;」「&quote;」と謂う記述に置き換える必要が有る ・或いはCDATA セクションを用いる(「<![CDATA[」と「]]>」で囲む) ・空白文字は無視される ・空白文字に意味を持たせる為には、XML 要素に「xml:space="preserve"」と謂う属性を追加する 参考:XAML コード単体で UI(ユーザーインターフェイス)表示 最後に、余談に成るが、XAML コード単体で(C#等の分離コードを一切書かず、MSBuild に依るコ ンパイルも行わず)UI を表示させる方法に触れて置く。 Loose XAML 分離コードを必要としない(或いは XAML コード中に、<x:Code>要素に依りインラインで C#/VB のプログラミングコードを埋め込んで居ない)XAML コードで有れば、コンパイルせずに其の儘 IE (Internet Explorer)等のブラウザ上で表示する事が可能で有る。此の、C#/VB 等のプログラミン グコードを含まないXAML コードを「Loose XAML」と呼ぶ。

Loose XAML の表示は.NET Framework 同梱のブラウザプラグインに依る物で有り、.NET Framework 3.0 のインストールされた Windows 上でなら IE 而巳、3.5 以上なら IE に加えて Firefox での表示が可能だ。

(29)

・Loose XAML のサンプル

Silverlight

WPF ではなく Silverlight を用いた技術に成るが、「Gestalt」と謂うライブラリを使う事で HTML コード中にXAML コードを埋め込んで表示出来る。Silverlight ベースで有る為、WPF とは利用出来 るUI 要素等に差が有るが、<Button>要素等の基本的な物は其の儘利用出来る部分も多い。以下の例 では、上述のLoose XAML と粗同じ(<Menu>要素と<StatusBar>要素が無い以外は全く同じ)XAML コードをHTML コード中に埋め込んで居る。

(30)

■ 第3 回 XAML コードから生成されるプログラム・コードを理解する ■ 前回は主に、WPF に依らない XAML の一般的な仕組みに付いて説明を行った。今回からは WPF 固有 の機能に踏み込んで説明して行く。 先ず、WPF の内部的な挙動の理解を深めて貰う為、XAML コードから自動生成される中間生成物のプ ログラムコード(C#/VB)に付いて説明を行う。亦、プログラムの起点と成る Application クラス (System.Windows 名前空間)に関する説明も行う(Application クラスと並んで WPF アプリケーシ ョンの基礎と成るWindow クラスに関しては、コントロールの一種と看做せる為、次回以降、コントロ ールに関する回にて説明を行う)。 更に、データバインディング等の高度な機能を実現する為の要と成る「依存関係プロパティ」と「ルー ティングイベント」に関する説明を行う。 ■ XAML コードから自動生成される中間生成物のプログラムコード 前回からの再掲に成るが、標準的なWPF アプリケーションの作りを今一度観てみよう。Visual Studio のテンプレートからWPF アプリケーションプロジェクトを作成すると、Figure 1 に示す様な状態が得 られる筈だ。

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

前回は概要而巳の説明だったが、今回は今少し踏み込んで、XAML コードから自動生成される中間生成 物のプログラムコード(.g.cs/.g.vb ファイル等。詳しくは第 1 回を参照)に付いて説明して行く。 MainWindow.xaml ファイルから生成されるプログラムコード

MainWindow.xaml ファイルの分離コードで有る MainWindow.xaml.cs/MainWindow.xaml.vb ファイ ル内に生成される MainWindow クラスは、名前通り、アプリケーション起動時に最初に開かれるメイ

(31)

ンウィンドウで、其の実体はWindow クラス(System.Windows 名前空間)を継承したクラスで有る。 MainWindow クラスはパーシャルクラスと成って居て、MainWindow.xaml ファイルから自動生成され るプログラムコードと合わせて1 つのクラスと成る。

Visual Studio のテンプレートから生成された儘の MainWindow.xaml ファイル(+其の分離コード) を ビ ル ド ( コ ン パ イ ル ) す る と 、List 1 に 示す様 なプログ ラムコード が (obj フォルダ 内に MainWindow.g.cs/MainWindow.g.vb 等の名前で)自動生成される(見易さを優先して、属性やコメン ト等を一部削って居る)。 Visual Basic 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 C# using System.Windows; using System.Windows.Markup; namespace SampleWpfApplication {

public partial class MainWindow : Window, IComponentConnector {

(32)

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; } } } List 1: MainWindow.xaml ファイルから自動生成される中間生成物のプログラムコード

上記のコードを観ると解る様に、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 Sub Button_Click(ByVal sender As Object, ByVal e As RoutedEventArgs) MessageBox.Show("test")

End Sub ]]>

(33)

<StackPanel>

<TextBlock Name="text1" Text="Sample" />

<Button Name="button1" Click="Button_Click" Content="OK" /> </StackPanel>

</Window>

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

List 2: Name 属性や Click 属性を含む様に MainWindow.xaml ファイルを書き換え(XAML) Visual Basic

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 Visual C#

(34)

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"); }

List 3: List 2 から自動生成される中間生成物のプログラムコード(※部分的に抜粋)

XAML コードに記述した<x:Code>要素は、HTML で謂う処の<script>タグに依るスクリプトコードの 埋め込みと同じ感覚で利用出来るが、実際の処WPF アプリケーション開発では余り利用されない。WPF の場合、プログラムコードは分離コードの中に記述するのが一般的で有る。 亦、XAML コード中の属性構文で指定した値がプロパティの場合は、(InitializeComponent メソッド 内で呼び出されて居る)LoadComponent メソッド内で自動的に読み出して貰えるが(即ち、プログラ ムコードの自動生成に頼らないXAML 自体の仕様)、其の値がイベントの場合には、上記の様なプログ ラムコードの追加が必要と成る。 続いて、App.xaml ファイルから生成されるプログラムコードに付いて説明する。 App.xaml ファイルから生成されるプログラムコード 【此処から】

次に、App.xaml ファイル(※VB では Application.xaml ファイル)を観てみよう。App.xaml ファイ ルの分離コードで有る App.xaml.cs/App.xaml.vb ファイル内に生成される App クラス(※VB では Application ク ラス ) は、 ア プ リ ケ ーシ ョ ン 自身 を 定 義 す る 物 で 、 実体 は .Application クラス (System.Windows 名前空間)を継承したクラスで有る。MainWindow クラスと同様に、こちらもパ ーシャルクラスと成って居る。

App.xaml ファイルから自動生成される中間生成物のプログラムコードは、MainWindow.xaml ファイ ルの物とは少し異なる。Visual Studio 上でファイルのプロパティを開いて見比べて貰うと、Figure 2 に示す様に、MainWindow.xaml ファイルと App.xaml ファイルで[ビルド アクション]が異なる事が 解る。

(35)

Figure 2: 「ビルド アクション」の差(左:MainWindow.xaml、右:App.xaml) [ビルド アクション]が「ApplicationDefinition」の場合、自動生成されるプログラムコード(obj フ ォルダ内に作成される「App.g.cs/Application.g.vb」ファイル)は、List 4 に示す様な物に成る(先程 と同様に、説明に不要な属性やコメントは削除して居る)。 Visual Basic Imports System.Windows Partial Public Class Application

Inherits System.Windows.Application

Public Sub InitializeComponent() Me.StartupUri = New System.Uri( _

"MainWindow.xaml", System.UriKind.Relative) End Sub

Public Shared Sub Main()

Dim app As Application = New Application() app.InitializeComponent app.Run End Sub End Class Visual C# using System.Windows; namespace SampleWpfApplication {

public partial class App : Application {

public void InitializeComponent() {

this.StartupUri = new System.Uri(

"MainWindow.xaml", System.UriKind.Relative); }

public static void Main() {

(36)

new SampleWpfApplication.App(); app.InitializeComponent(); app.Run(); } } } List 4: [ビルド アクション]が「ApplicationDefinition」の場合に自動生成される中間生成物のプロ グラムコード アプリケーションのエントリ・ポイント(Main メソッド)は此処で定義されて居る。

Visual Studio テンプレート生成時の状態では、XAML コードの内容総てがプログラムコード化されて 居り、XAML コードを実行時にロードする処理が含まれて居ないが、<Application.Resources>要素の 中身を(App.xaml ファイルに)追加したりすれば、MainWindow.xaml ファイルの場合と同様に、 LoadComponent メソッドの呼び出しが追加される。 System.Windows.Application クラス Application クラス(System.Windows 名前空間)は、アプリケーションの起点と成るクラスで、主に 以下の様なイベントを持って居る。 ・Startup: アプリケーションの起動時(Run メソッド呼び出し直後)に発生する。 ・Exit: アプリケーションの終了直前に発生する。 ・Activated: アプリケーションがアクティブに成った瞬間(他のアプリケーションからフォーカスが 戻った瞬間)に発生する。 ・Deactivated: 他のアプリケーションにフォーカスが移った瞬間に発生する。 ・SessionEnding: ユーザーのログオフや、オペレーティング・システムのシャットダウンに依ってセ ッションが終了するときに発生する。 ○コマンドライン引数 WPF アプリケーションでは、XAML コードから自動生成される中間生成物のプログラムコード中に、 Main メソッドが隠されて居る為、コマンドライン引数を直接、受け取れない。コマンドライン引数を 利用し度い場合には、Startup イベントのイベントハンドラ内で Environment クラス(System 名前空 間)のGetCommandLineArgs メソッドを通して受け取る(参考:「.NET TIPS:コマンドライン引数 を取得するには?」)。

○アプリケーション・オブジェクトの参照

一般に、ウィンドウをまたいでアプリケーション全体で利用する値等は、Application クラス(を継承 した自前のアプリケーション・クラス)の中に定義する(但し、グローバル変数が非推奨とされるのと 同様に、アプリケーション全体から参照される値は可能な限り避けるべきで有る)。ウィンドウ(例え ば、Visual Studio のテンプレートで生成される MainWindow クラス等)からは、Application.Current 静的プロパティを通して現在実行中のアプリケーション・オブジェクトを取得出来る為、各ウィンドウ がアプリケーション・オブジェクトの参照を持つ必要はない。

(37)

■ 依存関係プロパティ 此処迄にも名前丈はたびたび出てきて居るが、WPF では「依存関係プロパティ(dependency property)」 と謂う、通常のプロパティ(区別の為に、WPF の文脈に於いては「CLR プロパティ」と呼ぶ事が有る) とは異なる「値の保持機構」を持って居る。 依存関係プロパティは以下の様な用途を想定して作られて居る(Figure 3)。 ・包含継承: 親要素で設定した値を其の儘継承して使う為の機構。 ・リソース: 1 カ所で定義したオブジェクトを複数カ所から参照する為の、リソースの定義/参照機構。 ・スタイル: HTML で謂う処の CSS の様なスタイル設定機構。 ・データバインディング: モデルとビューの間等、異なるオブジェクト間で値を結び付ける(一方で の値の変更を他方に通知し、即座に反映させる)機構。 Figure 3: 依存関係プロパティの用途 此等は、孰れも「他の要素の値に依存してプロパティの値を決定する機構」と謂える。依存関係プロパ ティと謂う名前は此処から来て居る。 リソース、スタイル、及び、データバインディングに関する詳細は次回以降で説明する。今回は、依存 関係プロパティの定義及び利用方法に付いて説明して行く(包含継承の説明を含む)。 依存関係プロパティの定義 先ずList 5 に、依存関係プロパティを定義するクラスの最低限の実装例を示す。 Visual Basic

Public Class Point

Figure 2: XAML コード+(C#等の)分離コードのビルドの流れ
Figure 3:  ツリー構造の UI 要素  此の例では、 Canvas 要素を入れ子にして居るが、WPF ではボタン等のコントロールの中身も入れ子に する事が出来る。例えば、ボタンの中に動画を配置したり、コンボボックスの中にボタンを並べたりす る事も可能だ。  此の様な WPF のツリー構造の UI 要素では、要素の親子関係に依って以下の様な事が起こる。  ・平行移動や回転等の変形は、親要素からの相対位置に基づいて、子要素諸共行われる  ・添付プロパティと謂う仕組みを用いて、要素自身ではなく、親要素が
Figure 5: UI 要素の回転
Figure 6:  データ・バインディングの例
+7

参照

関連したドキュメント

この 文書 はコンピューターによって 英語 から 自動的 に 翻訳 されているため、 言語 が 不明瞭 になる 可能性 があります。.. このドキュメントは、 元 のドキュメントに 比 べて

主として、自己の居住の用に供する住宅の建築の用に供する目的で行う開発行為以外の開

2021] .さらに対応するプログラミング言語も作

の総体と言える。事例の客観的な情報とは、事例に関わる人の感性によって多様な色付けが行われ

しかし,物質報酬群と言語報酬群に分けてみると,言語報酬群については,言語報酬を与

本論文での分析は、叙述関係の Subject であれば、 Predicate に対して分配される ことが可能というものである。そして o

 “ボランティア”と言えば、ラテン語を語源とし、自

今回の調査に限って言うと、日本手話、手話言語学基礎・専門、手話言語条例、手話 通訳士 養成プ ログ ラム 、合理 的配慮 とし ての 手話通 訳、こ れら