# 通知設計書 9-CollectionChanged

## 概要

本ドキュメントは、Avalonia UIフレームワークにおけるCollectionChanged（コレクション変更）通知の設計について記述する。CollectionChanged通知は、INotifyCollectionChanged インターフェースを通じてコレクションの変更（追加・削除・移動・リセット）を通知するための仕組みである。

### 本通知の処理概要

CollectionChanged通知は、コレクションの内容が変更されたことをデータバインディングシステムやUIコントロールに通知するための仕組みである。

**業務上の目的・背景**：リスト表示やグリッド表示を含むアプリケーションにおいて、データソースのコレクションが変更されたときにUIを効率的に更新する必要がある。CollectionChangedイベントは、追加・削除・移動・置換・リセットのいずれの変更が発生したかを通知し、UIが差分更新を行えるようにする。これにより、コレクション全体を再描画する必要がなくなり、パフォーマンスが向上する。

**通知の送信タイミング**：コレクションに対して Add, Remove, Insert, Clear, Move などの変更操作が実行されたとき。AvaloniaList<T> などの通知対応コレクションクラスが自動的にイベントを発火する。

**通知の受信者**：CollectionChanged イベントをサブスクライブしているリスナー。主に ItemsControl などのコレクションを表示するUIコントロール、およびコレクションをバインドしているバインディングシステムが受信者となる。

**通知内容の概要**：NotifyCollectionChangedEventArgs オブジェクトとして表現され、変更の種類（Action）、追加されたアイテム（NewItems）、削除されたアイテム（OldItems）、インデックス情報などが含まれる。

**期待されるアクション**：UIコントロールが変更種類に応じた差分更新を実行する。例えば、Add の場合は新しいアイテムのみを追加し、Remove の場合は該当アイテムのみを削除する。

## 通知種別

イベント通知（.NET 標準の INotifyCollectionChanged インターフェース）

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 同期（イベント発火） |
| 優先度 | 通常 |
| リトライ | なし |

### 送信先決定ロジック

CollectionChanged イベントをサブスクライブしているすべてのハンドラに通知が送信される。CollectionChangedEventManager を通じてイベントが伝播し、UIコントロールがコレクションの変更を検知する。

## 通知テンプレート

### CollectionChanged イベントの場合

| 項目 | 内容 |
|-----|------|
| イベント名 | CollectionChanged |
| イベント引数型 | NotifyCollectionChangedEventArgs |
| アクション | Add, Remove, Replace, Move, Reset |

### イベント内容

```csharp
CollectionChanged?.Invoke(this, new NotifyCollectionChangedEventArgs(action, changedItems, index));
```

### アクション一覧

| アクション | 説明 | 追加情報 |
|----------|------|---------|
| Add | アイテム追加 | NewItems, NewStartingIndex |
| Remove | アイテム削除 | OldItems, OldStartingIndex |
| Replace | アイテム置換 | NewItems, OldItems, Index |
| Move | アイテム移動 | NewItems, OldStartingIndex, NewStartingIndex |
| Reset | コレクションリセット | なし（全体再読み込み） |

### 添付ファイル

| ファイル名 | 形式 | 条件 | 説明 |
|----------|------|------|------|
| なし | - | - | イベント通知のため添付ファイルは存在しない |

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| Action | 変更の種類 | NotifyCollectionChangedAction | Yes |
| NewItems | 追加されたアイテム | コレクション操作 | No（Add, Replace, Move） |
| OldItems | 削除されたアイテム | コレクション操作 | No（Remove, Replace, Move） |
| NewStartingIndex | 追加位置 | コレクション操作 | No |
| OldStartingIndex | 削除位置 | コレクション操作 | No |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| Add操作 | Add, Insert, AddRange, InsertRange | アイテムが追加された | Add アクション |
| Remove操作 | Remove, RemoveAt, RemoveRange, RemoveAll | アイテムが削除された | Remove アクション |
| Clear操作 | Clear | コレクションがクリアされた | Reset または Remove（設定による） |
| Move操作 | Move, MoveRange | アイテムが移動された | Move アクション |
| Replace操作 | インデクサー設定 | アイテムが置換された | Replace アクション |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| イベント未サブスクライブ | ハンドラがない場合はイベント発火されない |
| 同一値での置換 | 新旧の値が等しい場合は発火しない |

## 処理フロー

### CollectionChanged 発火フロー

```mermaid
flowchart TD
    A[コレクション操作] --> B{操作の種類}
    B -->|Add| C[NotifyAdd 呼び出し]
    B -->|Remove| D[NotifyRemove 呼び出し]
    B -->|Clear| E{ResetBehavior}
    B -->|Move| F[Move イベント作成]
    B -->|Replace| G[Replace イベント作成]
    E -->|Reset| H[Reset イベント作成]
    E -->|Remove| I[Remove イベント作成（全アイテム）]
    C --> J[CollectionChanged.Invoke]
    D --> J
    F --> J
    G --> J
    H --> J
    I --> J
    J --> K[リスナーに通知]
    K --> L[UI差分更新]
    L --> M[処理完了]
```

## データベース参照・更新仕様

### 参照テーブル一覧

| テーブル名 | 用途 | 備考 |
|-----------|------|------|
| なし | - | イベント通知のためデータベースは使用しない |

### 更新テーブル一覧

| テーブル名 | 操作 | 概要 |
|-----------|------|------|
| なし | - | イベント通知のためデータベースは使用しない |

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| インデックス範囲外 | 不正なインデックス | コレクション境界を確認 |
| スレッド問題 | UIスレッド外からの更新 | Dispatcher を使用 |
| メモリリーク | イベントハンドラ未解除 | CollectionChangedEventManager を使用 |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | なし |
| リトライ間隔 | - |
| リトライ対象エラー | - |

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 1分あたり上限 | なし |
| 1日あたり上限 | なし |

### 配信時間帯

コレクション変更時（アプリケーション実行中、常時）

## セキュリティ考慮事項

- コレクション内のアイテムに機密情報が含まれる場合、デバッグ出力に注意
- イベントハンドラの追加/削除を適切に管理してメモリリークを防止

## 備考

- AvaloniaList<T> は INotifyCollectionChanged を実装
- ResetBehavior プロパティで Clear 時の動作（Reset または Remove）を制御可能
- CollectionChangedEventManager を使用して弱参照イベントハンドラを実装可能
- INotifyCollectionChangedDebug インターフェースでデバッグ用のサブスクライバー取得が可能

---

## コードリーディングガイド

本通知を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: インターフェースを理解する

INotifyCollectionChanged インターフェースの実装を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | AvaloniaList.cs | `src/Avalonia.Base/Collections/AvaloniaList.cs` | INotifyCollectionChanged の実装 |

**読解のコツ**: AvaloniaList.cs の93-97行目で CollectionChanged イベントを定義。50行目で INotifyCollectionChanged を実装。

#### Step 2: 通知ロジックを理解する

各種コレクション操作での通知発火を確認。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | AvaloniaList.cs | `src/Avalonia.Base/Collections/AvaloniaList.cs` | NotifyAdd, NotifyRemove メソッド |

**主要処理フロー**:
- **703-711行目**: NotifyAdd メソッド（リスト追加）
- **719-728行目**: NotifyAdd メソッド（単一アイテム追加）
- **744-753行目**: NotifyRemove メソッド（リスト削除）
- **760-769行目**: NotifyRemove メソッド（単一アイテム削除）
- **438-453行目**: Move メソッドで Move イベント発火
- **170-198行目**: インデクサーセッターで Replace イベント発火
- **241-262行目**: Clear メソッドで Reset または Remove イベント発火

#### Step 3: ResetBehavior を理解する

Clear 時の動作制御を確認。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | AvaloniaList.cs | `src/Avalonia.Base/Collections/AvaloniaList.cs` | ResetBehavior 列挙型と Clear の動作 |

**主要処理フロー**:
- **10-26行目**: ResetBehavior 列挙型の定義
- **112行目**: ResetBehavior プロパティ
- **245-253行目**: ResetBehavior に応じた Clear の動作

### プログラム呼び出し階層図

```
AvaloniaList<T> 操作
    │
    ├─ Add / AddRange / Insert / InsertRange
    │      └─ NotifyAdd(items, index)
    │             └─ CollectionChanged.Invoke(Add)
    │
    ├─ Remove / RemoveAt / RemoveRange / RemoveAll
    │      └─ NotifyRemove(items, index)
    │             └─ CollectionChanged.Invoke(Remove)
    │
    ├─ Clear
    │      └─ ResetBehavior 判定
    │             ├─ Reset → CollectionChanged.Invoke(Reset)
    │             └─ Remove → CollectionChanged.Invoke(Remove, 全アイテム)
    │
    ├─ Move / MoveRange
    │      └─ CollectionChanged.Invoke(Move)
    │
    └─ this[index] = value
           └─ CollectionChanged.Invoke(Replace)
                  │
                  ▼
           UIコントロール差分更新
```

### データフロー図

```
[入力]                    [処理]                              [出力]

コレクション操作         AvaloniaList<T>                    イベント
├─ 追加アイテム   ───▶   ├─ 内部リストを更新        ───▶    ├─ NotifyCollectionChangedEventArgs
├─ 削除アイテム          ├─ NotifyXxx メソッド呼び出し       │      ├─ Action
├─ インデックス          └─ CollectionChanged.Invoke         │      ├─ NewItems
└─ アクション                   │                            │      ├─ OldItems
                                ▼                            │      └─ Index
                         ItemsControl / リスナー             │
                         └─ 差分更新                         └─ UI更新
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| AvaloniaList.cs | `src/Avalonia.Base/Collections/AvaloniaList.cs` | ソース | INotifyCollectionChanged 実装 |
| IAvaloniaReadOnlyList.cs | `src/Avalonia.Base/Collections/IAvaloniaReadOnlyList.cs` | ソース | 読み取り専用リストインターフェース |
| NotifyCollectionChangedExtensions.cs | `src/Avalonia.Base/Collections/NotifyCollectionChangedExtensions.cs` | ソース | 拡張メソッド |
| CollectionChangedEventManager.cs | `src/Avalonia.Controls/Utils/CollectionChangedEventManager.cs` | ソース | イベントマネージャー |
| INotifyCollectionChangedDebug.cs | `src/Avalonia.Base/Diagnostics/INotifyCollectionChangedDebug.cs` | ソース | デバッグインターフェース |
| ItemsControl.cs | `src/Avalonia.Controls/ItemsControl.cs` | ソース | コレクション表示コントロール |
