Open棟梁Project - マイクロソフト系技術情報 Wiki
パネルと呼ばれるレイアウト用コントロールを使用して、Windowsフォームのような座標レイアウト、HTMLのようなフロー レイアウト(ブロック化、格子分割)にも対応する。
イベント トリガ、トリガ アクション、ストーリ ボードを定義することで、UIコントロールなどの表示項目にタイムライン ベースのアニメーションの効果を付加できる。
P/InvokeやRCW呼出しなどWin32連携技術を使用した相互運用が可能である。また、WindowsFormsHost?、Hwndhost を使用することで、WindowsフォームやActiveXのUIコントロールを使用することも可能である(パフォーマンス的には不利)。
例えば、下記は、System.Windows.Forms名前空間のDataGrid?コントロールをホストするWPFの例である。
<Window x:Class="WpfApplication1.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:wf="clr-namespace:System.Windows.Forms;assembly=System.Windows.Forms" Title="HostingWfInWpf" Height="150" Width="300" Loaded="Window_Loaded"> <Canvas> <WindowsFormsHost Name="windowsFormsHost1" Height="100" Width="275"> <wf:DataGrid x:Name="dataGrid1"/> </WindowsFormsHost> </Canvas> </Window>
主に3Dグラフィックの高度な機能に関する制限であるので、リッチでインタラクティブな業務アプリケーションの開発に、大きな支障はないと言える。
System.Object
http://msdn.microsoft.com/ja-jp/library/system.object.aspx
WPFのプログラミング モデルを提供するフレームワークは、CLR上のマネージ コンポーネント(PresentationFramework?.dll、PresentationCore?.dll)として公開される。System.Objectは、マネージ コンポーネントが提供する全てのマネージ クラスの基本クラスであり、型階層のルートである。
マネージ コンポーネントには、開発の生産性と信頼性を高める多数の機能(メモリ管理、エラー処理、共通型システムなど)が用意されているが、性能など犠牲となるものもある。これに対し、アンマネージ コンポーネント(milcore.dll)はDirectXとの緊密な統合の実現(ハードウェア レンダリングおよびソフトウェア レンダリングの効率性を考え、WPF での表示はすべて DirectX エンジンによって実行されるようになっている。)、メモリ・実行の詳細な制御の要件による。
http://msdn.microsoft.com/ja-jp/library/system.windows.threading.dispatcherobject.aspx
DispatcherObject?は、派生したCLRオブジェクトに、STAオブジェクトとしての動作を実装する基本抽象クラスである。
通常、WPFアプリケーションは、
の2つのスレッドを使用して実行される。
「レンダリング スレッド」は、「UIスレッド」がユーザ入力を受け取り、イベント処理・UI処理をしている間に、バック グラウンドで実行される。このため、ほとんどのWPFアプリケーションは、単一の「UIスレッド」で済むが、状況によっては、応答性を高める目的でバック グラウンド スレッドを使用する場合もある。WPFでは、バック グラウンド処理の実装を支援するDispatcherObject?を使用できる。
DispatcherObject?.Invoke、BeginInvoke?メソッドを使用することにより、バック グラウンド処理からの「UI変更処理」(= UI要素の操作処理)が、容易に実装可能となる。
このメソッドに指定されたデリゲートは、同期実行されるため、バック グラウンド スレッドが実行結果を表示する「UI変更処理」に利用することが多い。
これらのメソッドは、内部的には
これにより、
http://msdn.microsoft.com/ja-jp/library/system.windows.dependencyobject.aspx
DependencyObject?は、派生したCLRオブジェクトに「WPFプロパティ システム」を実装する。
WPFのアーキテクチャの理念は、「メソッドやイベント(コードビハインド)よりも、なるべくXAMLのマークアップによる宣言的プロパティを使用する」ことである。これを実現する「WPFプロパティ システム」を実装するDependencyObject?により、開発者は多数の宣言的プロパティを使用し、コントロールに開発者の意図を設定できる。このためWPFの開発元は、このXAMLのマークアップによる宣言的プロパティによる制御の範囲を拡大するために、「WPFプロパティ システム」の「依存関係プロパティ」が必要であると判断した。「依存関係プロパティ」は、プロパティの依存関係を把握し、双方向の接続と変更通知を実現する。具体的には、ソースとなるオブジェクトのプロパティの変更が通知された場合(必須ではないが、INotifyPropertyChanged?インターフェイスを使用すると、オブジェクトによる変更通知の発行が可能になる。)、ターゲットとなるオブジェクトのプロパティ値を自動的に検証、計算するなど、高度なオブジェクト プロパティ間の接続を実現する。
「依存関係プロパティ」の入力には、次のものがある。
http://msdn.microsoft.com/ja-jp/library/system.windows.media.visual.aspx
Visualは、WPF の中心的な機能である描画をサポートする基本抽象クラスである。
Visualは、マネージ コンポーネントとアンマネージ コンポーネントの2つのサブシステムの接続ポイントであり、Visualで定義されているマネージ データ(描画情報、描画方法など)から、「ビジュアル ツリー」(後述)と呼ばれるツリー構造のアンマネージ データを構成する。これを「レンダリング スレッド」がツリー構造の上から下にスキャンすることによって描画内容をレンダリングする。
┬Visual ├UIElement │└FrameworkElement ├ContainerVisual │├DrawingVisual │├HostVisual └Viewport3DVisual
http://msdn.microsoft.com/ja-jp/library/system.windows.uielement.aspx
UIElementは、WPFコア レベル実装の基本クラス
http://msdn.microsoft.com/ja-jp/library/system.windows.frameworkelement.aspx
UIElementに、「レイアウト」、「スタイル」を中心とした機能を追加する基本クラス。
http://msdn.microsoft.com/ja-jp/library/system.windows.controls.control.aspx
「テンプレート」を使用して外観を定義する UI 要素の基本クラス
Controlの最も重要な機能は、「テンプレート」である。この「テンプレート」により、コントロールの「外観」を宣言型マークアップでカスタマイズ可能になる(「テンプレート」を複数の子要素から構成する)。また、「イベント ハンドラ」や「イベント トリガ」などもこの「テンプレート」により定義可能で、「テンプレート」を「スタイル」化することで、任意の型のコントロールに、これらの「テンプレート」の定義の適用を強制できる。
http://msdn.microsoft.com/ja-jp/library/system.windows.controls.contentcontrol.aspx
ContentControl? は、Contentプロパティを持つコントロールであるContentControl?も、Contentプロパティの表示に特化した「テンプレート」を持つ。Contentプロパティには、文字列に限らず、様々な子要素を1つだけ設定可能である。代表的なContentControl?型の(ContentControl?クラスから派生した)コントロールには、Button、CheckBox?、RadioButton?などがある。なお、プロパティへ子要素を設定するXAML構文を、
と呼び、この中で、特にContentプロパティに子要素を設定するXAML構文を「コンテンツ構文」と呼ぶ。
ItemsControl?は、1つのコンテンツを設定するContentControl?に対し、複数のコンテンツを設定できるItemsコレクション プロパティを持つコントロールである。ItemsControl?も、Itemsコレクション プロパティの表示に特化した「テンプレート」を持つ。Itemsコレクション プロパティには、様々な子要素を複数設定可能である。代表的なItemsControl?型の(ItemsControl?クラスから派生した)コントロールには、ComboBox?、ListBox?、TabControl?、TreeView?などがある。なお、同様にItemsコレクション プロパティに子要素を設定するXAML構文を「コンテンツ構文」と呼ぶ。
WPFは、ビジュアル要素や、CLRオブジェクトによる「要素ツリー」を構築して、それを処理することでディスプレイへの表示を行う。
「要素ツリー」は、XAMLやプログラムにより、構築される。
例えばXAMLは、次の「プロパティ要素構文」の暗黙的、または明示的な記述で、ツリー構造のCLRオブジェクトをインスタンス化する。
<DockPanel> <!--implicit: <DockPanel.Children>--> → プロパティ要素構文(省略可能) <ListBox DockPanel.Dock="Top"> <!--implicit: <ListBox.Items>--> → プロパティ要素構文(省略可能) <ListBoxItem> <TextBlock>Dog</TextBlock> </ListBoxItem> <ListBoxItem> <TextBlock>Cat</TextBlock> </ListBoxItem> <ListBoxItem> <TextBlock>Fish</TextBlock> </ListBoxItem> <!--implicit: </ListBox.Items>--> → プロパティ要素構文(省略可能) </ListBox> <Button Height="20" Width="100" DockPanel.Dock="Top">Buy a Pet</Button> <!--implicit: </DockPanel.Children>--> → プロパティ要素構文(省略可能) </DockPanel>
ただし、「要素ツリー」は、実体そのものではない「メタファ」であるため、XML DOM のようなXMLツリー操作用のAPIを使用して直接操作することはない。これは、WPFのUIサブシステムのアーキテクチャ、UIフレームワークの構造を理解する上で役立つ。「要素ツリー」には、「論理ツリー」・「ビジュアル ツリー」の2つの解釈方法がある。
「論理ツリー」は、CLRオブジェクトの要素のツリーを表し、「プロパティ継承」や、「ルーティング イベント」を理解する上で役立つ。
以下のXAMLとコードは、同じ「論理ツリー」(CLRオブジェクトの要素のツリー)を生成するため、同じUIを表示する。
<DockPanel> <ListBox Width="100"> <ListBoxItem>Dog</ListBoxItem> <ListBoxItem>Cat</ListBoxItem> <ListBoxItem>Fish</ListBoxItem> </ListBox> <Button Click="OnClick">OK</Button> </DockPanel>
DockPanel dp = new DockPanel(); ListBox lbx = new ListBox(); lbx.Width = 100; ListBoxItem lbxItem = null; lbxItem = new ListBoxItem(); lbxItem.Content = "Dog"; lbx.Items.Add(lbxItem); lbxItem = new ListBoxItem(); lbxItem.Content = "Cat"; lbx.Items.Add(lbxItem); lbxItem = new ListBoxItem(); lbxItem.Content = "Fish"; lbx.Items.Add(lbxItem); dp.Children.Add(lbx); Button btn = new Button(); btn.Content = "OK"; btn.Click += new RoutedEventHandler(this.OnClick); dp.Children.Add(btn); this.AddChild(dp);
「ビジュアル ツリー」は、「論理ツリー」と異なり、ビジュアル要素のツリーを表し、コントロールの「テンプレート」が展開される。このため、アプリケーションのUIで使用する、全てのVisualオブジェクト(描画内容)が含まれる。
MSDN > Windows Presentation Foundation > チュートリアル:
Win32アプリケーションでのビジュアル オブジェクトのホスト
http://msdn.microsoft.com/ja-jp/library/ms754039.aspx
実際に、「要素ツリー」の内容を確認したい場合は、以下のヘルパ クラスのGetChildren?メソッドを再帰的に使用して、各ツリーを出力すると良い。
上記のヘルパ クラスの使用例を、サンプルコードとして以下に示す。
private void PrintLogicalTree() { Debug.WriteLine("PrintLogicalTree"); PrintLogicalTree(0, this); } // 論理ツリーを出力する。 // DependencyObjectの場合は、子要素も再帰的に表示する private void PrintLogicalTree(int level, DependencyObject obj) { PrintObject(level, obj); foreach (var child in LogicalTreeHelper.GetChildren(obj)) { if (child is DependencyObject) { PrintLogicalTree(level + 1, (DependencyObject)child); } else { PrintObject(level + 1, child); } } }
private void PrintVisualTree() { Debug.WriteLine("PrintVisualTree"); PrintVisualTree(0, this); } // ビジュアル ツリーを表示する。 // DependencyObjectの場合はビジュアル ツリー上の子要素も再帰的に出力していく private void PrintVisualTree(int level, DependencyObject obj) { PrintObject(level, obj); foreach (var child in GetVisualChildren(obj)) { if (child is DependencyObject) { PrintVisualTree(level + 1, (DependencyObject)child); } else { PrintObject(level + 1, child); } } } // ビジュアル ツリーの子要素の列挙を返す private IEnumerable<object> GetVisualChildren(DependencyObject obj) { for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++) { yield return VisualTreeHelper.GetChild(obj, i); } }
// ToStringの結果をインデントつきで出力 private void PrintObject(int level, object obj) { Debug.WriteLine(new string('\t', level) + obj); }
本項では、DependencyObject?により実装される「WPFプロパティ システム」の
について説明する。
なお、それぞれのプロパティの定義方法などについても触れるが、実際にこれらのプロパティを独自に定義する必要がある場合は、カスタム コントロール作成時にあたる 。
「依存関係プロパティ」は、「WPFプロパティ システム」によってサポートされるプロパティで、WPFに管理される一種の辞書構造を用いて値を保持する。「依存関係プロパティ」では、変更監視・有効値検証などの機能が使用可能である。