private void BuildVisualTree()
        {
            // use current position for laying out as we iterate
            Vector3 currentGridPosition = new Vector3(horizontalSpace, horizontalSpace, 1.0f);
            Vector2 imageSize           = new Vector2(imageDimension, imageDimension);

            Vector3KeyFrameAnimation firstAnimation = _compositor.CreateVector3KeyFrameAnimation();

            firstAnimation.InsertKeyFrame(0.0f, new Vector3(-50.0f, -50.0f, 0.0f));
            firstAnimation.InsertKeyFrame(1.0f, currentGridPosition);
            firstAnimation.Duration = TimeSpan.FromMilliseconds(2000);

            var animation = _compositor.CreateVector3KeyFrameAnimation();

            animation.InsertExpressionKeyFrame(0.0f, "previous.Offset");
            animation.InsertExpressionKeyFrame(1.0f, "finalvalue");
            animation.DelayTime = TimeSpan.FromMilliseconds(1000);
            animation.Duration  = TimeSpan.FromMilliseconds(1500);

            Visual previousVisual = null;

            foreach (Uri profileImageUri in GetProfileUrisForTwitterFollowers("@wincomposition"))
            {
                var profileImageVisual = MakeImageVisualforFollower(profileImageUri, imageSize);

                if (previousVisual == null)
                {
                    firstAnimation.SetVector3Parameter("finalvalue", currentGridPosition);
                    profileImageVisual.ConnectAnimation("Offset", firstAnimation).Start();
                }
                else
                {
                    animation.SetReferenceParameter("previous", previousVisual);
                    animation.SetVector3Parameter("finalvalue", currentGridPosition);
                    animation.DelayTime += TimeSpan.FromMilliseconds(300); //50
                    profileImageVisual.ConnectAnimation("Offset", animation).Start();
                }

                _rootVisual.Children.InsertAtBottom(profileImageVisual);

                previousVisual = profileImageVisual;

                #region CalcNextOffset
                // simple dumb layout
                currentGridPosition.X += horizontalSpace + imageDimension;

                if (currentGridPosition.X + imageDimension > this.ActualWidth)
                {
                    currentGridPosition.X  = horizontalSpace;
                    currentGridPosition.Y += imageDimension + verticalSpace;
                }
                #endregion
            }
        }
        public void Start(UIElement newParent, CompositionImage targetImage, ScrollViewer scrollViewer, UIElement animationTarget)
        {
            Visual transitionVisual = ElementCompositionPreview.GetElementChildVisual(_parent);

            ElementCompositionPreview.SetElementChildVisual(_parent, null);


            //
            // We need to reparent the transition visual under the new parent.  This is important to ensure
            // it's propertly clipped, etc.
            //

            GeneralTransform coordinate = newParent.TransformToVisual(_parent);
            Point            position   = coordinate.TransformPoint(new Point(0, 0));

            Vector3 currentOffset = transitionVisual.Offset;

            currentOffset.X        -= (float)position.X;
            currentOffset.Y        -= (float)position.Y;
            transitionVisual.Offset = currentOffset;

            _parent      = newParent;
            _targetImage = targetImage;

            // Move the transition visual to it's new parent
            ElementCompositionPreview.SetElementChildVisual(_parent, transitionVisual);

            // Hide the target Image now since the handoff visual is still transitioning
            targetImage.Opacity = 0f;

            // Load image if necessary
            _imageLoaded = targetImage.IsContentLoaded;
            if (!_imageLoaded)
            {
                targetImage.ImageOpened += CompositionImage_ImageOpened;
            }

            //
            // Create a scoped batch around the animations.  When the batch completes, we know the animations
            // have finished and we can cleanup the transition related objects.
            //

            Compositor compositor = transitionVisual.Compositor;

            _scopeBatch = compositor.CreateScopedBatch(CompositionBatchTypes.Animation);

            //
            // Determine the offset between the parent and the target UIElement.  This will be used to calculate the
            // target position we are animating to.
            //

            coordinate = targetImage.TransformToVisual(_parent);
            position   = coordinate.TransformPoint(new Point(0, 0));

            TimeSpan totalDuration = TimeSpan.FromMilliseconds(1000);
            Vector3KeyFrameAnimation offsetAnimation = compositor.CreateVector3KeyFrameAnimation();

            if (scrollViewer != null)
            {
                CompositionPropertySet scrollProperties = ElementCompositionPreview.GetScrollViewerManipulationPropertySet(scrollViewer);

                // Include the scroller offset as that is a factor
                position.X += scrollViewer.HorizontalOffset;
                position.Y += scrollViewer.VerticalOffset;


                //
                // Since the target position is relative to the target UIElement which can move, we need to construct
                // an expression to bind the target's position to the end position of our animation.
                //

                string expression = "Vector3(scrollingProperties.Translation.X, scrollingProperties.Translation.Y, 0) + itemOffset";
                offsetAnimation.InsertExpressionKeyFrame(1f, expression);
                offsetAnimation.SetReferenceParameter("scrollingProperties", scrollProperties);
                offsetAnimation.SetVector3Parameter("itemOffset", new Vector3((float)position.X, (float)position.Y, 0));
                offsetAnimation.Duration = totalDuration;
            }
            else
            {
                offsetAnimation.InsertKeyFrame(1, new Vector3((float)position.X, (float)position.Y, 0));
                offsetAnimation.Duration = totalDuration;
            }

            // Create size animation to change size of the visual
            Vector2KeyFrameAnimation sizeAnimation = compositor.CreateVector2KeyFrameAnimation();

            sizeAnimation.InsertKeyFrame(1f, new Vector2((float)targetImage.ActualWidth, (float)targetImage.ActualHeight));
            sizeAnimation.Duration = totalDuration;

            // Create the fade in animation for the other page content
            if (animationTarget != null)
            {
                Visual fadeVisual = ElementCompositionPreview.GetElementVisual(animationTarget);
                ScalarKeyFrameAnimation fadeIn = compositor.CreateScalarKeyFrameAnimation();
                fadeIn.InsertKeyFrame(0f, 0.0f);
                fadeIn.InsertKeyFrame(1f, 1.0f);
                fadeIn.Duration = totalDuration;
                fadeVisual.StartAnimation("Opacity", fadeIn);
            }

            //Start Animations
            _sprite.StartAnimation("Size", sizeAnimation);
            _sprite.StartAnimation("Offset", offsetAnimation);

            //Scoped batch completed event
            _scopeBatch.Completed += ScopeBatch_Completed;
            _scopeBatch.End();

            // Clear the flag
            _animationCompleted = false;
        }