2013-06-05 7 views
9

Sto cercando di scorrere in vista in modo che l'ultimo elemento in un listivew verticale sia sempre visualizzato, ma ListView.ScrollIntoView() non funziona mai.Perché ListView.ScrollIntoView non funziona mai?

ho provato:

button1_Click(object sender, EventArgs e) 
{ 

      activities.Add(new Activities() 
      { 
       Time = DateTime.Now, 
       Message = message 
      }); 

      ActivityList.ItemsSource = activities; 

      // Go to bottom of ListView. 
      ActivityList.SelectedIndex = ActivityList.Items.Count; 
      ActivityList.ScrollIntoView(ActivityList.SelectedIndex); 
} 

Ho anche provato:

ActivityList.ScrollIntoView(ActivityList.Items.Count), e ActivityList.ScrollIntoView(ActivityList.Items.Count + 1); ma niente sta funzionando.

Per favore aiuto. Questo è davvero fastidioso. E la documentazione isn't very helpful in questo caso.

risposta

12

Stai passando l'indice quando il metodo si aspetta l'oggetto oggetto. Prova questo per scorrere fino all'elemento selezionato.

ActivityList.ScrollIntoView(ActivityList.SelectedItem); 

Se si desidera scorrere fino all'ultima voce, è possibile utilizzare questo

ActivityList.ScrollIntoView(ActivityList.Items[ActivityList.Items.Count - 1]); 
+1

Scusa, ho dimenticato di dire che è stata la prima cosa che ho provato (come da la documentazione). Neanche questo funziona. –

+1

'SelectedIndex' è anche impostato oltre gli elementi listl. Se, allora dovrebbe essere 'ActivityList.SelectedIndex = ActivityList.Items.Count - 1' – dkozl

+2

+1 @dkozl per il valore' SelectedIndex'. Jase, se ancora non funziona, prova a chiamare 'ActivityList.UpdateLayout();' appena prima del metodo 'ScrollIntoView'. – keyboardP

1

si sta assegnando l'indice della voce, e la casella di riepilogo si aspetta l'elemento stesso. provare qualcosa di simile:

var activity = new Activities() 
     { 
      Time = DateTime.Now, 
      Message = message 
     }; 

activities.Add(activity); 

ActivityList.ItemsSource = activities; 
ActivityList.ScrollIntoView(activity); 
+0

È un ListView. E originariamente assegnavo l'oggetto reale (ListView.SelectedItem) ma non funzionava. Ho dimenticato di metterlo nella mia domanda, dato che ho provato circa una dozzina di cose per cercare di farlo funzionare. In questo momento sto lavorando a un ListView, non a un ListBox, ma a collegamenti MSDN alla pagina ListBox dal collegamento ListView.ScrollIntoView(). Come potete vedere da qui: http://msdn.microsoft.com/en-us/library/system.windows.controls.listview.aspx –

8

Essa ha avuto qualcosa a che fare con la rappresentazione lista interna, vale a dire, gli elementi non sono ancora a posto quando si chiama il ScrollIntoView(). Dopo molti tentativi, questo è quello che finalmente si avvicinò con e questo sembra funzionare: collegare due gestori ad ogni ListBox/ListView:

<ListBox x:Name="YourList" ... Loaded="YourList_Loaded" SelectionChanged="YourList_SelectionChanged"> 

e

void YourList_Loaded(object sender, RoutedEventArgs e) { 
    if (YourList.SelectedItem != null) 
    YourList.ScrollIntoView(YourList.SelectedItem); 
} 

void YourList_SelectionChanged(object sender, SelectionChangedEventArgs e) { 
    if (YourList.SelectedItem != null) 
    YourList.ScrollIntoView(YourList.SelectedItem); 
} 

Il secondo gestore di cui non puoi fare a meno. Non è possibile chiamare ScrollIntoView() immediatamente dopo aver impostato l'elemento selezionato, non è ancora pronto. Devi permettere alla lista di informarti quando ha effettivamente cambiato l'oggetto. Il primo gestore dipende dalle circostanze, se hai problemi con la selezione visualizzata dopo il caricamento iniziale del contenuto della lista, potresti averne bisogno.

+1

Questa soluzione ha funzionato per me! – sharpguru

3

Il problema con ActivityList.ScrollIntoView(ActivityList.Items[ActivityList.Items.Count - 1]); e "soluzioni" simili, almeno da quello che sto vivendo, è che quando il ListBox contiene lo stesso oggetto più di una volta, salta al primo che trova, cioè all'indice più basso. Quindi, non si preoccupa dell'indice dell'articolo che hai inserito, cerca solo quell'elemento e sceglie il primo.

Non ho ancora trovato una soluzione a questo, ma l'approccio che sto prendendo ora è quello di inserire anziché Aggiungi elementi. Nel caso manifesti originali Penso che si tradurrebbe in:

activities.Insert(0, new Activities() 
     { 
      Time = DateTime.Now, 
      Message = message 
     }); 

o, eventualmente:

ActivityList.Items.Insert(0, new Activities() 
     { 
      Time = DateTime.Now, 
      Message = message 
     }); 

che fa sì che ogni nuova voce da inserire nella parte superiore, e quindi ScrollIntoView non ha nemmeno bisogno di essere chiamato.

+0

Questo era il mio problema, ma potevo risolverlo avvolgendo le mie corde in una classe. –

0

È un vecchio post ma poiché nessuna delle risposte qui ha funzionato per il mio caso, desidero aggiungere la mia implementazione. Ho trovato la soluzione qui: [https://social.msdn.microsoft.com/Forums/vstudio/en-US/8a745550-4360-4b53-85f5-032f8f46e2cc/listview-scrollintoview-not-working-with-a-observablecollection?forum=wpf][1]

((INotifyCollectionChanged)lvLogs.Items).CollectionChanged += ListView_CollectionChanged; 

private void ListView_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) 
{ 
    ScrollToEnd(this.lvLogs); 
} 

private void ListView_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) 
     { 
      if ((e.Action == NotifyCollectionChangedAction.Add) && (e.NewItems != null)) 
      { 
       try 
       { 
        ScrollToEnd(this.lvLogs); 
       } 
       catch (Exception ex) 
       { 
        MessageBox.Show(ex.ToString(), "Error updating list view", MessageBoxButton.OK, MessageBoxImage.Error); 
       } 

      } 
     } 

public void ScrollToEnd(ListView _ListView) 
{ 
    ScrollViewer _ScrollViewer = GetDescendantByType(_ListView, typeof(ScrollViewer)) as ScrollViewer; 
    _ScrollViewer.ScrollToEnd(); 
} 

public Visual GetDescendantByType(Visual element, Type type) 
{ 
    if (element == null) return null; 
    if (element.GetType() == type) return element; 
    Visual foundElement = null; 
    if (element is FrameworkElement) 
    { 
     (element as FrameworkElement).ApplyTemplate(); 
    } 
    for (int i = 0; i < VisualTreeHelper.GetChildrenCount(element); i++) 
    { 
     Visual visual = VisualTreeHelper.GetChild(element, i) as Visual; 
     foundElement = GetDescendantByType(visual, type); 
     if (foundElement != null) 
      break; 
    } 
    return foundElement; 
} 

Per me funziona perfettamente.

0

Il problema che ho affrontato era simile. Stavo aggiungendo programmaticamente a un ListBox e avevo bisogno che l'ultimo elemento aggiunto fosse visibile. Dopo aver legato i vari metodi che ho trovato il seguente per essere il più semplice e il miglior

lstbox.Items.MoveCurrentToLast(); 
lstbox.ScrollIntoView(lstbox.Items.CurrentItem); 
0

questo è un vecchio post, ma ho avuto lo stesso problema in un'applicazione Windows Store e hanno trovato la seguente lavorato:

private void PagesListView_SelectionChanged(object sender, SelectionChangedEventArgs e) 
    { 
     pageListView.UpdateLayout(); 
     pageListView.ScrollIntoView(pageListView.SelectedItem); 
    } 

Cheers, Paul

0

Basta chiamare il metodo UpdateLayout ...

UpdateLayout(); 
ActivityList.ScrollIntoView(ActivityList.Items[ActivityList.Items.Count - 1]); 

Ciò funzionerà ...

O più modo più semplice ... basta compilare app :) e che funzionerà senza UpdateLayot()