# 通知設計書 10-NotificationClosed

## 概要

本ドキュメントは、Avalonia UIフレームワークにおけるNotificationClosed（通知クローズ）イベントの設計について記述する。NotificationClosedイベントは、NotificationCardが閉じられたことを通知するRoutedEventであり、NotificationCard.NotificationClosedEvent として定義されている。

### 本通知の処理概要

NotificationClosedイベントは、UI通知（NotificationCard）が閉じられたときにアプリケーションに通知を行う仕組みである。

**業務上の目的・背景**：通知システムにおいて、通知が閉じられたタイミングを検知することは重要である。通知のクローズ時にクリーンアップ処理を実行したり、ユーザーの応答を記録したり、次のアクションをトリガーしたりする必要がある場合がある。NotificationClosedイベントは、自動クローズ（タイムアウト）、ユーザーによる明示的なクローズ、プログラムによるクローズのいずれの場合でも発火され、通知ライフサイクルの終了を検知できる。

**通知の送信タイミング**：NotificationCard の IsClosed プロパティが true に変更されたとき、または IsClosing が true の状態で IsClosed が変更されたとき。具体的には、自動クローズタイマー満了時、ユーザーがクローズボタンをクリックしたとき、通知をクリックしたとき、またはプログラムから Close() メソッドが呼び出されたとき。

**通知の受信者**：NotificationClosedイベントはBubble RoutingStrategy を使用するため、NotificationCard から親要素へとイベントがバブルアップする。主な受信者はWindowNotificationManager であり、通知カードのリストから該当カードを削除し、OnClose コールバックを実行する。

**通知内容の概要**：RoutedEventArgs オブジェクトとして表現される。イベントソースは閉じられた NotificationCard であり、イベントを通じてどの通知が閉じられたかを特定できる。

**期待されるアクション**：WindowNotificationManager が通知カードを内部リストから削除し、Notification.OnClose コールバックを実行する。アプリケーションは必要に応じてクリーンアップ処理や後続のアクションを実行する。

## 通知種別

RoutedEvent（UIイベント）

## 送信仕様

### 基本情報

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

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

NotificationClosedEvent はバブリングイベントとして定義されており、NotificationCard から親要素に向かって伝播する。WindowNotificationManager は NotificationCard を作成する際にこのイベントのハンドラを登録し、通知のクローズを検知する。

## 通知テンプレート

### NotificationClosed イベントの場合

| 項目 | 内容 |
|-----|------|
| イベント名 | NotificationClosed |
| イベント引数型 | RoutedEventArgs |
| ルーティング方式 | Bubble |

### イベント内容

```csharp
RaiseEvent(new RoutedEventArgs(NotificationClosedEvent));
```

### 添付ファイル

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

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| Source | イベント発生元のNotificationCard | イベント引数 | Yes |
| RoutedEvent | NotificationClosedEvent | イベント定義 | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| タイムアウト | DispatcherTimer 満了 | Expiration 時間経過 | 自動クローズ |
| ユーザー操作 | クローズボタンクリック | CloseOnClick = true | 明示的クローズ |
| ユーザー操作 | 通知クリック | PointerPressed | クリックによるクローズ |
| プログラム | Close() メソッド呼び出し | 明示的呼び出し | プログラムによるクローズ |
| プログラム | WindowNotificationManager.Close(content) | 特定通知のクローズ | コンテンツ指定クローズ |
| プログラム | WindowNotificationManager.CloseAll() | 全通知のクローズ | 一括クローズ |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| IsClosing = true の状態で再度Close | 二重クローズは発火しない |
| 既にクローズ済み | クローズ処理は一度のみ |

## 処理フロー

### NotificationClosed 発火フロー

```mermaid
flowchart TD
    A[クローズトリガー発生] --> B{IsClosing?}
    B -->|Yes| C[処理スキップ]
    B -->|No| D[IsClosing = true]
    D --> E[クローズアニメーション開始]
    E --> F[IsClosed = true]
    F --> G[OnPropertyChanged: IsClosed]
    G --> H[RaiseEvent: NotificationClosedEvent]
    H --> I[イベントバブルアップ]
    I --> J[WindowNotificationManager受信]
    J --> K[OnClose コールバック実行]
    K --> L[_items.Remove 実行]
    L --> M[処理完了]
    C --> M
```

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

### 参照テーブル一覧

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

### 更新テーブル一覧

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

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| OnClose例外 | コールバック内で例外発生 | try-catchでハンドリング |
| 二重クローズ | 既にクローズ処理中 | IsClosing フラグで防止 |

### リトライ仕様

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

## 配信設定

### レート制限

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

### 配信時間帯

通知クローズ時（アプリケーション実行中、常時）

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

- OnClose コールバック内での処理は適切にエラーハンドリングすること
- コールバック内で長時間の処理を行わないこと（UIスレッドをブロックしない）

## 備考

- NotificationClosedEvent は RoutingStrategies.Bubble で定義されている
- IsClosing プロパティで二重クローズを防止
- IsClosed プロパティの変更時にイベントが発火
- OnClose コールバックは Notification クラスのプロパティとして設定可能

---

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

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

### 推奨読解順序

#### Step 1: イベント定義を理解する

NotificationClosedEvent の定義を確認。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | NotificationCard.cs | `src/Avalonia.Controls/Notifications/NotificationCard.cs` | NotificationClosedEvent の定義 |

**読解のコツ**: NotificationCard.cs の78-79行目で RoutedEvent.Register を使用して NotificationClosedEvent を定義。RoutingStrategies.Bubble でバブリングイベントとして登録。

#### Step 2: イベント発火を理解する

NotificationClosedEvent がいつ発火されるかを確認。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | NotificationCard.cs | `src/Avalonia.Controls/Notifications/NotificationCard.cs` | OnPropertyChanged でのイベント発火 |

**主要処理フロー**:
- **146-169行目**: OnPropertyChanged メソッド
- **160-168行目**: IsClosed プロパティ変更時の処理
  - IsClosing または IsClosed が true の場合にイベント発火
  - RaiseEvent(new RoutedEventArgs(NotificationClosedEvent))

#### Step 3: イベントハンドリングを理解する

WindowNotificationManager でのイベント処理を確認。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | WindowNotificationManager.cs | `src/Avalonia.Controls/Notifications/WindowNotificationManager.cs` | NotificationClosed ハンドラ |

**主要処理フロー**:
- **148-152行目**: notificationControl.NotificationClosed イベントハンドラ登録
  - onClose?.Invoke() で Notification.OnClose コールバックを実行
  - _items.Remove(notificationControl) で通知カードをリストから削除

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

```
クローズトリガー
    │
    ├─ DispatcherTimer.RunOnce（自動クローズ）
    │      └─ NotificationCard.Close()
    │
    ├─ PointerPressed（クリック）
    │      └─ NotificationCard.Close()
    │
    └─ CloseOnClick ボタン
           └─ NotificationCard.Close()
                  │
                  ├─ IsClosing = true
                  │
                  └─ IsClosed = true（アニメーション後）
                         │
                         └─ OnPropertyChanged(IsClosedProperty)
                                │
                                └─ RaiseEvent(NotificationClosedEvent)
                                       │
                                       └─ WindowNotificationManager
                                              ├─ onClose?.Invoke()
                                              └─ _items.Remove()
```

### データフロー図

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

クローズ操作             NotificationCard                   RoutedEvent
├─ Timer満了      ───▶   ├─ Close() 呼び出し       ───▶    ├─ NotificationClosedEvent
├─ クリック              ├─ IsClosing = true                │      └─ Source = Card
├─ ボタン                ├─ IsClosed = true                 │
└─ API呼び出し           └─ RaiseEvent                      └─ WindowNotificationManager
                                │                                    ├─ OnClose コールバック
                                ▼                                    └─ リストから削除
                         バブリング伝播
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| NotificationCard.cs | `src/Avalonia.Controls/Notifications/NotificationCard.cs` | ソース | NotificationClosedEvent 定義とイベント発火 |
| WindowNotificationManager.cs | `src/Avalonia.Controls/Notifications/WindowNotificationManager.cs` | ソース | イベントハンドリングとコールバック実行 |
| Notification.cs | `src/Avalonia.Controls/Notifications/Notification.cs` | ソース | OnClose コールバック定義 |
| INotification.cs | `src/Avalonia.Controls/Notifications/INotification.cs` | ソース | OnClose プロパティ定義 |
