Saturday, December 8, 2012

Animate via Horizontal/Vertical offset of ScrollViewer

Animate via Horizontal/Vertical offset of ScrollViewer

I need to have control whose position is directly correlated by the scroll offset of a ScrollViewer in Windows Phone 8 SDK (silverlight/wpf). Additionally I need to be able to tell what the scroll offset in a delegate of sorts so that I may change other in-app properties. Is this even possible?

I have looked all over but can not seem to find any example, nor do I seem to have a grasp of WPF/Silverlight's animation concepts enough to pick this up.

The best that I could come up with is shown below. It would appear at first to work, but unfortunately will only update when your finger is not down and the ScrollViewer is not animating, so the updates come too infrequently. I need the updates to come as a part of the animation loop, so every frame or so (60-100+ per second), I get the new scroll offset value. Is there any way to schedule the DispatchTimer in the animation loop? Or would there be some sort of better way to approach this entirely, using something like 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;     } 

Answers & Comments...

Answer: 1

This took me a while to figure out too. Here's how you do it:

  • Ensure that your ScrollViewer has ManipulationMode set to 'Control'
  • Walk through the visual tree to find the Vertical Scrollbar child of the ScrollViewer.
  • Hook into its ValueChanged event.

So, you XAML would be:

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

And your code behind:

    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     } 
by : Carlos Phttp://stackoverflow.com/users/384005




No comments:

Post a Comment

Send us your comment related to the topic mentioned on the blog