It all started because I couldn't find a way to automatically scroll any element into view in Silverlight (a feature
that exists in WPF). I take that back, I could get the job done with a ListBox's ScrollIntoView(ListBoxItem item)
method, but I hardly wanted everything on my screen to be wrapped as a ListBoxItem; it feels as dirty as it sounds.
Anyways, here is the code.
/* Extension Methods */
public static class FrameworkElementExtensions
{
private const int ScrollPadding = 10;
public static void BringIntoView(this FrameworkElement frameworkElement)
{
var parent = VisualTreeHelper.GetParent(frameworkElement);
while(parent != null)
{
parent = VisualTreeHelper.GetParent(parent);
var scrollViewer = parent as ScrollViewer;
if(scrollViewer != null)
{
frameworkElement.BringIntoViewForScrollViewer(scrollViewer);
break;
}
}
}
public static void BringIntoViewForScrollViewer(this FrameworkElement frameworkElement, ScrollViewer scrollViewer)
{
var transform = frameworkElement.TransformToVisual(scrollViewer);
var positionInScrollViewer = transform.Transform(new Point(0, 0));
if (positionInScrollViewer.Y < 0 || positionInScrollViewer.Y > scrollViewer.ViewportHeight)
scrollViewer.ScrollToVerticalOffset(scrollViewer.VerticalOffset + positionInScrollViewer.Y - ScrollPadding);
}
}
Bonus Behavior! (Behaviors?!? Here is an Introduction).
This behavior was created ensure that as a user tabs through the screen, scrolling automatically takes place.
Note: If you want to use behaviors in Silverlight, install the Blend 3 SDK and reference
Microsoft.Expression.Interactions.dll
/* Behavior class */
public class BringIntoViewOnFocusBehavior : Behavior<FrameworkElement>
{
protected override void OnAttached()
{
base.OnAttached();
AssociatedObject.GotFocus += OnGotFocus;
}
protected override void OnDetaching()
{
base.OnDetaching();
AssociatedObject.GotFocus -= OnGotFocus;
}
private void OnGotFocus(object sender, RoutedEventArgs e1)
{
AssociatedObject.BringIntoView();
}
}
<!-- XAML usage of custom behavior -->
<UserControl
xmlns:interactivity="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
xmlns:behaviors="clr-namespace:YourNamespaceToBehaviors.Behaviors">
<StackPanel>
<TextBox>
<interactivity:Interaction.Behaviors>
<behaviors:BringIntoViewOnFocusBehavior />
</interactivity:Interaction.Behaviors>
</TextBox>
</StackPanel>
</UserControl>