繁体   English   中英

通过 ScrollViewer 的水平/垂直偏移设置动画

[英]Animate via Horizontal/Vertical offset of ScrollViewer

我需要控制其位置与 Windows Phone 8 SDK (silverlight/wpf) 中 ScrollViewer 的滚动偏移量直接相关的控件。 此外,我需要能够知道各种委托中的滚动偏移量,以便我可以更改其他应用程序内属性。 这甚至可能吗?

我已经看遍了,但似乎找不到任何例子,我似乎也没有足够的 WPF/Silverlight 动画概念来掌握它。

我能想到的最好的结果如下所示。 它起初似乎可以工作,但不幸的是只会在您的手指没有按下并且 ScrollViewer 没有动画时才会更新,因此更新频率太低。 我需要更新作为动画循环的一部分,所以每一帧左右(每秒 60-100+),我都会得到新的滚动偏移值。 有什么办法可以在动画循环中安排 DispatchTimer 吗? 或者是否有某种更好的方法来完全解决这个问题,使用诸如 DependentProperties 之类的东西?

    protected override void OnNavigatedTo(NavigationEventArgs e)
    {
        if (!App.ViewModel.IsDataLoaded)
        {
            App.ViewModel.LoadData();
        }
        DispatcherTimer t = new DispatcherTimer();
        t.Interval = TimeSpan.FromMilliseconds(16.6);
        t.Tick += new EventHandler(
            (object s, EventArgs ee) =>
                {
                    // FunkBox is some ListBox
                    ScrollViewer sv = FindChildOfType<ScrollViewer>(FunkBox);
                    if (sv == null) 
                    {
                        // TOffset is some TextBlock
                        TOffset.Text = "dur...";
                    }
                    else
                    {
                        TOffset.Text = String.Format("dur {0}", sv.HorizontalOffset);
                    }
                });
        t.Start();
    }

    static T FindChildOfType<T>(DependencyObject root) where T : class
    {
        var queue = new Queue<DependencyObject>();
        queue.Enqueue(root);

        while (queue.Count > 0)
        {
            DependencyObject current = queue.Dequeue();
            for (int i = System.Windows.Media.VisualTreeHelper.GetChildrenCount(current) - 1; 0 <= i; i--)
            {
                var child = System.Windows.Media.VisualTreeHelper.GetChild(current, i);
                var typedChild = child as T;
                if (typedChild != null)
                {
                    return typedChild;
                }
                queue.Enqueue(child);
            }
        }
        return null;
    }

这也花了我一段时间才弄明白。 这是你如何做到的:

  • 确保您的 ScrollViewer 将 ManipulationMode 设置为“控制”
  • 遍历可视化树以找到 ScrollViewer 的 Vertical Scrollbar 子项。
  • 连接到它的 ValueChanged 事件。

因此,您的 XAML 将是:

 <ScrollViewer x:Name="mainScrollViewer" ManipulationMode="Control">
        ....
 </ScrollViewer>

而你背后的代码:

    public MainPage()
    {
        InitializeComponent();

        this.Loaded += MainPage_Loaded;
    }

    void MainPage_Loaded(object sender, RoutedEventArgs e)
    {
        ScrollBar verticalBar;
        verticalBar = ((FrameworkElement)VisualTreeHelper.GetChild(mainScrollViewer, 0)).FindName("VerticalScrollBar") as ScrollBar;
        verticalBar.ValueChanged += verticalBar_ValueChanged;
    }

    void verticalBar_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
    {
        double newVerticalOffset =  e.NewValue;
        // Set the offset of your other control here, using newVerticalOffset
    }

或者,对于 ListBox,您需要使用以下代码从 Listbox 内部获取 ScrollViewer:

    ScrollViewer mainScrollViewer = GetVisualChild<ScrollViewer>(yourListBoxControl);
    // ...then use the code above

    public T GetVisualChild<T>(UIElement parent) where T : UIElement
    {
        T child = null; // default(T);

        int numVisuals = VisualTreeHelper.GetChildrenCount(parent);
        for (int i = 0; i < numVisuals; i++)
        {
            UIElement element = (UIElement)VisualTreeHelper.GetChild(parent, i);
            child = element as T;
            if (child == null)
                child = GetVisualChild<T>(element);
            if (child != null)
                break;
        }

        return child;
    }

您可能还需要在构造函数中设置 ScrollViewer 的操作模式:

    ScrollViewer mainScrollViewer = GetVisualChild<ScrollViewer>(lstTest);
    sv.ManipulationMode = ManipulationMode.Control;

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM