ScrollViewer を巡るまとめ
サンプルプロジェクト ScrollViewer_Tips.zip
大きな画像など画面に入りきらないエレメントをスクロールして表示したい時に使用するのが ScrollViewer です。ScrollViewer の中に Image コントロールを配置するだけで、Image サイズが ScrollViewer のサイズを超えたとき、指で触ってスクロールさせることが出来ます。
便利ですね。Windows Mobile の頃は大変でした。
ScrollViewer の各種プロパティ
ScrollViewer には表示しているエレメントの大きさやスクロール状態などのプロパティが用意されていて、どのような状態にあるか分かります。
たとえば ScrollableWidth == 0 であれば横にははみ出していない事が分かります。
右の画像は、
- Image コントロールが 450x500
- 表示している画像が 2000x1500
です。
Actual* | ScrollViewer が実際に画面に表示されているサイズ |
Viewport* | ScrollViewer の中の表示可能領域 |
Extent* | ScrollViewer が表示しているエレメントのサイズ |
Scrollable* | ScrollViewer が表示しているエレメントがはみ出しているサイズ |
*Offset | ScrollViewer 左上からの縦横のスクロール位置 |
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