Bilateral binding of the VerticalOffset property on a ScrollViewer?

I have View and ViewModel in Silverlight 3.0.

The view contains a standard ScrollViewer containing dynamic content.

Depending on the content in ScrollViewer, the user could scroll halfway down the content, and then perform an action that causes ScrollViewer to load new content, but ScrollViewer does not automatically scroll up.

I want to be able to bind to the VerticalOffset property, but it is read-only. Any ideas on adjustable behavior? Any ideas?

Thanks.

+5
source share
3 answers

The following blog post contains pinned behavior that provides scrollviewer vertical / horizontal offsets so you can snap to them or set them in code:

http://blog.scottlogic.com/2010/07/21/exposing-and-binding-to-a-silverlight-scrollviewers-scrollbars.html

This allows the following markup:

<ScrollViewer local:ScrollViewerBinding.VerticalOffset="{Binding YPosition, Mode=TwoWay}" local:ScrollViewerBinding.HorizontalOffset="{Binding XPosition, Mode=TwoWay}"> <!-- Big content goes here! --> </ScrollViewer> 
+4
source

Since you are using the ViewModel, I believe that the โ€œaction that calls the ScrollViewer to load new contentโ€ is the result of changes made internally or to the ViewModel. In this case, I would add an event to the ViewModel that fires every time such a change occurs.

In your view, you can add a handler for this event and call ScrollToVerticalPosition in the ScrollViewer when it starts.

+3
source

I simplified @ColinE's solution. Instead of connecting to the ScrollBar.ValueChanged event, I am connecting to the ScrollViewer.ScrollChanged event. So, 1. there is no need to find the ScrollBar in the visual tree, and 2. ScrollBar.ValueChanged is called in some transition states when the contents of the ScrollViewer change, and I do not want to catch these states.

I am posting my code for VerticalOffset , HorizontalOffset is like:

 /// <summary> /// VerticalOffset attached property /// </summary> public static readonly DependencyProperty VerticalOffsetProperty = DependencyProperty.RegisterAttached("VerticalOffset", typeof(double), typeof(ScrollViewerBinding), new FrameworkPropertyMetadata(double.NaN, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnVerticalOffsetPropertyChanged)); OnVerticalOffsetPropertyChanged)); /// <summary> /// Just a flag that the binding has been applied. /// </summary> private static readonly DependencyProperty VerticalScrollBindingProperty = DependencyProperty.RegisterAttached("VerticalScrollBinding", typeof(bool?), typeof(ScrollViewerBinding)); public static double GetVerticalOffset(DependencyObject depObj) { return (double)depObj.GetValue(VerticalOffsetProperty); } public static void SetVerticalOffset(DependencyObject depObj, double value) { depObj.SetValue(VerticalOffsetProperty, value); } private static void OnVerticalOffsetPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { ScrollViewer scrollViewer = d as ScrollViewer; if (scrollViewer == null) return; BindVerticalOffset(scrollViewer); scrollViewer.ScrollToVerticalOffset((double)e.NewValue); } public static void BindVerticalOffset(ScrollViewer scrollViewer) { if (scrollViewer.GetValue(VerticalScrollBindingProperty) != null) return; scrollViewer.SetValue(VerticalScrollBindingProperty, true); scrollViewer.ScrollChanged += (s, se) => { if (se.VerticalChange == 0) return; SetVerticalOffset(scrollViewer, se.VerticalOffset); }; } 

And use it in XAML:

 <ScrollViewer local:ScrollViewerBinding.VerticalOffset="{Binding ScrollVertical}"> <!-- content ... --> </ScrollViewer> 
0
source

All Articles