WPF 標準コントロールデモアプリ › ScrollViewer
ScrollViewer Layout
ScrollViewer は内容がコンテナより大きい場合にスクロールバーを提供するコンテナコントロールです。垂直・水平スクロールバーの表示方法、論理スクロールと物理スクロールの切り替え、スクロール中の遅延更新などを制御できます。
概要
WPF の ScrollViewer は子要素を表示領域にクリップし、コンテンツが表示領域より大きい場合にスクロールバーを提供するコンテナコントロールです。ListBox、DataGrid、TreeView、TextBox など多くのコントロールが内部で ScrollViewer を使用しており、これらのコントロールのスクロールバーは ScrollViewer 添付プロパティでカスタマイズできます。
VerticalScrollBarVisibility と HorizontalScrollBarVisibility はそれぞれ 4 つの値を取ります。Disabled(スクロール不可)、Hidden(スクロール可能だがバーは非表示)、Auto(コンテンツが溢れた時だけバーを表示)、Visible(常にバーを表示)です。
CanContentScroll は論理スクロール(アイテム単位)と物理スクロール(ピクセル単位)を切り替えます。true(デフォルト)では仮想化パネルがアイテム単位でスクロールし、false ではすべてのアイテムを計測したうえでピクセル単位でスクロールします。
IsDeferredScrollingEnabled を true にすると、スクロールサムを動かしている間はコンテンツを更新せず、マウスボタンを離したときにまとめて更新します。大量データの DataGrid や ListView で動かしている間のパフォーマンスを大幅に向上させます。
画面キャプチャ

デモしているプロパティ
以下のプロパティが WPF 標準コントロールデモアプリでインタラクティブにデモされています。
| プロパティ | 設定値 | 説明 |
|---|---|---|
VerticalScrollBarVisibility | Disabled / Auto / Hidden / Visible | 垂直スクロールバーの表示方法を設定します。Auto はコンテンツが溢れたときのみ表示、Disabled は垂直スクロール不可、Hidden はスクロール可能だがバー非表示(タッチ操作向け)、Visible は常に表示です。動的に増減するコンテンツには Auto が最適で、横スクロールのみにしたい場合は Disabled を使います。Visible は常にスクロールバー領域を確保するため、コンテンツが収まる場合でもスペースを消費します。ほとんどのケースでは Auto を使い、Visible は意図的にスペースを固定したい特殊な場面に限定することを推奨します。 |
HorizontalScrollBarVisibility | Disabled / Auto / Hidden / Visible | 水平スクロールバーの表示方法を設定します。幅の広いテーブルやコンテナより横長の画像を表示する場合に Auto または Visible に設定します。多くのコントロールのデフォルトは Disabled(横スクロール不可)です。ListBox や TextBox などの内部 ScrollViewer の水平スクロールを有効にするには、コントロールの Disabled 設定をオーバーライドするため ScrollViewer.HorizontalScrollBarVisibility 添付プロパティをコントロール自身に設定します。コントロールを ScrollViewer で囲んで設定しても内部の設定が優先されるため、効果がない場合は添付プロパティを使ってください。 |
CanContentScroll | bool | 論理スクロール(アイテム単位)と物理スクロール(ピクセル単位)を切り替えます。True でアイテム単位、False でピクセル単位のスクロールになります。True(デフォルト)では仮想化パネルによるアイテム単位スクロールが有効になり、仮想化のパフォーマンスが最大限活かされます。False に設定するとすべてのアイテムを計測してからピクセル単位でスムーズにスクロールする動作になりますが、ItemsControl の仮想化が破棄されてすべてのアイテムが一度に描画されます。大量アイテムのリストで False を設定するとメモリと描画パフォーマンスが著しく低下するため、滑らかなスクロールが必要な画像ビューアーなど特定の用途に限定してください。 |
IsDeferredScrollingEnabled | bool | True のとき、スクロールサム(つまみ)をドラッグ中はコンテンツを更新せず、離したときにまとめて更新します。大量データのリストでドラッグパフォーマンスを向上させます。数千行の DataGrid でスクロールバーをドラッグする際、途中の無数の中間位置へのレンダリングをスキップし最終位置のみを描画するため大幅なパフォーマンス向上が得られます。ただしドラッグ中に中間コンテンツが表示されないため、どこにスクロールするか確認しながら操作したいユーザーには不便に感じられることがあります。データ量が真に大きい場合に限定して有効にするのが適切です。 |
ExtentHeight / ViewportHeight / ScrollableHeight / VerticalOffset (ReadOnly) | double | コンテンツの全高、表示領域の高さ、スクロール可能な高さ、現在のスクロール位置を示す読み取り専用プロパティです。コードからログ末尾へのスクロールや、最下部到達を検知してのページネーション実装などに使用します。ScrollableHeight - VerticalOffset < 1 で最下部到達を判定できます。ただしレイアウト処理中に VerticalOffset を読み取ると古い値が返ることがあります。Loaded イベント後や Dispatcher.BeginInvoke 経由で読み取ることで、レイアウト完了後の正確な値を取得できます。 |
XAML 使用例
<!-- 基本的な使用 -->
<ScrollViewer VerticalScrollBarVisibility="Auto"
HorizontalScrollBarVisibility="Auto"
CanContentScroll="False"
IsDeferredScrollingEnabled="True">
<Image Source="large-map.png" Stretch="None" />
</ScrollViewer>
<!-- ListBox のスクロールバーをカスタマイズ(添付プロパティ) -->
<ListBox ScrollViewer.VerticalScrollBarVisibility="Hidden"
ScrollViewer.CanContentScroll="False"
ItemsSource="{Binding Items}" />主な使用例
- 大きな画像のビューアー — 高解像度の画像を ScrollViewer で囲んでパン(スクロール)できるようにします。
- 長いフォーム — 多数の入力フィールドを持つ長いフォームを ScrollViewer で囲み、小さなウィンドウでも使えるようにします。
- ログ・出力パネル — 大量のログ行を表示する TextBox または ItemsControl を ScrollViewer で囲みます。
- コントロールのスクロールカスタマイズ — ListBox、TreeView などの内部 ScrollViewer を添付プロパティでカスタマイズします。
- パフォーマンス最適化 — 大規模 DataGrid の IsDeferredScrollingEnabled を有効にしてスクロール体験を向上させます。
ヒントとベストプラクティス
- ScrollViewer のネストを避ける — ScrollViewer を入れ子にするとレイアウトの計測が複雑になり、予期しない動作や外側のスクロールが機能しないことがあります。
- 仮想化パネルには CanContentScroll=true を保つ — CanContentScroll=False にするとすべてのアイテムが描画されて仮想化が無効になり、大量データでメモリ問題が起きます。
- プログラムからスクロール —
ScrollToBottom()やScrollToVerticalOffset(...)を呼び出してコードからスクロール位置を制御できます。 - マウスホイールとタッチ — ScrollViewer はマウスホイールとタッチのパン操作を自動でハンドルするため、追加のコードは不要です。
- キーボードスクロール — ScrollViewer は矢印キー、PageUp/Down、Home/End キーに対応しており、追加コードなしにキーボードスクロールが機能します。
- プログラムからの末尾スクロール —
ScrollToVerticalOffset(double.MaxValue)は末尾へのスクロールとして信頼性が低く、実際の最大オフセット値を超えると無視される場合があります。末尾へスクロールするにはScrollToBottom()またはScrollToVerticalOffset(scrollViewer.ScrollableHeight)を使用してください。 - 入れ子 ScrollViewer のホイールイベント — 内側の ScrollViewer がマウスホイールイベントを消費するため、外側の ScrollViewer にイベントが届かなくなります。外側にもスクロールを伝えたい場合は内側の
PreviewMouseWheelをハンドルしてイベントを手動でルーティングしてください。
関連コントロール
- ListBox — 内部に ScrollViewer を持つリストコントロール。添付プロパティでスクロールをカスタマイズできます。
- StackPanel — ScrollViewer の子要素として長いコンテンツを構成するのによく使われます。
- Viewbox — スクロールではなくスケーリングでコンテンツを表示する代替手段。
ソースコード
このデモ画面のソースコードは GitHub で公開しています。