WPF拡張手法の使い分けを整理する― CustomControl / UserControl / Behavior / Helper の違い ―

コンピュータ

WPFでは、UIの振る舞いを拡張する方法が数多く用意されています。

  • カスタムコントロール

  • ユーザーコントロール

  • ビヘイビア

  • アタッチドプロパティ

  • static ヘルパー

しかし実際の開発では、

「どれを使うのが正解なのか分からない」

という場面に頻繁に遭遇します。

本記事では、WPFの拡張手法を目的別に整理し、
「どの場面で何を選ぶべきか」をまとめます。


WPF拡張手法一覧

まず全体像を整理します。

目的 手法
フルスクラッチで作る カスタムコントロール
既存コントロールを拡張 継承によるカスタムコントロール
複数コントロールを合成 UserControl
任意のプロパティを追加 Attached Property
振る舞いを追加 Behavior
軽量に拡張 static Helper

① カスタムコントロール(フルスクラッチ)

public class MyControl : Control

特徴

  • 見た目・構造・振る舞いをすべて自作

  • Generic.xaml によるテンプレート定義

  • テーマ変更が可能

向いている用途

  • 完全独自UI

  • 再利用前提のライブラリ

  • コントロールそのものを提供したい場合

注意点

  • 学習コストが高い

  • 実装量が多い

  • 個人開発では過剰になりがち


② 継承によるカスタムコントロール

public class FileListView : ListView

特徴

  • 既存コントロールの性質を維持

  • DependencyProperty を自然に追加できる

  • 普通のコントロールとして使用可能

向いている用途

  • ListView / TreeView などの拡張

  • 独自プロパティを持つコントロール


③ UserControl(複合コントロール)

<Grid>
    <TextBox/>
    <Button/>
</Grid>

特徴

  • 複数コントロールの組み合わせ

  • 実装が最も簡単

  • 視覚的に分かりやすい

注意点

  • 内部構造がブラックボックス化

  • Template差し替え不可

  • ライブラリ化には不向き

👉 アプリ内限定部品向け


④ Attached Property(プロパティの追加)

public static readonly DependencyProperty

できること

  • 任意のコントロールに状態を追加

  • クラス定義を変更せず拡張可能

  • 継承不要

代表例

  • CurrentDirectory

  • IsDragSource

  • ZoomFactor

  • SelectionMode

WPFらしさが最も強く出る拡張手法です。


⑤ Behavior(振る舞いの追加)

public class DragBehavior : Behavior<UIElement>

特徴

  • イベント処理の分離

  • XAMLから宣言的に指定可能

  • View とロジックの分離

向いている用途

  • マウス操作

  • ドラッグ&ドロップ

  • キーボード制御


⑥ static Helper(軽量拡張)

CanvasZoomHelper.Attach(canvas);

特徴

  • 実装が非常に軽い

  • すぐ使える

  • デバッグしやすい

注意点

  • 状態管理は工夫が必要

  • AttachedProperty や ConditionalWeakTable と併用することが多い

👉 個人開発では非常に実用的。


使い分けの判断基準

最後に判断フローとして整理します。

完全に新しいUIか?
カスタムコントロール
既存コントロールの拡張か?
継承コントロール
複数部品の合成か?
UserControl
プロパティを追加したいか?
AttachedProperty

 

振る舞いを追加したいか?
Behavior

軽く追加したいだけか?
static Helper


まとめ

筆者の好みは static Helper です。
理由としては、C# の基礎知識があれば誰でも拡張可能である点が挙げられます。

static クラスである以上、インスタンスごとの状態を直接保持することはできませんが、
ConditionalWeakTable という、まさにこの用途のために用意されたようなコレクションを利用することで、

  • コントロールごとの状態管理

  • 任意プロパティの追加

といったことが可能になります。

結果として、カスタムコントロールに近い振る舞いを実現できます。


もちろんデメリットも存在します。

static Helper は DependencyProperty を前提とした設計ではないため、
厳密な意味での MVVM 向きの実装ではありません

もっとも、コントロールそのものを拡張している時点で、
設計の関心はすでに View 側に寄っており、
MVVM の理想論からはかなり離れた位置にいます。

そのため、実用上はそれほど大きな問題にはならないでしょう。


もう一つのデメリットとして挙げるなら、

  • すべて自分で実装する必要があること

でしょうか。

フレームワークの補助はほぼ無く、
設計も責任もすべて自分で引き受けることになります。

ただし裏を返せば、

  • 挙動が完全に把握できる

  • デバッグしやすい

  • 不要な抽象化が入り込まない

という利点でもあります。


WPF には多くの拡張手法が用意されていますが、
重要なのは「どれが正しいか」ではなく、

自分が理解し、保守できる形であるか

だと筆者は考えています。

用途と規模に応じて拡張手法を選び分けることができれば、
WPF は今でも十分に柔軟で、長く付き合える UI フレームワークだと言えるでしょう。

コメント