2009-03-20 14 views
12

Ho una collezione di Visual s in un ListBox. Devo trovare lo XPosition di un elemento al suo interno e quindi animare lo HorizontalOffset dello . In sostanza, voglio creare un metodo animato ScrollIntoView.WPF - Animate ListBox.ScrollViewer.HorizontalOffset?

Questo mi dà un paio di problemi. Innanzitutto, come posso ottenere un riferimento allo scrollviewer ListBox s? In secondo luogo, come posso ottenere il relativo XPosition o HozintalOfffset di un elemento arbitrario nello ListBox?

Non sto rispondendo a nessun input sullo ListBox quindi non posso utilizzare le proprietà correlate Mouse.

risposta

32

Non penso che sarà possibile utilizzare uno storyboard WPF per l'animazione perché gli storyboard animano le proprietà di dipendenza WPF. Dovrai chiamare lo ScrollViewer.ScrollToHorizontalOffset(double) per scorrere.

Si potrebbe provare a creare una proprietà di dipendenza personalizzata che chiama SetHorizontalOffset nella funzione OnDependencyPropertyChanged(). Quindi puoi animare questa proprietà.

public static readonly DependencyProperty ScrollOffsetProperty = 
    DependencyProperty.Register("ScrollOffset", typeof(double), typeof(YOUR_TYPE), 
    new FrameworkPropertyMetadata(0.0, new PropertyChangedCallback(OnScrollOffsetChanged))); 


public double ScrollOffset 
{ 
    get { return (double)GetValue(ScrollOffsetProperty); } 
    set { SetValue(ScrollOffsetProperty, value); } 
} 

private static void OnScrollOffsetChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args) 
{ 
    YOUR_TYPE myObj = obj as YOUR_TYPE; 

    if (myObj != null) 
     myObj.SCROLL_VIEWER.ScrollToHorizontalOffset(myObj.ScrollOffset); 
} 

Per ottenere lo spettatore di scorrimento è possibile utilizzare il VisualTreeHelper per cercare i bambini visive del ListBox. Salva un riferimento a ScrollViewer perché ne avrai bisogno in seguito. Prova questo:

public static childItem FindVisualChild<childItem>(DependencyObject obj) 
    where childItem : DependencyObject 
{ 
    // Iterate through all immediate children 
    for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++) 
    { 
     DependencyObject child = VisualTreeHelper.GetChild(obj, i); 

     if (child != null && child is childItem) 
     return (childItem)child; 

     else 
     { 
     childItem childOfChild = FindVisualChild<childItem>(child); 

     if (childOfChild != null) 
      return childOfChild; 
     } 
    } 

    return null; 
} 

Questa funzione restituisce il primo figlio visivo del tipo di parametro. Chiama il numero FindVisualChild<ScrollViewer>(ListBox) per ottenere ScrollViewer.

Infine, provare a utilizzare UIElement.TranslatePoint(Point, UIElement) per ottenere la posizione X dell'oggetto. Chiama questa funzione sull'oggetto, passa 0,0 per il punto e passa in ScrollViewer.

Spero che questo aiuti.

+0

Mio Dio, è proprio un lavoro! Grazie per l'aiuto Josh, mi ha indicato nella giusta direzione almeno. – Stimul8d

+0

Intendi ScrollToHorizontalOffset invece di SetHorizontalOffset? –

+0

Sì, hai ragione. Grazie! –

1

Non sono sicuro che il mio metodo sia una buona pratica, ma per il tempo limitato che ho avuto sembrava funzionare bene. Invece di usare una story board ho usato invece un DispatcherTimer.

ScrollLeftButtonCommand = new DelegateCommand(
    o => 
     { 
      var scrollViewer = (ScrollViewer)o; 

      scrollTimer = new DispatcherTimer(); 

      scrollTimer.Start(); 

      scrollTimer.Interval = TimeSpan.FromMilliseconds(30); 

      scrollTimer.Tick += (s, e) => 
      {   
       scrollViewer.ScrollToHorizontalOffset(scrollViewer.HorizontalOffset - 50); 

       if (scrollViewer.HorizontalOffset <= 0) 
       { 
        scrollTimer.Stop(); 
       } 
      }; 
     }); 

Assicurarsi che sia un DispatchTimer modo che il filo è in grado di prendere il controllo del elemento dell'interfaccia utente

Ricorda anche di legarsi al vostro oggetto nel vostro vista!

<Button CommandParameter="{Binding ElementName=MyScrollViewer }" 
     Command="{Binding ScrollLeftButtonCommand }"/>