WPF基本

WPFアプリを作成
.net API
連載:WPF入門
  • 第1回 いよいよWPFの時代。WPFの習得を始めよう
  • 第2回 WPFとXAMLの関係とは? XAMLの基礎を学ぶ
  • 第3回 XAMLコードから生成されるプログラム・コードを理解する
    • XAMLコードに記述したx:Code要素は、HTMLでいうところの script タグによるスクリプト・コードの埋め込みと同じ感覚で利用できる
    • System.Windows.Applicationクラス
      • 主なイベント:Startup/Exit/Activated/Deactivated/SessionEnding
      • コマンドライン引数を利用したい場合には、Startupイベントのイベント・ハンドラ内でEnvironmentクラス(System名前空間)のGetCommandLineArgsメソッドを通して受け取る。
      • 参考: .NET TIPS:コマンドライン引数を取得するには?
      • ウィンドウ(MainWindowクラスなど)からは、Application.Current静的プロパティを通して現在実行中のアプリケーション・オブジェクトを取得できるため、各ウィンドウがアプリケーション・オブジェクトの参照を持つ必要はない。
    • 依存関係プロパティ
      • 主な用途:包含継承/リソース/スタイル/データ・バインディング
      • 依存関係プロパティの定義
        • DependencyPropertyクラス(System.Windows名前空間)を用いる。
        • DependencyPropertyクラスのインスタンス自身は、プロパティそのものというよりは辞書のキーのようなもので、実際に値を保持するのはDependencyObjectクラス(System.Windows名前空間)(の子クラス)になる。
      • 依存関係プロパティの仕組みは、添付プロパティを実現するためにも利用される。
      • ほかのクラスで定義された既存の依存関係プロパティを自作のクラスでも利用したい場合、DependencyProperty.AddOwnerメソッドを用いることで、WPFに登録情報を追加できる。
    • ルーティング・イベント
      • ルーティング・イベントは依存関係プロパティのイベント版といえる。
      • ルーティングの方針:直接(Direct)/トンネル(Tunnel)/バブル(Bubble)
  • WPFの「リソース、スタイル、テンプレート」を習得しよう
    • リソース
      • WPFでは、複数のUI要素で1つのオブジェクトを共有するために、リソースという仕組みを持っている。(アセンブリ・リソースではなく、オブジェクト・リソース)
      • アセンブリ・リソース
        • アセンブリの中にバイナリ・ファイルを埋め込むためのリソース機構。バイナリ・リソースなどとも呼ぶ。
      • オブジェクト・リソース
        • .NETオブジェクトを複数のUI要素から参照するためのリソース機構。
      • システム・リソース
        • 「個人設定」などで設定されたシステム色やフォントなど
        • SystemColors
        • SystemFonts
        • SystemParameters
    • スタイル
      • HTMLでいうところのCSSのようなスタイル設定の機構、UI要素の外観をカスタマイズ可能
    • コントロール・テンプレート
  • WPFの「データ・バインディング」を理解する

    • GUIアプリケーションに対する要件
      • ビューとモデルの疎結合
      • GUIアプリケーションに求められる機能
        • 同じデータを複数のウィンドウやコントロールから参照
      • データ・バインディング
        • バインディングのソースとターゲット
          • バインディング・ソース: データの提供元のオブジェクト。
          • ソース・プロパティ: データの提供元となる、バインディング・ソースのプロパティ。
          • バインディング・ターゲット: データの反映先のオブジェクト。
          • ターゲット・プロパティ: データの反映先となる、バインディング・ターゲットのプロパティ。
    • Bindingマークアップ拡張の書き方
      • データ・バインディングの向きとタイミング
        • OneTime: UI要素生成時に一度だけ、ソース・プロパティの値を読み出してターゲット・プロパティに与える。
        • OneWay: ソース・プロパティが変更された際に、ターゲット・プロパティに変更を反映させる(逆は行わない)。
        • OneWayToSource: ターゲット・プロパティが変更された際に、ソース・プロパティに変更を反映させる。
        • TwoWay:ソース・プロパティおよびターゲット・プロパティのいずれの変更も、他方に反映させる。
        • UpdateSourceTriggerプロパティ (TwoWay/OneWayToSource)
          • Default: バインディング・ターゲットの依存関係プロパティのメタデータに基づいてタイミングを決定する
          • PropertyChanged: バインディング・ターゲットの値が変化するたびに変更を通知する。
          • LostFocus: バインディング・ターゲットの要素がフォーカスを失うたびに変更を通知する。
          • Explicit: 明示的にUpdateSourceメソッドを呼び出した場合にのみ変更を通知する。
      • バインディング・ソースのパスの書き方
        • {Binding X} : {Binding Path=X} と同じ
        • {Binding X.Y} : 「.」でつなぐことで階層的なパス指定が可能
        • {Binding X[0]} : 角カッコを用いてインデクサを利用可能
        • {Binding [0]} : データ・ソース(=DataContextに渡されたオブジェクト)そのもののインデクサを利用する場合
        • <Binding Path="[3,4]" /> : 引数が複数あるインデクサを利用する場合
        • {Binding X[0].Y} : 階層的なパス指定とインデクサは混在可能
        • {Binding (Canvas.Left)} : 添付プロパティをバインディング・ソースにする場合
      • コレクション走査パスの指定
        • {Binding Path=List/X} : 「/」でつなぐことで、リストボックスなどで選択された行のプロパティを表示することができる
      • バインディング・ソースの明示的指定
        • 特に何も指定しない場合、バインディング・ソースは、UI要素のDataContextプロパティに与えられたオブジェクトになる。
        • Bindingマークアップ拡張のSourceプロパティを設定することで、バインディング・ソースを明示的に指定できる。
      • XPath
        • バインディング・ソースがXMLデータの場合、PathプロパティではなくXPathプロパティを利用する。
        • XPathプロパティには、XPath言語でクエリを記述する。
      • ほかのUI要素の参照
        • モデルなどのデータ・ソースを介さず、UI要素間で直接プロパティ値の同期を取りたい場合
          • ElementNameプロパティを指定することで、ほかのUI要素をバインディング・ソースにしてデータ・バインディングを行える。
      • 自分自身や先祖要素の参照
        • RelativeSourceプロパティを指定することで、UI要素自身や、先祖要素(=直接の親だけではなく、階層的にたどれる上位の要素すべて)のプロパティをデータ・ソースに指定することができる。
      • 値の変換
        • 値そのままではなく、何らかの変換処理を行ってからデータ・バインディングしたい場合
          • Bindingマークアップ拡張のConverterプロパティにIValueConverterインターフェイス(System.Windows.Data名前空間)を実装するクラスを渡す。
      • データ検証
        • ValidationRules:
          • ValidationRuleクラス(System.Windows.Controls名前空間)を継承するクラスを使って、明示的に検証ルールを追加する。
        • ValidatesOnExceptions:
          • 「True」に設定されている場合、ソース・プロパティの更新中に例外が発生していないかを確認する。
          • ValidationRulesプロパティに「ExceptionValidationRule」を追加した場合と同様の挙動になる。
        • ValidatesOnDataErrors:
          • 「True」に設定されている場合、IDataErrorInfoインターフェイスを介したデータ検証を有効にする。
          • ValidationRulesプロパティに「DataErrorValidationRule」を追加した場合と同様の挙動になる。
        • データ検証の結果、何らかのエラーがあった場合
          • Validation.HasError添付プロパティに「True」が設定され、Validation.Errors添付プロパティにエラーの一覧が格納される。
          • 標準でデータ検証エラーがある場合にテキストボックスの枠線が赤くなるなどの変化が生じる(Validation.HasError添付プロパティをトリガーとしたスタイルが定義されている)。
    • データ・テンプレート
      • ContentControlクラス:単一のデータに対するデータ・テンプレートの適用
        • 単一データに対するテンプレート指定は、ContentControlクラス(Sytem.Windows.Control名前空間)のContentプロパティにデータを、ContentTemplateプロパティにデータ・テンプレートを渡すことによって行う。
        • データ・テンプレートの自動適用
          • <DataTemplate>要素のDataTypeプロパティを設定することで、指定した型に対してデータ・テンプレートを自動適用できる。
      • ItemControlクラス:コレクションに対するデータ・テンプレートの適用
        • データ・ソースがコレクションの場合、ItemsControlクラス(Sytem.Windows.Control名前空間)のItemsSourceプロパティにデータを、ItemTemplateプロパティにデータ・テンプレートを渡すことによってデータ・バインディングを行う。
  • 「コマンド」と「MVVM(Model-View-ViewModel)パターン」を理解する

    • コマンド
      • WPFでは、以下の2つの機能を提供する「コマンド」(command)という仕組みを持っている。
        • クリックやキー入力などの実操作レベルのイベントではなく、コピーや貼り付けなどの意味的なイベント処理を行う
        • モデルの状態に応じてボタンを押せなくするなどして、コマンドを実行の可否を切り替える
      • コマンドの実体
        • WPFのコマンドの実体はICommandインターフェイス(System.Windows.Input名前空間)を実装したクラスである。
        • ICommandインターフェイスは以下のようなメンバを持っている。
          • Executeメソッド: コマンドを実行する。
          • CanExecuteメソッド: コマンドが実行可能な状態にあるかどうかを判定する。
          • CanExecuteChangedイベント:
            • コマンド実行の可否が変化したことを通知するためのイベント。
            • INotifyPropertyChangedインターフェイスのPropertyChangedイベントと同様
    • コマンドの使い方
      • データ・バインディングでコマンド処理
        1. ICommandインターフェイスを実装したクラスを作る(=コマンドの実装)
        2. 外部から与えるデータ(=ビューモデル)により、実装したコマンドをプロパティとして公開する
        3. 公開したプロパティを、<Button>要素や<MenuItem>要素などのCommandプロパティにデータ・バインディングする
      • ルーティング・コマンドを使ったコマンド処理
        • WPFでは標準で、RoutedCommandクラスを継承したRoutedUICommandクラスが用意されている。
        • RoutedCommandクラスは、以下のようなルーティング・イベントを発生させる
          • PreveiwExecuted: Excuteメソッドが呼ばれたときに発生するトンネル・イベント。
          • Executed: Excuteメソッドが呼ばれたときに発生するバブル・イベント。
          • PreviewCanExecute: CanExcuteメソッドが呼ばれたときに発生するトンネル・イベント。
          • CanExecute: CanExcuteメソッドが呼ばれたときに発生するバブル・イベント。
        • ルーティング・コマンドの利用手順
          1. ルーティング・コマンドの実体(=公開済みの静的プロパティの値)を、<Button>要素や<MenuItem>要素などのCommandプロパティに与える
          2. 標準のルーティング・コマンドは、例えば「Command="ApplicationCommands.Copy"」などと書くだけで利用可能
          3. コマンド処理を行う上位のUI要素でCommandBindingsプロパティを設定。
            • その中の<CommandBinding>要素のCommandプロパティにルーティング・コマンドの実体(=公開済みの静的プロパティの値)を指定し、Executedプロパティなどにイベント・ハンドラを登録する(=コマンド・バインディング)
        • WPF標準のルーティング・コマンド(=コマンド・ライブラリ)
          • ApplicationCommands: ファイルを開く、保存、ウィンドウを閉じるなど。
          • NavigationCommands: ブラウザの戻る、ホームを開く、前項/次項を開くなど。
          • ComponentCommands: リスト・アイテムやセルの移動、スクロール、フォーカスの移動など。
          • EditingCommands: テキスト編集用のコマンド。
          • MediaCommands: メディアの再生、停止、次のトラックへ移動など。
      • コマンド・ソース
        • WPFでは、コマンド・ソースを実装するためのICommandSourceインターフェイス(System.Windows.Input名前空間)があり、コマンド・ソースとなるUI要素を作る場合には、このインターフェイスを実装する。
        • ICommandSourceインターフェイスは以下のようなメンバを持っている。
          • Commandプロパティ: 発生させたいコマンドを設定する。
          • CommandParameterプロパティ:
            • ICommandインターフェイスのExecuteメソッドやCanExecuteメソッドの引数として渡されるパラメータを設定する。
          • CommandTargetプロパティ:
            • コマンドの実行対象を設定する。例えば、Pasteコマンドが実行される際に、どのUI要素に対して貼り付け処理を行うかなどを指定する。ルーティング・イベントでのみ利用可能。
        • コントロール
          • <Button>要素や<MenuItem>要素など、一部のコントロールはICommandSourceインターフェイスを実装している。
        • インプット・バインディング
          • コントロールのような、目に見えるコマンド・ソース以外に、キーボード・ショートカットや特殊なマウス・ジェスチャーなどの入力系のイベントを拾ってコマンド実行するための仕組み
          • UIElementクラス(System.Windows名前空間)(=WPFのUI要素の共通基底クラス)にはInputBindingsというプロパティがあり、これに<KeyBinding>要素、もしくは、<MouseBinding>要素を与えることでインプット・バインディングを行う。
    • MVVM(Model-View-ViewModel)パターン
      • ビューモデルの役割
        • モデルをラッピング
        • ビューから状態を分離
      • データ・バインディングによる疎結合
        • 標準的なインターフェイスを介した通知機構を利用する
      • ビューモデルの作成方法
        • INotifyPropertyChangedインターフェイスの実装
        • ICommandインターフェイス(=コマンド)の実装
        • IDataErrorInfoインターフェイス(=データ検証)の実装
  • WPF UI要素の基礎とレイアウト用のパネルを学ぼう
    • UI要素の継承階層
      1. DisptacherObjectクラス
        • 単一のスレッドのみが直接操作可能なオブジェクトを表すクラス
        • ほかのスレッドからは「Dispatcher: 配送係り」と呼ばれるオブジェクトを介してアクセスしなければならない。
        • パフォーマンス上の理由から、UI要素に対する操作を単一のスレッド(UIスレッド)上で行わなければならない。
      2. DependencyObjectクラス
        • 依存関係プロパティを利用するための共通基底クラスとなる。
      3. Visualクラス
        • 画面への描画にかかわる要素の共通基底クラスとなる。
      4. UIElementクラス
        • UI要素として必要な最低限の機能を備える共通基底クラスで、以下のような処理を行う。
          • レイアウト(=要素のサイズや配置の決定)用の抽象メンバ
          • ユーザー入力への応答
          • ルーティング・イベントの発生
          • 最低限の(一般的な)アニメーション
      5. FrameworkElementクラス
        • UIElementクラスに以下のようなWPF固有の機能を追加したものである。
          • レイアウトの具体的な実装
          • スタイル
          • プロパティ値の包含継承
          • WPF固有のアニメーション(ストーリーボードなど)
    • パネル(レイアウト用のUI要素)
      • 背景
        • 多様な表示方法への対応
        • 多言語対応
      • WPFのレイアウトの基礎概念
        • WPFのUI要素は自分自身だけでなく、レイアウト用のパネル(CanvasやGridなど)などを親要素とし、親子間で協調しながらサイズや配置を決定していく。
        • 親子間の協調のため、UIElementクラスには以下のようなメソッドが用意されている。
          • DesiredSizeプロパティ: 要素が希望するサイズ。
          • Measureメソッド: 親要素から利用可能な領域サイズを渡し、DesiredSizeプロパティの値を更新する。
          • Arrangeメソッド: 実際に要素のサイズや配置を決定する。
      • 標準提供されるパネル
        • StackPanel
          • 子要素を縦または横一列に整列する。
        • WrapPanel
          • 子要素を左から右に順番に並べ、幅を超えた分は右端で折り返すようにレイアウトする。
        • DockPanel
          • パネルの上下左右に子要素を貼り付ける(ドッキング)ようにレイアウトする。
          • ドッキングする位置はDockPanel.Dock属性(実体は添付プロパティ)によって行う。
        • Canvas
          • 固定レイアウトが必要なときにはCanvasクラス(System.Windows.Controls名前空間)を利用する。
          • 配置の指定はCanvas.Left属性やCanvas.Top属性(いずれも実体は添付プロパティ)を用いて行う。
        • Grid
          • 表形式(列位置と行位置の指定)でレイアウトを行う。
          • 表形式といっても、余白(Margin属性)やサイズ(Width属性とHeight属性)を使った固定的なレイアウトになりがちである。
          • 列の幅、および、行の高さには、以下のように3種類の指定方法がある。
            • 固定値指定:
              • - 「Width="100"」というように、数値のみを与えると、固定幅/高さになる。
            • 比率指定:
              • - 「Width="2*"」というように、数値の後ろにアスタリスクを付けると、比率指定となる。 - <Grid>要素自身のサイズ変更に応じて、比率を保ったまま行/列のサイズも変化する。
            • 自動:
              • - 「Width="auto"」というように、「auto」を指定すると、子要素のサイズに応じて行/列のサイズが自動調整される。 - フォント・サイズの変更と相性がよい。 - 多言語対応によって文字幅が変化した場合にも自動的に対応できる。
          • <Grid>要素の行・列のサイズを動的に変更したい場合、<Grid>要素の子に<GridSplitter>要素を配置する。
        • そのほか
          • UniformGridクラス:
            • すべての行・列が同じサイズの単純な表形式でレイアウトを行う。
            • 柔軟性はないものの、描画の性能はよい。
          • VirtualizingPanelクラス:
            • 子要素を仮想化するためのパネル。
              • - スクロールされるまで隠れていて見えない子要素を、実際に表示されるタイミングまで、サイズ計測も配置も行わない
            • 単体で利用するよりは、ListBoxクラスなどの内部で利用する。
  • WPFの「コントロール」を学ぼう
    • コントロール
      • Controlクラス
        • 外観設定
          • Background / BorderBrush / BorderThickness / Foreground
        • フォント
          • FontFamily / FontSize / FontStretch / FontStyle / FontWeight
        • 内容物のレイアウト決定
          • HorizontalContentAlignment / VerticalContentAlignment / Padding
        • フォーカス管理
          • IsTabStop / TabIndex
        • コントロール・テンプレート
          • Template
        • マウス・イベント
          • MouseDoubleClick / PreviewMouseDoubleClick
      • ContentControlクラス
        • コンテンツを1つだけ持つコントロールの基底クラスである。
        • アプリケーション本体となることの多いWindowクラスもContentControlクラスから派生している。
        • コンテンツを表すContentプロパティはobject型になっていて、何でも格納することができる。
        • 格納した型によって、以下のように、異なる表示が行われる。
          • UIElementクラスの場合、そのままUI要素として表示が行われる(OnRenderメソッドで描画を行う)
          • そのほかのクラスの場合、データ・テンプレートが設定されていればテンプレートを使った表示が行われる
          • データ・テンプレートも設定されていない場合、ToStringメソッドを使って文字列化された結果が表示される
        • ContentControlクラスの派生クラスの中に複数のUI要素を並べたい場合、
          • <Grid>要素などのパネルを置いて、その中にUI要素を並べる必要がある。
        • コンテンツへのテンプレート適用は、
          • ContentTemplateプロパティで明示的に指定する。
          • DataTypeプロパティを使った自動適用で行う。
      • HeaderedContentControlクラス
        • 単一のコンテンツを含みヘッダーを持つすべてのコントロールの基底クラス
      • ItemsControlクラス
        • 複数の項目を持つコントロールの基底クラス
        • コレクション・ビュー
          • ItemsSourceプロパティ経由で<ItemsControls>要素に渡されたデータ・ソースは、実際には間にコレクション・ビュー(collection view)というものが挟まったうえで表示される。
          • コレクション・ビューは、データ・ソースを変更せずに、ビュー上でだけデータの整列やグループ化を行うためのものである。
      • HeaderedItemsControlクラス
        • ヘッダ情報と複数の項目を持っているコントロールの基底クラス
    • コントロールを用途ごとに分類
      • レイアウト
        • ウィンドウ
          • ウィンドウ(=<Window>要素)もContentControlクラスを継承する一種のレイアウト用コントロールである。
      • ユーザーとの対話
        • ボタン
          • ButtonBase : ボタンの共通基底
          • Button :  通常のボタン
          • ToggleButton : CheckBoxコントロールなどの、オン/オフを切り替えられるコントロールの基底クラス
        • テキスト入力
          • TextBox : 通常のテキストボックス
          • RichTextBox : リッチ・テキストを編集するためのテキストボックス
          • PasswordBox : パスワード用のテキストボックス。入力された文字列は伏せ字で表示され、内部的に暗号化される
        • そのほかの対話要素
          • データ
            • DataGrid / Calendar / DatePicker
          • 選択
            • CheckBox / RadioButton / ComboBox / ListBox / TreeView / Slider
          • メニュー
            • Menu / ContextMenu / ToolBar
          • 情報表示
            • TextBlock / Label / ToolTip / Popup / ProgressBar / StatusBar
          • ナビゲーション
            • NavigationWindow / Frame / Page / Hyperlink
      • そのほか
        • メディア
          • Image / MediaElement
        • ドキュメント
          • DocumentViewer / FlowDocumentPageViewer / FlowDocumentReader / FlowDocumentScrollViewer / StickyNoteControl
        • デジタル・インク
          • InkCanvas
  • WPFの「グラフィックス」を学ぼう
  • WPFの「入力イベントとアニメーション」を学ぼう
    • 入力
      • 入力に関連するクラス
      • バブル・イベントとトンネル・イベント
        • バブル・イベント
          • 語頭に「Preview」が付いていない(KeyDown)
          • 処理済み=それ以上イベントが親要素に伝搬しない
        • トンネル・イベント
          • 語頭に「Preview」が付いている(PreviewKeyDown)
          • 親要素側でイベントを拾いたい
      • キーボード
      • テキスト入力
      • マウス
      • ドラッグ&ドロップ
      • スタイラス
      • マルチタッチ
    • アニメーション
  • WPF連載の落ち穂拾いと、標準以外のWPF関連パッケージ
    • スプラッシュ・スクリーン
      • アプリケーションのメイン・ウィンドウ表示前に何らかの重たい作業(例えば、大量のプラグイン読み込みなど)を行う際に、スプラッシュ・スクリーンを表示できる。
    • InkCanvasコントロール
      • 手書き入力ができる
配置