2009-03-20 4 views
12

У меня есть коллекция Visual s в ListBox. Мне нужно найти XPosition элемента внутри него, а затем анимировать HorizontalOffsetListBoxScrollViewer. По сути, я хочу создать анимированный метод ScrollIntoView.WPF - анимация ListBox.ScrollViewer.HorizontalOffset?

Это дает мне пару проблем. Во-первых, как я могу получить ссылку на scrollviewer s ListBox? Во-вторых, как я могу получить относительный XPosition или HozintalOfffset произвольного элемента в ListBox?

Я не отвечаю ни на какой вход на ListBox, поэтому не могу использовать связанные свойства Mouse.

ответ

32

Я не думаю, что вы сможете использовать раскадровку WPF для анимации, потому что раскадровки ожидают свойства зависимостей WPF. Для прокрутки вам необходимо позвонить ScrollViewer.ScrollToHorizontalOffset(double).

Вы можете попробовать создать настраиваемое свойство зависимостей, которое вызывает SetHorizontalOffset в функции OnDependencyPropertyChanged(). Тогда вы можете анимировать это свойство.

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); 
} 

Чтобы зритель прокрутки вы можете использовать VisualTreeHelper для поиска визуальных детей в ListBox. Сохраните ссылку на ScrollViewer, потому что она вам понадобится позже. Попробуйте следующее:

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; 
} 

Эта функция возвращает первый визуальный дочерний элемент типа параметра. Вызовите FindVisualChild<ScrollViewer>(ListBox), чтобы получить ScrollViewer.

Наконец, попробуйте использовать UIElement.TranslatePoint(Point, UIElement), чтобы получить позицию X элемента. Вызовите эту функцию на элементе, перейдите в 0,0 для точки и пройдите в ScrollViewer.

Надеюсь, это поможет.

+0

Господи, это отличная работа! Спасибо за помощь Джошу, он указал мне в правильном направлении, по крайней мере. – Stimul8d

+0

Вы имеете в виду ScrollToHorizontalOffset вместо SetHorizontalOffset? –

+0

Да, ты прав. Благодаря! –

1

Я не уверен, что мой метод является хорошей практикой, но в течение ограниченного времени, которое у меня было, похоже, все в порядке. Вместо того, чтобы использовать панель рассказов, я просто использовал 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(); 
       } 
      }; 
     }); 

Убедитесь, что это DispatchTimer поэтому нить может взять под свой контроль элемента пользовательского интерфейса

Также не забудьте привязать к объекту, на ваш взгляд!

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