# 機能設計書 41-VirtualizingStackPanel

## 概要

本ドキュメントは、Avalonia UIフレームワークにおけるVirtualizingStackPanel（仮想化スタックパネル）機能の設計仕様を定義する。VirtualizingStackPanelは大量のデータを効率的に表示するためのレイアウトパネルである。

### 本機能の処理概要

VirtualizingStackPanelは、大量のアイテムを持つリストやコレクションを効率的に表示するための仮想化機能を提供するパネルコントロールである。ビューポート内に表示される要素のみを実体化（Realize）し、画面外の要素はリサイクルまたは破棄することで、メモリ使用量とレンダリングパフォーマンスを最適化する。

**業務上の目的・背景**：大規模なデータセット（数千〜数百万件）を持つアプリケーションにおいて、すべてのアイテムを同時にUIとして生成するとメモリ不足やパフォーマンス低下を引き起こす。VirtualizingStackPanelはこの問題を解決し、スムーズなスクロール体験とメモリ効率を両立させる。

**機能の利用シーン**：大量のデータを表示するListBox、ComboBox、TreeViewなどのItemsControlの内部パネルとして使用される。チャットアプリケーション、データグリッド、ファイルブラウザなど、動的にアイテムが追加・削除されるシナリオで特に有効である。

**主要な処理内容**：
1. ビューポート（表示領域）の計算と管理
2. 表示に必要な要素のみを実体化（Realize）
3. 画面外要素のリサイクルプールへの退避
4. スクロールに応じた要素の動的な生成・破棄
5. スナップポイントの計算と提供
6. フォーカス管理とキーボードナビゲーションのサポート

**関連システム・外部連携**：ItemsControlおよびその派生クラス（ListBox、ComboBoxなど）と密接に連携する。ItemContainerGeneratorを通じてアイテムコンテナを生成・管理する。

**権限による制御**：本機能に権限による制御はない。すべてのアプリケーションで使用可能である。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 38 | ListBox | 主画面 | ListBoxコントロールのデモ。リスト形式の選択で仮想化パネルを使用 |
| 85 | Playground | 主画面 | 仮想化テスト用プレイグラウンド。大量データの効率的表示 |
| 86 | Chat | 主画面 | チャット風UIの仮想化デモ。動的アイテム追加 |

## 機能種別

レイアウト処理 / 仮想化処理 / メモリ最適化

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| Orientation | Orientation | No | レイアウトの方向（水平/垂直） | Horizontal または Vertical |
| CacheLength | double | No | バッファ領域の倍率（0〜2） | 0以上2以下 |
| AreHorizontalSnapPointsRegular | bool | No | 水平スナップポイントが等間隔か | - |
| AreVerticalSnapPointsRegular | bool | No | 垂直スナップポイントが等間隔か | - |

### 入力データソース

- ItemsControl.Items: 表示対象のアイテムコレクション
- EffectiveViewport: 実効ビューポート（表示可能領域）
- ItemContainerGenerator: アイテムコンテナ生成器

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| FirstRealizedIndex | int | 最初に実体化された要素のインデックス |
| LastRealizedIndex | int | 最後に実体化された要素のインデックス |
| ViewPort | Rect | 現在のビューポート領域 |
| ExtendedViewPort | Rect | キャッシュ領域を含む拡張ビューポート |
| DesiredSize | Size | パネルの必要サイズ |

### 出力先

- 画面表示: 仮想化されたコンテンツのレンダリング
- SnapPointsChanged イベント: スナップポイント変更の通知

## 処理フロー

### 処理シーケンス

```
1. MeasureOverride（測定フェーズ）
   └─ ビューポートを計算し、必要な要素を実体化

2. CalculateMeasureViewport
   └─ 表示に必要なビューポート範囲を決定

3. RealizeElements
   └─ アンカー要素から前後に要素を実体化

4. ArrangeOverride（配置フェーズ）
   └─ 実体化された要素を正しい位置に配置

5. OnEffectiveViewportChanged
   └─ スクロール時にビューポート変更を検知し再測定
```

### フローチャート

```mermaid
flowchart TD
    A[MeasureOverride開始] --> B{アイテム数 > 0?}
    B -->|No| C[デフォルトサイズを返却]
    B -->|Yes| D[ビューポート計算]
    D --> E{ビューポートが不連続?}
    E -->|Yes| F[全要素をリサイクル]
    E -->|No| G[要素の実体化]
    F --> G
    G --> H[前方要素の実体化]
    H --> I[後方要素の実体化]
    I --> J[不要要素のリサイクル]
    J --> K[DesiredSize計算]
    K --> L[ArrangeOverride]
    L --> M[要素の配置]
    M --> N[完了]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-001 | 仮想化閾値 | CacheLengthで指定した倍率分の追加要素をバッファとして保持 | 常時適用 |
| BR-002 | リサイクル優先 | 同じRecycleKeyを持つ要素は新規生成せずリサイクルプールから取得 | コンテナ再利用時 |
| BR-003 | フォーカス保持 | フォーカスを持つ要素はビューポート外でもリサイクルしない | フォーカス時 |

### 計算ロジック

**要素サイズの推定**：
```
EstimatedElementSizeU = Σ(実体化要素のサイズ) / 実体化要素数
```

**拡張ビューポートの計算**：
```
BufferSize = ViewportSize * CacheLength
ExtendedViewportStart = ViewportStart - BufferSize
ExtendedViewportEnd = ViewportEnd + BufferSize
```

## データベース操作仕様

本機能はデータベース操作を行わない。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | InvalidOperationException | ItemContainerGeneratorがnull | ItemsControlへの接続を確認 |
| - | ArgumentOutOfRangeException | 無効なインデックスでのコンテナ取得 | 範囲チェックを実施 |

### リトライ仕様

リトライは行わない。レイアウト失敗時は次のレイアウトパスで再試行される。

## トランザクション仕様

トランザクション管理は不要（UIレイアウト処理のため）。

## パフォーマンス要件

- 1万件のアイテムでも60FPSのスムーズスクロールを維持
- メモリ使用量はビューポート内要素数に比例（O(n)、nはビューポート内要素数）
- 要素の実体化・リサイクルは1フレーム以内に完了

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

特になし。UIレイアウト処理のため、セキュリティ上の懸念は発生しない。

## 備考

- 可変高さのアイテムをサポートするが、推定サイズは平均値を使用
- スナップポイント機能はスクロールの「カクつき」を防止するために使用

---

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

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

### 推奨読解順序

#### Step 1: データ構造を理解する

仮想化パネルの状態管理に使用されるデータ構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | MeasureViewport | `src/Avalonia.Controls/VirtualizingStackPanel.cs` | 1184-1194行目の構造体。測定時のビューポート情報を保持 |
| 1-2 | RealizedStackElements | `src/Avalonia.Controls/Utils/RealizedStackElements.cs` | 実体化された要素のコレクション管理 |

**読解のコツ**: MeasureViewport構造体のフィールド（anchorIndex、anchorU、viewportUStart、viewportUEnd）がビューポート計算の核心。

#### Step 2: エントリーポイントを理解する

レイアウトパスの開始点を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | MeasureOverride | `src/Avalonia.Controls/VirtualizingStackPanel.cs` | 187-239行目。測定フェーズのエントリーポイント |
| 2-2 | ArrangeOverride | `src/Avalonia.Controls/VirtualizingStackPanel.cs` | 241-292行目。配置フェーズのエントリーポイント |

**主要処理フロー**:
1. **187-193行目**: アイテム数のチェックとビューポート更新待機
2. **205-206行目**: 実体化要素コレクションの初期化
3. **215行目**: ビューポート計算（CalculateMeasureViewport呼び出し）
4. **223行目**: 要素の実体化（RealizeElements呼び出し）
5. **226行目**: measureElementsとrealizedElementsの交換

#### Step 3: 仮想化ロジックを理解する

要素の実体化・リサイクルのコアロジック。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | RealizeElements | `src/Avalonia.Controls/VirtualizingStackPanel.cs` | 706-782行目。前後方向に要素を実体化 |
| 3-2 | GetOrCreateElement | `src/Avalonia.Controls/VirtualizingStackPanel.cs` | 784-805行目。要素の取得または生成 |
| 3-3 | RecycleElement | `src/Avalonia.Controls/VirtualizingStackPanel.cs` | 885-913行目。要素のリサイクル処理 |

**主要処理フロー**:
- **729-747行目**: アンカーから前方への要素実体化ループ
- **760-778行目**: アンカーから後方への要素実体化ループ
- **798-799行目**: リサイクルプールからの要素取得試行

#### Step 4: ビューポート変更処理を理解する

スクロール時のビューポート更新処理。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | OnEffectiveViewportChanged | `src/Avalonia.Controls/VirtualizingStackPanel.cs` | 955-1096行目。ビューポート変更ハンドラ |

**主要処理フロー**:
- **964行目**: 新しいビューポートの計算
- **968-1003行目**: 拡張ビューポートの計算（バッファ含む）
- **1033-1041行目**: 再測定が必要かの判定

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

```
VirtualizingStackPanel.MeasureOverride
    │
    ├─ CalculateMeasureViewport
    │      └─ GetOrEstimateAnchorElementForViewport
    │
    ├─ RealizeElements
    │      ├─ GetOrCreateElement
    │      │      ├─ GetRealizedElement
    │      │      ├─ GetRecycledElement
    │      │      └─ CreateElement
    │      │             └─ ItemContainerGenerator.CreateContainer
    │      │
    │      └─ RecycleElementsBefore / RecycleElementsAfter
    │
    └─ CalculateDesiredSize

VirtualizingStackPanel.ArrangeOverride
    │
    └─ Element.Arrange (各要素の配置)
```

### データフロー図

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

Items Collection ──────▶ MeasureOverride ──────────────▶ DesiredSize
                              │
EffectiveViewport ─────────▶ │
                              │
                         RealizeElements
                              │
                         ┌────┴────┐
                         ▼         ▼
              GetOrCreateElement  RecycleElement
                         │         │
                         ▼         ▼
              [実体化要素]    [リサイクルプール]
                         │
                         ▼
                   ArrangeOverride
                         │
                         ▼
                 [画面描画された要素]
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| VirtualizingStackPanel.cs | `src/Avalonia.Controls/VirtualizingStackPanel.cs` | ソース | 仮想化スタックパネルの主要実装 |
| VirtualizingPanel.cs | `src/Avalonia.Controls/VirtualizingPanel.cs` | ソース | 仮想化パネルの基底クラス |
| RealizedStackElements.cs | `src/Avalonia.Controls/Utils/RealizedStackElements.cs` | ソース | 実体化要素の管理ユーティリティ |
| IScrollSnapPointsInfo.cs | `src/Avalonia.Controls/IScrollSnapPointsInfo.cs` | ソース | スナップポイント情報インターフェース |
| ItemContainerGenerator.cs | `src/Avalonia.Controls/Generators/ItemContainerGenerator.cs` | ソース | アイテムコンテナ生成器 |
