2011-08-31 11 views
5

スムーズにスクロールする必要があるため、CanContentScroll == falseを必要とするリストボックスがあります。これにより、物理スクロールが可能になります。物理スクロールでListBoxの次の論理ページにスクロールする方法

また、リストボックスをページ単位でスクロールしたいのですが、リストボックス内のScrollViewerのPageDownメソッドを呼び出すと、リストボックスの高さが行の高さの倍数ではないため、最初の行が切り詰められます。

論理スクロールを使用する場合と同様に、最初の行を常に完全に表示します。

誰かが私にそれをどうやってヒントを与えることができますか?

答えて

2

スクロールしてマウスで上部の表示されるコンテナを選択すると、非仮想化の場合と同じ効果が得られます。ItemsControlScrollViewer.CanContentScroll="False")は仮想化の場合と同じです。これはコードでも行うことができます。

CanContentScrollがfalseに設定されていると、仮想化がオフになり、すべてのコンテナが常に生成されます。上部の可視コンテナを取得するには、ScrollViewerVerticalOffsetに達するまで、上部からコンテナを反復することができます。私たちが入手したら、単にBringIntoViewと呼ぶことができます。仮想化が使用されていたのと同じように、一番上にうまく整列します。であなたはPageDownを呼び出したい場合にのみ、この効果を達成するために、イベントハンドラ

private void listBox_ScrollChanged(object sender, ScrollChangedEventArgs e) 
{ 
    ItemsControl itemsControl = sender as ItemsControl; 
    ScrollViewer scrollViewer = e.OriginalSource as ScrollViewer; 
    FrameworkElement lastElement = null; 
    foreach (object obj in itemsControl.Items) 
    { 
     FrameworkElement element = itemsControl.ItemContainerGenerator.ContainerFromItem(obj) as FrameworkElement; 
     double offset = element.TransformToAncestor(scrollViewer).Transform(new Point(0, 0)).Y + scrollViewer.VerticalOffset; 
     if (offset > e.VerticalOffset) 
     { 
      if (lastElement != null) 
       lastElement.BringIntoView(); 
      break; 
     } 
     lastElement = element; 
    } 
} 

で上部可視コンテナに

<ListBox ItemsSource="{Binding MyCollection}" 
     ScrollViewer.CanContentScroll="False" 
     ScrollViewer.ScrollChanged="listBox_ScrollChanged" > 

コールBringIntoView、たとえば、ボタンをクリックすると、拡張機能を作成できます。 thod for ListBoxLogicalPageDownと呼ばれます。

listBox.LogicalPageDown(); 

ListBoxExtensions

public static class ListBoxExtensions 
{ 
    public static void LogicalPageDown(this ListBox listBox) 
    { 
     ScrollViewer scrollViewer = VisualTreeHelpers.GetVisualChild<ScrollViewer>(listBox); 
     ScrollChangedEventHandler scrollChangedHandler = null; 
     scrollChangedHandler = (object sender2, ScrollChangedEventArgs e2) => 
     { 
      scrollViewer.ScrollChanged -= scrollChangedHandler; 
      FrameworkElement lastElement = null; 
      foreach (object obj in listBox.Items) 
      { 
       FrameworkElement element = listBox.ItemContainerGenerator.ContainerFromItem(obj) as FrameworkElement; 
       double offset = element.TransformToAncestor(scrollViewer).Transform(new Point(0, 0)).Y + scrollViewer.VerticalOffset; 
       if (offset > scrollViewer.VerticalOffset) 
       { 
        if (lastElement != null) 
         lastElement.BringIntoView(); 
        break; 
       } 
       lastElement = element; 
      } 
     }; 
     scrollViewer.ScrollChanged += scrollChangedHandler; 
     scrollViewer.PageDown(); 
    } 
} 

私はあなたがすでにScrollViewerを得たあなたの質問に気づいたが、他の誰がこの質問

public static T GetVisualChild<T>(DependencyObject parent) where T : Visual 
{ 
    T child = default(T); 

    int numVisuals = VisualTreeHelper.GetChildrenCount(parent); 
    for (int i = 0; i < numVisuals; i++) 
    { 
     Visual v = (Visual)VisualTreeHelper.GetChild(parent, i); 
     child = v as T; 
     if (child == null) 
     { 
      child = GetVisualChild<T>(v); 
     } 
     if (child != null) 
     { 
      break; 
     } 
    } 
    return child; 
} 
+0

@ Zmaster:コンテナの相対的な位置を見つけるときに、「マージン」などが関与することを忘れています。それに応じて私の答えを更新しました –

+0

私はScrollToOffset()を使って、すべてのアイテムの高さが同じであるという前提でターゲットオフセットを計算しました(これは私の場合です)。アイテムを反復するよりも効率的です。一方、あなたのソリューションは異なるアイテムの高さでも動作するので、私はそれを答えとして受け入れました。 – Zmaster

0

「新しいページ」の一番上の項目をスクロールして表示すると、それはあなたが探しているものを達成するでしょうか? ScrollIntoViewを参照してください。

+0

渡って来る場合、私はGetVisualChildに実装を追加しています私は、アイテムが上部の代わりにリストボックスの下部に表示されると思う。また、私はどのようにそのアイテムを識別するためのアイデアがありません。 – Zmaster

関連する問題