• 追加された行はこの色です。
  • 削除された行はこの色です。
#setlinebreak(on);
[[WP TIPS に戻る>wp7/tips]]

*ListBox をスクロールさせる [#k4b8e4c7]
サンプルプロジェクト [[Listbox_scroll.zip>https://skydrive.live.com/redir.aspx?cid=793b87c06d2f0cd5&resid=793B87C06D2F0CD5!1910&parid=793B87C06D2F0CD5!223]]
サンプルプロジェクト [[Listbox_scroll.zip>https://skydrive.live.com/redir.aspx?cid=793b87c06d2f0cd5&resid=793B87C06D2F0CD5!1911&parid=793B87C06D2F0CD5!223]]

**開く・閉じる [#he4ac033]
ListBox のスクロール部分は ScrollViewer で実装されており、この ScrollViewer を取り出して、使用することで ListBox に表示されている項目をスクロールさせることが出来ます。

#htmlinsert(u2b,id=c364r6rEhhE,width=480,height=360;)

**ListBox の ScrollViewer を取り出す [#i302b75f]
取り出し方は簡単です。ListBox の最初の子エレメントが ScrollViewer になっているので、VisualTreeHelper.GetChild メソッドで指定すれば取得できます。

 private ScrollViewer GetScrollViewer(ListBox lb)
 {
    return (ScrollViewer)VisualTreeHelper.GetChild(lb, 0);
 }

**ListBox をスクロールさせる [#ba029193]
上記の方法で取得した 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();
  }

**スクロール時の注意 [#q6b02838]
上記のように ScrollToVerticalOffset メソッドに 0.1 ずつ値を加算(または減算)することで、なめらかなスクロールを行うことが出来ます。
ただし注意しなければならないのは、''0.1 というのは項目の高さの 10% である'' と言うことです。

たとえば ListBox 最初の項目が 100px の高さの場合 0.1 = 10% = 10px ですが、2番目の項目が 200px の場合 0.1 = 10% = 20px になると言うことです。
高さが違う項目が表示されている場合に 0.1 ずつ足してスクロールさせると、高さの低い項目はゆっくりスクロールし、高い項目は早くスクロールすることになります。

この場合は、各項目の高さを取得し逆算した上で、ScrollToVerticalOffset メソッドに値を設定する必要があります。