ListBox をスクロールさせる
サンプルプロジェクト Listbox_scroll.zip
ListBox のスクロール部分は ScrollViewer で実装されており、この ScrollViewer を取り出して、使用することで ListBox に表示されている項目をスクロールさせることが出来ます。
ListBox の ScrollViewer を取り出す
取り出し方は簡単です。ListBox の最初の子エレメントが ScrollViewer になっているので、VisualTreeHelper.GetChild メソッドで指定すれば取得できます。
private ScrollViewer GetScrollViewer(ListBox lb) { return (ScrollViewer)VisualTreeHelper.GetChild(lb, 0); }
ListBox をスクロールさせる
上記の方法で取得した ScrollViewer の ScrollToVerticalOffset メソッドを使用することで、上下にスクロールさせることが出来ます。( ScrollToHorizontalOffset なら左右 )
ScrollToVerticalOffset メソッドに指定する値ですが、通常の ScrollViewer であればピクセルを指定するので 100 を指定すると、左上から 100px の所にスクロールします。
しかし ListBox の ScrollViewer での指定は、表示したい項目のインデックスになります。
たとえば上から10番目の項目を ListBox の先頭に表示させる場合は、9 を指定します。
さらに ScrollToVerticalOffset の値は、double の小数点を指定することが出来、9.5 を指定すると 10番目の項目が半分だけ表示されます(上半分はスクロールしていて隠れる)。
つまり 1つの項目が 1 に相当し、0.1 ずつ足していくと 項目の高さ 10% ずつ下側にスクロール させることが出来ます。逆に 0.1 ずつ引いていくと上側にスクロールします。
DispatcherTimer を使用し 0.1 ずつ変化させると、自動的にスクロールする効果を演出することが出来ます。
private void down_button_Click(object sender, System.EventArgs e) { // 現在位置を取得 (表示されている項目のインデックスと等価) int currentIndex = (int)Math.Floor(this.sv.VerticalOffset); this.Start(currentIndex + 5); } IDisposable q; private void Start(double to) { // 既に動いていたら停止 if (this.q != null) { this.q.Dispose(); this.q = null; } // 現在位置を取得 (表示されている項目のインデックスと等価) double from = (int)Math.Floor(this.sv.VerticalOffset); // タイマで 10ms ごとに、項目の高さ 10% ずつスクロールさせる double offset = 0.1; bool isDown = from < to; DispatcherTimer timer = new DispatcherTimer(); timer.Interval = TimeSpan.FromMilliseconds(10); System.Diagnostics.Debug.WriteLine(from + " " + to); this.q = Observable.FromEvent<EventArgs>(timer, "Tick") .Select(n => { from = isDown ? from + offset : from - offset; return from; }) .Subscribe(n => { // 範囲を超えたら終了 if (isDown && n > to) this.q.Dispose(); else if (!isDown && n < to) this.q.Dispose(); // スクロール this.sv.ScrollToVerticalOffset(n); }); // スクロール開始 timer.Start(); }
スクロール時の注意
上記のように ScrollToVerticalOffset メソッドに 0.1 ずつ値を加算(または減算)することで、なめらかなスクロールを行うことが出来ます。
ただし注意しなければならないのは、0.1 というのは項目の高さの 10% である と言うことです。
たとえば ListBox 最初の項目が 100px の高さの場合 0.1 = 10% = 10px ですが、2番目の項目が 200px の場合 0.1 = 10% = 20px になると言うことです。
高さが違う項目が表示されている場合に 0.1 ずつ足してスクロールさせると、高さの低い項目はゆっくりスクロールし、高い項目は早くスクロールすることになります。
この場合は、各項目の高さを取得し逆算した上で、ScrollToVerticalOffset メソッドに値を設定する必要があります。