November 2009 - Posts

Silverlight BringIntoView() extension method (with OnGotFocus behavior)

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>
Posted by dotjosh | 4 comment(s)
Filed under: , , ,
More Posts