Visually Located

XAML and GIS

Easily Create Parallax effects in Windows 10 apps

In October James Clarke tweeted some source code to add a parallax effect to UWP apps using the new Windows Composition framework.

At the time the new SDK was not available so you could not get it working. Now that the new SDK is released we can start building apps using Windows Composition. The sample that James posted is nice and short, but it’s still code that you would need to repeat over and over. As I’ve mentioned before, I’m not a fan of repeating code. I am however a fan of custom controls and behaviors. This effect can easily be made into a behavior.

In James’ sample he is parallaxing an image, but there is no reason it has to be an image. It could be any visual element. This allows you to use graphics or whatever you want as a background.

public class ParallaxBehavior : Behavior<FrameworkElement>
{
    /// <summary>
    /// Gets or sets the element that will parallax while scrolling.
    /// </summary>
    public UIElement ParallaxContent
    {
        get { return (UIElement)GetValue(ParallaxContentProperty); }
        set { SetValue(ParallaxContentProperty, value); }
    }
 
    public static readonly DependencyProperty ParallaxContentProperty = DependencyProperty.Register(
        "ParallaxContent", 
        typeof(UIElement), 
        typeof(ParallaxBehavior), 
        new PropertyMetadata(null, OnParallaxContentChanged));
 
    /// <summary>
    /// Gets or sets the rate at which the ParallaxContent parallaxes.
    /// </summary>
    public double ParallaxMultiplier
    {
        get { return (double)GetValue(ParallaxMultiplierProperty); }
        set { SetValue(ParallaxMultiplierProperty, value); }
    }
 
    public static readonly DependencyProperty ParallaxMultiplierProperty = DependencyProperty.Register(
        "ParallaxMultiplier", 
        typeof(double), 
        typeof(ParallaxBehavior), 
        new PropertyMetadata(0.3d));
 
    protected override void OnAttached()
    {
        base.OnAttached();
        AssignParallax();
    }
 
    private void AssignParallax()
    {
        if (ParallaxContent == null) return;
        if (AssociatedObject == null) return;
 
        var scroller = AssociatedObject as ScrollViewer;
        if (scroller == null)
        {
            scroller = AssociatedObject.GetChildOfType<ScrollViewer>();
        }
        if (scroller == null) return;
 
        CompositionPropertySet scrollerViewerManipulation = ElementCompositionPreview.GetScrollViewerManipulationPropertySet(scroller);
 
        Compositor compositor = scrollerViewerManipulation.Compositor;
 
        ExpressionAnimation expression = compositor.CreateExpressionAnimation("ScrollManipululation.Translation.Y * ParallaxMultiplier");
 
        expression.SetScalarParameter("ParallaxMultiplier", (float)ParallaxMultiplier);
        expression.SetReferenceParameter("ScrollManipululation", scrollerViewerManipulation);
 
        Visual textVisual = ElementCompositionPreview.GetElementVisual(ParallaxContent);
        textVisual.StartAnimation("Offset.Y", expression);
    }
 
    private static void OnParallaxContentChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var b = d as ParallaxBehavior;
        b.AssignParallax();
    }
 }

You will need to reference the new UWP Behaviors SDK from nuget for this behavior

Now adding the parallax effect to your pages is very simple.

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    <Image x:Name="ParallaxImage" Source="ms-appx:///Assets/Guadeloupe.jpg" Stretch="Fill"/>
    <ScrollViewer>
        <TextBlock HorizontalAlignment="Stretch" TextWrapping="WrapWholeWords" FontSize="30" Foreground="Black">
                Lorem ipsum dolor sit amet, consectetur adipiscing elit. 
                Nunc fringilla ultrices est eu ornare. 
                Suspendisse purus massa, iaculis in finibus dictum, gravida vel purus. 
                Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos.
        </TextBlock>
        <interactivity:Interaction.Behaviors>
            <behaviors:ParallaxBehavior ParallaxContent="{Binding ElementName=ParallaxImage}" />
        </interactivity:Interaction.Behaviors>    
    </ScrollViewer>                                
</Grid>

I took the code from James’ sample, but shortened the text of the TextBlock for easier viewing.

This behavior can also be used when you have controls that have ScrollViewers within them like the ListView

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    <ListView>
        <ListView.Header>
            <Image x:Name="ParallaxImage" Source="ms-appx:///Assets/Guadeloupe.jpg" Stretch="UniformToFill"/>
        </ListView.Header>
        <ListView.ItemContainerStyle>
            <Style TargetType="ListViewItem">
                <Setter Property="Background" Value="White"/>
            </Style>
        </ListView.ItemContainerStyle>
        <x:String>Lorem ipsum dolor sit amet, consectetur adipiscing.</x:String>
        <x:String>Nunc fringilla ultrices est eu ornare.</x:String>
        <x:String>Suspendisse purus massa, iaculis in finibus dictum, gravida vel purus.</x:String>
        <interactivity:Interaction.Behaviors>
            <behaviors:ParallaxBehavior ParallaxContent="{Binding ElementName=ParallaxImage}" ParallaxMultiplier="-0.2"/>
        </interactivity:Interaction.Behaviors>
    </ListView>
</Grid>

You can find the source for the behavior and three samples on GitHub.

And here is a video demonstrating three samples.