滚动动画

Cob*_*old 5 wpf animation

如何为ListBox的滚动设置动画?我知道我可以使用scrollIntoView,但我该如何设置它的动画?我想按箭头键从一个listBoxItem移动到另一个.

Fre*_*lad 7

以下是基于与以下链接相同的方法的粗略实现
http://aniscrollviewer.codeplex.com/

VerticalOffset属性是只读的,因此您可以使用附加属性VerticalOffset,而ScrollViewer这反过来ScrollToVerticalOffset.此附加属性可以设置动画.

您还可以为ItemsControl被调用创建扩展方法AnimateScrollIntoView.

像这样称呼它

listBox.AnimateScrollIntoView(yourItem);
Run Code Online (Sandbox Code Playgroud)

ScrollViewerBehavior

public class ScrollViewerBehavior
{
    public static DependencyProperty VerticalOffsetProperty =
        DependencyProperty.RegisterAttached("VerticalOffset",
                                            typeof(double),
                                            typeof(ScrollViewerBehavior),
                                            new UIPropertyMetadata(0.0, OnVerticalOffsetChanged));

    public static void SetVerticalOffset(FrameworkElement target, double value)
    {
        target.SetValue(VerticalOffsetProperty, value);
    }
    public static double GetVerticalOffset(FrameworkElement target)
    {
        return (double)target.GetValue(VerticalOffsetProperty);
    }
    private static void OnVerticalOffsetChanged(DependencyObject target, DependencyPropertyChangedEventArgs e)
    {
        ScrollViewer scrollViewer = target as ScrollViewer;
        if (scrollViewer != null)
        {
            scrollViewer.ScrollToVerticalOffset((double)e.NewValue);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

ItemsControlExtensions

public static class ItemsControlExtensions
{
    public static void AnimateScrollIntoView(this ItemsControl itemsControl, object item)
    {
        ScrollViewer scrollViewer = VisualTreeHelpers.GetVisualChild<ScrollViewer>(itemsControl);

        UIElement container = itemsControl.ItemContainerGenerator.ContainerFromItem(item) as UIElement;
        int index = itemsControl.ItemContainerGenerator.IndexFromContainer(container);
        double toValue = scrollViewer.ScrollableHeight * ((double)index / itemsControl.Items.Count);
        Point relativePoint = container.TranslatePoint(new Point(0.0, 0.0), Window.GetWindow(container));

        DoubleAnimation verticalAnimation = new DoubleAnimation();
        verticalAnimation.From = scrollViewer.VerticalOffset;
        verticalAnimation.To = toValue;
        verticalAnimation.DecelerationRatio = .2;
        verticalAnimation.Duration = new Duration(TimeSpan.FromMilliseconds(1000));
        Storyboard storyboard = new Storyboard();
        storyboard.Children.Add(verticalAnimation);
        Storyboard.SetTarget(verticalAnimation, scrollViewer);
        Storyboard.SetTargetProperty(verticalAnimation, new PropertyPath(ScrollViewerBehavior.VerticalOffsetProperty));
        storyboard.Begin();
    }
}
Run Code Online (Sandbox Code Playgroud)

因为你还需要掌握ScrollViewer你需要的东西

public static class VisualTreeHelpers
{
    public static T GetVisualChild<T>(DependencyObject parent) where T : Visual
    {
        T child = default(T);

        int numVisuals = VisualTreeHelper.GetChildrenCount(parent);
        for (int i = 0; i < numVisuals; i++)
        {
            Visual v = (Visual)VisualTreeHelper.GetChild(parent, i);
            child = v as T;
            if (child == null)
            {
                child = GetVisualChild<T>(v);
            }
            if (child != null)
            {
                break;
            }
        }
        return child;
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 代码中可能有一个错误:`scrollViewer.ScrollableHeight*((double)index/itemsControl.Items.Count); `应该是`scrollViewer.ScrollableHeight*((double)index /(itemsControl.Items.Count -1)); `例如,如果列表包含12个元素并且我想滚动到最后一个(索引11),结果必须变为`scrollViewer.ScrollableHeight*1`,小心除零:) (2认同)