WPF 標準コントロールデモアプリ › ScrollViewer

ScrollViewer Layout

ScrollViewer は内容がコンテナより大きい場合にスクロールバーを提供するコンテナコントロールです。垂直・水平スクロールバーの表示方法、論理スクロールと物理スクロールの切り替え、スクロール中の遅延更新などを制御できます。

概要

WPF の ScrollViewer は子要素を表示領域にクリップし、コンテンツが表示領域より大きい場合にスクロールバーを提供するコンテナコントロールです。ListBoxDataGridTreeViewTextBox など多くのコントロールが内部で ScrollViewer を使用しており、これらのコントロールのスクロールバーは ScrollViewer 添付プロパティでカスタマイズできます。

VerticalScrollBarVisibilityHorizontalScrollBarVisibility はそれぞれ 4 つの値を取ります。Disabled(スクロール不可)、Hidden(スクロール可能だがバーは非表示)、Auto(コンテンツが溢れた時だけバーを表示)、Visible(常にバーを表示)です。

CanContentScroll は論理スクロール(アイテム単位)と物理スクロール(ピクセル単位)を切り替えます。true(デフォルト)では仮想化パネルがアイテム単位でスクロールし、false ではすべてのアイテムを計測したうえでピクセル単位でスクロールします。

IsDeferredScrollingEnabled を true にすると、スクロールサムを動かしている間はコンテンツを更新せず、マウスボタンを離したときにまとめて更新します。大量データの DataGrid や ListView で動かしている間のパフォーマンスを大幅に向上させます。

画面キャプチャ

scrollviewer demo screen

デモしているプロパティ

以下のプロパティが WPF 標準コントロールデモアプリでインタラクティブにデモされています。

プロパティ設定値説明
VerticalScrollBarVisibilityDisabled / Auto / Hidden / Visible垂直スクロールバーの表示方法を設定します。Auto はコンテンツが溢れたときのみ表示、Disabled は垂直スクロール不可、Hidden はスクロール可能だがバー非表示(タッチ操作向け)、Visible は常に表示です。動的に増減するコンテンツには Auto が最適で、横スクロールのみにしたい場合は Disabled を使います。Visible は常にスクロールバー領域を確保するため、コンテンツが収まる場合でもスペースを消費します。ほとんどのケースでは Auto を使い、Visible は意図的にスペースを固定したい特殊な場面に限定することを推奨します。
HorizontalScrollBarVisibilityDisabled / Auto / Hidden / Visible水平スクロールバーの表示方法を設定します。幅の広いテーブルやコンテナより横長の画像を表示する場合に Auto または Visible に設定します。多くのコントロールのデフォルトは Disabled(横スクロール不可)です。ListBox や TextBox などの内部 ScrollViewer の水平スクロールを有効にするには、コントロールの Disabled 設定をオーバーライドするため ScrollViewer.HorizontalScrollBarVisibility 添付プロパティをコントロール自身に設定します。コントロールを ScrollViewer で囲んで設定しても内部の設定が優先されるため、効果がない場合は添付プロパティを使ってください。
CanContentScrollbool論理スクロール(アイテム単位)と物理スクロール(ピクセル単位)を切り替えます。True でアイテム単位、False でピクセル単位のスクロールになります。True(デフォルト)では仮想化パネルによるアイテム単位スクロールが有効になり、仮想化のパフォーマンスが最大限活かされます。False に設定するとすべてのアイテムを計測してからピクセル単位でスムーズにスクロールする動作になりますが、ItemsControl の仮想化が破棄されてすべてのアイテムが一度に描画されます。大量アイテムのリストで False を設定するとメモリと描画パフォーマンスが著しく低下するため、滑らかなスクロールが必要な画像ビューアーなど特定の用途に限定してください。
IsDeferredScrollingEnabledboolTrue のとき、スクロールサム(つまみ)をドラッグ中はコンテンツを更新せず、離したときにまとめて更新します。大量データのリストでドラッグパフォーマンスを向上させます。数千行の 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}" />

主な使用例

ヒントとベストプラクティス

関連コントロール

ソースコード

このデモ画面のソースコードは GitHub で公開しています。

GitHub で ScrollViewer のソースコードを見る →