WP TIPS に戻る

ScrollViewer を巡るまとめ

サンプルプロジェクト ScrollViewer_Tips.zip

大きな画像など画面に入りきらないエレメントをスクロールして表示したい時に使用するのが ScrollViewer です。ScrollViewer の中に Image コントロールを配置するだけで、Image サイズが ScrollViewer のサイズを超えたとき、指で触ってスクロールさせることが出来ます。

便利ですね。Windows Mobile の頃は大変でした。

ScrollViewer の各種プロパティ

ScrollViewer には表示しているエレメントの大きさやスクロール状態などのプロパティが用意されていて、どのような状態にあるか分かります。

たとえば ScrollableWidth == 0 であれば横にははみ出していない事が分かります。

右の画像は、

  • Image コントロールが 450x500
  • 表示している画像が 2000x1500

です。

scrollviewer_tips-01.jpg
Actual*ScrollViewer が実際に画面に表示されているサイズ
Viewport*ScrollViewer の中の表示可能領域
Extent*ScrollViewer が表示しているエレメントのサイズ
Scrollable*ScrollViewer が表示しているエレメントがはみ出しているサイズ
*OffsetScrollViewer 左上からの縦横のスクロール位置

Viewport が表示してるサイズ(=ScrollViewサイズ)、Extent が画像サイズ、Scrollable がはみ出しているサイズになっているのが分かると思います。

スクロールさせないようにする

ScrollView.HorizontalScrollBarVisibility/VerticalScrollBarVisibility を Disable にすると、縦横のスクロールを出来ないようにすることが出来ます。
Expression Blend では、HorizontalScrollBarVisibility がデフォルト Disable になっており水平方向のスクロールが無効になっているので注意が必要です。

コードでスクロールさせる

ScrollViewer のスクロール位置を変更するには、ScrollViewer.ScrollToHorizontalOffset/ScrollToVerticalOffset メソッドで移動させるピクセル数を指定することで水平・垂直方向のスクロールを行えます。原点は左上が 0,0 です。

このときに *ScrollBarVisibility = Disable にっていると、ScrollTo* メソッドでスクロールをさせてもスクロールしないので注意が必要です。

以下が、オートスクロールのサンプルです。
本当なら Storyboard でアニメーションしたいところですが、スクロールがメソッドなので DispatcherTimer でスクロールしました。

private void autoscroll_button_Click(object sender, System.EventArgs e)
{
   DispatcherTimer timer = new DispatcherTimer();
   timer.Interval = TimeSpan.FromMilliseconds(10);
   timer.Tick += (s, args) =>
   {
       // スクロールする
       this.scrollViewer.ScrollToHorizontalOffset(this.scrollViewer.HorizontalOffset + 1);
       this.scrollViewer.ScrollToVerticalOffset(this.scrollViewer.VerticalOffset + 1);
       
       double ho = this.scrollViewer.HorizontalOffset;
       double vo = this.scrollViewer.VerticalOffset;
       double sw = this.scrollViewer.ScrollableWidth;
       double sh = this.scrollViewer.ScrollableHeight;
       
       // 右端か下に達したら停止
       if (ho >= sw || vo >= sh)
       {
           ((DispatcherTimer)s).Stop();
           MessageBox.Show("停止しました");
       }
   };
   timer.Start();
}

Transform で拡大表示してもスクロールしない

ScrollViewer 内のエレメントを Transform.ScaleY 等で拡大表示しても、ScrollViewer でスクロールさせることは出来ません。というのも Translform.ScaleY 等で拡大表示しているのは コントロールのサイズはそのままで拡大表示している だけなので、実際のコントロールサイズは変わっていません。
ScrollViewer は格納しているエレメントサイズを基準にスクロールするので、拡大表示しただけではスクロールさせることは出来ません。

端っこのイベントを取得する

ScrollViewer で一番下や右下で、ぐぐっと引っ張って手を離すとびよよーんと画像が元の位置に戻ります。
この状態をイベントとして取得するには、XAML で VisualState を定義すれば可能です。

以下では ListBox 内の ScrollViewer のイベントを取得しています。

WP7.5 でリストボックスのスクロールエンドで圧縮されるときのイベントを取る
http://blogs.msdn.com/b/shintak/archive/2011/08/06/10193347.aspx