2009-07-03 2 views
10

En WPF, sé que puedo usar ListView.ScrollIntoView para desplazar un elemento determinado a la vista, pero siempre hará la menor cantidad de desplazamiento para que se muestre el elemento.Desplácese ListViewItem para estar en la parte superior de un ListView

¿Cómo puedo hacer que se desplace para que el elemento que deseo mostrar se desplaza hacia la parte superior de ListView?

He pensado en llamar a ScrollIntoView dos veces, una vez para el artículo que quiero en la parte superior, y una para el último elemento mostrado, pero no sé cómo averiguar cuál es el último elemento mostrado.

Respuesta

14

Podemos hacerlo obteniendo el ScrollViewer que está presente en ControlTemplate de ListView. Si tiene acceso a un ScrollViewer, entonces hay a lot de diferentes métodos de desplazamiento expuestos.

En primer lugar, podemos crear un ListView que queremos añadir este efecto a:

<ListView ItemsSource="{Binding Percents}" 
     SelectionChanged="OnSelectionChanged" 
     x:Name="uiListView"/> 


public List<int> Percents { get; set; } 

public Window1() 
{ 
    InitializeComponent(); 

    Percents = new List<int>(); 
    for (int i = 1; i <= 100; i++) 
    { 
     Percents.Add(i); 
    } 
    this.DataContext = this; 
} 

También necesitaremos algo que podemos utilizar para obtener el ScrollViewer de la Vista de la lista. He usado algo similar a esto antes para trabajar con desplazamiento personalizado, y podemos usarlo aquí también.

public static DependencyObject GetScrollViewer(DependencyObject o) 
{ 
    if (o is ScrollViewer) 
    { return o; } 

    for (int i = 0; i < VisualTreeHelper.GetChildrenCount(o); i++) 
    { 
     var child = VisualTreeHelper.GetChild(o, i); 

     var result = GetScrollViewer(child); 
     if (result == null) 
     { 
      continue; 
     } 
     else 
     { 
      return result; 
     } 
    } 

    return null; 
} 

Ahora, solo tenemos que manejar el evento SelectionChanged. Debido a que estamos tratando de desplazar un elemento a la parte superior de la lista, la mejor opción es desplazarse hacia la parte inferior y luego volver a desplazarse hacia arriba hasta nuestro elemento seleccionado. Como dijiste, ScrollIntoView se desplazará solo hasta que el elemento sea visible, de modo que una vez que el elemento seleccionado llegue a la parte superior a medida que se desplaza hacia atrás, dejará de dejar nuestro elemento seleccionado en la parte superior de la lista.

private void OnSelectionChanged(object sender, SelectionChangedEventArgs e) 
{ 
    ScrollViewer scrollViewer = GetScrollViewer(uiListView) as ScrollViewer; 
    scrollViewer.ScrollToBottom(); 

    uiListView.ScrollIntoView(e.AddedItems[0]); 
} 
+0

Perfecto :) Gracias – Ray

+0

Funciona como un encanto para mí. Gracias !!! – thowa

+1

Nota: si está utilizando el WPF Extended Toolkit, puede obtener el ScrollViewer en una línea de código: VisualTreeHelperEx.FindDescendantByType (YourListView); –

0

Esta es una alternativa a la respuesta de @rmoore que evita el desplazamiento de la parte inferior. También tenga en cuenta que esto solo es útil en casos donde SelectionMode=Single.

En caso de que ScrollViewer.CanContentScroll=True el puede desplazarse directamente al SelectedIndex.

private void OnSelectionChanged(object sender, SelectionChangedEventArgs e) 
{ 
    ScrollViewer scrollViewer = GetScrollViewer(uiListView) as ScrollViewer;  
    scrollViewer.ScrollToVerticalOffset(listView.SelectedIndex); 
} 

y en caso ScrollViewer.CanContentScroll=False algunos XAML adicional se requiere:

<ListView ScrollViewer.CanContentScroll="False" ItemsSource="{Binding Percents}" x:Name="uiListView"> 
    <ListView.ItemContainerStyle> 
     <Style TargetType="{x:Type ListViewItem}"> 
      <EventSetter Event="Selected" Handler="OnSelected"/> 
     </Style> 
    </ListView.ItemContainerStyle> 
</ListView> 

Y el ScrollViewer se puede mover a la desviación vertical de la parte superior de la ListViewItem.

private void OnSelected(object sender, RoutedEventArgs e) 
{ 
    ScrollViewer scrollViewer = GetScrollViewer(uiListView) as ScrollViewer;  

    ListViewItem listViewItem = (ListViewItem)e.Source; 
    Point offset = listViewItem.TranslatePoint(new Point(), scrollViewer); 
    scrollViewer.ScrollToVerticalOffset(scrollViewer.VerticalOffset + offset.Y); 
} 
Cuestiones relacionadas