Подтвердить что ты не робот

WPF - анимация ListBox.ScrollViewer.HorizontalOffset?

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

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

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

4b9b3361

Ответ 1

Я не думаю, что вы сможете использовать раскадровку 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.

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

Ответ 2

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