はじめに
この設計スタイルは、ツール・ユーティリティ系アプリの作成を想定してデザインしています。
開発規模は個人向けです。
XAMLの役割
やること
-
画面構造の定義
-
Grid / StackPanel / DockPanel など
-
-
コントロール階層の定義
-
見た目の定義
-
色、マージン、フォント、サイズ
-
-
Style / Template の定義
-
コンテナ系コントロールのデータ表示
-
ItemsSource
-
-
選択状態の同期
-
SelectedItem
-
SelectedIndex
-
-
XAML 内で完結するデータバインディング
-
表示専用の Converter
出来るが、やらないこと
-
UI 振る舞いロジックの記述
-
状態遷移の制御
-
処理フローの分岐
-
ビジネスロジックの記述
-
コマンド実装の集中管理
-
画面全体の状態をバインディングで制御
-
トリガー多用による疑似ロジック化
-
複雑な MultiBinding
-
ViewModel を前提とした設計依存
-
XAML 側でのイベント処理完結
ViewState クラスの役割
やること
-
アプリ(ウィンドウ)の状態を管理するプロパティを集約する
-
表示状態
-
選択状態
-
一時的な UI 状態
-
-
INotifyPropertyChangedを実装する -
データバインディングのソースになる(ことが出来る)
-
XAML とコードビハインドから参照可能な状態コンテナとして振る舞う
やらないこと
-
コマンドの定義
-
ICommandを実装しない -
RoutedCommandを保持しない
-
-
メソッドによる処理の実装
-
画面操作ロジックの記述
-
状態遷移の判断
-
他オブジェクトとの連携制御
-
ビジネスロジックの保持
補足
ViewState は 振る舞いを持たない純粋な状態オブジェクトであり、
-
値を保持する
-
変更を通知する
以上の役割に限定します。
処理の起点は常にコードビハインド側にあり、
ViewState はその結果を反映するための 受動的なデータ構造として扱います。
Helper の役割
やること
-
static class として定義する
-
WPF に依存するメソッドを集約する
-
コントロールの振る舞いを提供する
-
UI 実装都合の状態を保持する場合がある(ConditionalWeakTable)
やらないこと
-
グローバル状態の管理
-
アプリ状態の管理(ViewState の代替)
-
ビジネスロジックの実装
-
状態遷移の判断
Utilities の役割
やること
-
static classとして定義する -
WPF に依存しない処理をまとめる
-
純粋な C# ロジックを提供する
-
UI とは無関係な共通処理を集約する
-
どのアプリケーション層からでも利用可能な機能を提供する
想定される内容
-
ファイル操作・パス処理
-
文字列処理
-
日付・数値変換
-
設定ファイル読み書き
-
ログ出力
-
コマンドライン引数解析
-
計算処理
-
データ変換ロジック
やらないこと
-
WPF 型への依存
-
Window -
DependencyObject -
Dispatcherなど
-
-
UI 操作
-
バインディング関連処理
-
イベント・入力処理
-
表示状態の管理
-
ViewState や Helper の代替
補足
Utilities は 最下層のロジック層に位置します。
-
UI 技術に依存しない
-
再利用性が高い
-
単体テストが容易
という特徴を持ちます。
位置関係
Utilities は、上位層から一方向に呼び出されるのみで、
UI 側の存在を一切知りません。
RoutedCommand の扱い
基本方針
-
ICommandを直接使用しない -
WPF 標準の
RoutedCommand / RoutedUICommandを使用する -
コマンドは「処理の抽象化」ではなく 入力配線の仕組みとして扱う
やること
-
RoutedCommandを UI 入力の受け口として使用する -
CommandBindingに処理を定義する -
KeyBinding/InputBindingと組み合わせて使用する -
実際の処理はコードビハインドのメソッドに委譲する
-
必要に応じて Helper 経由で生成・登録する
やらないこと
-
ICommand実装クラスを作成しない-
RelayCommand
-
DelegateCommand
-
ViewModelCommand
-
-
コマンドをロジック単位として扱わない
-
コマンドに処理内容を持たせない
-
ViewModel にコマンドを集約しない(ViewModelがいないので)
-
コマンドの再利用性を設計しない
コードビハインドの役割
やること
-
画面単位の制御を担当する
-
UI 操作を起点とした処理の流れを記述する
-
ユーザー操作と処理ロジックを結び付ける
-
ViewState の値を更新する
-
Helper を呼び出して WPF 固有処理を実行する
-
Utilities を利用して非 UI ロジックを実行する
-
RoutedCommand の実行先を実装する
-
初期化・終了処理を記述する
具体的な責務
-
ボタン・メニュー・ホットキーなど入力の受信
-
処理順序の制御
-
画面状態の切り替え
-
非同期処理の開始・完了制御
-
例外のハンドリング
-
UI 更新タイミングの調整
この設計のメリット
-
Helper と Utilities が継続的に増えていく
-
一度書いた処理を次のアプリでもそのまま使える
-
-
WPF 固有処理と非依存処理が自然に分離される
-
Helper:WPF 依存
-
Utilities:WPF 非依存
-
-
再利用単位が明確
-
Window や ViewModel ではなく
メソッド単位・機能単位で再利用できる
-
-
新しいアプリを作るたびに初期実装が減る
-
ドラッグ&ドロップ
-
ホットキー
-
ファイル選択
-
表示制御
-
-
コードビハインドは薄く保たれる
-
実装の多くが Helper / Utilities 側に移動する
-
-
アプリごとの差分が見えやすい
-
「何をするか」だけがコードビハインドに残る
-
-
ライブラリとして切り出しやすい
-
Helper / Utilities は独立性が高い
-
-
開発速度が継続的に向上する
-
新規アプリほど楽になる構造
-
-
技術的負債になりにくい
-
フレームワーク依存が少ない
-
MVVM 固有構造に縛られない
-
要点
-
コードビハインドは「使う側」
-
Helper / Utilities は「資産側」
という役割分担になる。
アプリが増えるほど、
となり、開発は段階的に楽になっていく。

コメント