2009-10-23 21 views
7

Mam ItemsControl, który jest databound do ObservableCollection. Mam tę metodę w kodzie, za którym dodaje nowy model do listy. Chciałbym wtedy przewinąć nowy element (u dołu listy) do widoku.Przewiń nowy element w ItemControl do widoku

Myślę, że rozmiar ItemsControl nie jest jeszcze aktualizowany, gdy szukam rozmiaru, ponieważ ActualHeight przed dodaniem modelu i po nim jest taki sam. Efektem tego kodu jest przewinięcie do punktu nieznacznie powyżej nowego elementu.

Skąd mam wiedzieć, co nowego będzie miało nowe ActualHeight?

Oto mój kod:

 ViewModel.CreateNewChapter(); 
     var height = DocumentElements.ActualHeight; 
     var width = DocumentElements.ActualWidth; 
     DocumentElements.BringIntoView(new Rect(0, height - 1, width, 1)); 

Odpowiedz

5

myślę, że trzeba zadzwonić BringIntoView na pojemniku elementu, a nie sama ItemsControl:

var container = DocumentElements.ItemContainerGenerator.ContainerFromItem(model) as FrameworkElement; 
if (container != null) 
    container.BringIntoView(); 

EDIT: Właściwie to nie robi działa, ponieważ w tym momencie kontener elementu nie został jeszcze wygenerowany ... Prawdopodobnie można obsłużyć zdarzenie StatusChanged z ItemContainerGenerator. Próbowałem następujący kod:

public static class ItemsControlExtensions 
{ 
    public static void BringItemIntoView(this ItemsControl itemsControl, object item) 
    { 
     var generator = itemsControl.ItemContainerGenerator; 

     if (!TryBringContainerIntoView(generator, item)) 
     { 
      EventHandler handler = null; 
      handler = (sender, e) => 
      { 
       switch (generator.Status) 
       { 
        case GeneratorStatus.ContainersGenerated: 
         TryBringContainerIntoView(generator, item); 
         break; 
        case GeneratorStatus.Error: 
         generator.StatusChanged -= handler; 
         break; 
        case GeneratorStatus.GeneratingContainers: 
         return; 
        case GeneratorStatus.NotStarted: 
         return; 
        default: 
         break; 
       } 
      }; 

      generator.StatusChanged += handler; 
     } 
    } 

    private static bool TryBringContainerIntoView(ItemContainerGenerator generator, object item) 
    { 
     var container = generator.ContainerFromItem(item) as FrameworkElement; 
     if (container != null) 
     { 
      container.BringIntoView(); 
      return true; 
     } 
     return false; 
    } 
} 

Jednak to nie działa albo ... z jakiegoś powodu, ContainerFromItem nadal zwraca NULL po zmianach statusu do ContainersGenerated i nie mam pojęcia dlaczego: S


EDYCJA: OK, teraz rozumiem ... było to spowodowane wirtualizacją: kontenery są generowane tylko wtedy, gdy muszą być wyświetlane, więc nie są generowane kontenery dla ukrytych przedmiotów. Po wyłączeniu wirtualizacji dla ItemsControl (VirtualizingStackPanel.IsVirtualizing="False") powyższe rozwiązanie działa poprawnie.

+0

DocumentElements.ItemContainerGenerator.ContainerFromItem (model) zwraca wartość null? Nie sądzę, że widok został zaktualizowany do nowego elementu w źródle danych. –

+0

ah, tak, zapomniałem o tym ... ale w każdym razie, jeśli kontener nie jest jeszcze w ItemControl, nie możesz go przewinąć: S –

+0

zobacz moją zaktualizowaną odpowiedź –