// Apply two sourcemodifiers to the input source: One to provide resistance, one to stop motion
        public void SetupPullToRefreshBehavior(
            float pullToRefreshDistance)
        {
            //
            // Modifier 1: Cut DeltaY to a third as long as the InteractionTracker is not yet at the
            // pullRefreshDistance.
            //

            CompositionConditionalValue resistanceModifier = CompositionConditionalValue.Create(_compositor);

            ExpressionAnimation resistanceCondition = _compositor.CreateExpressionAnimation(
                $"-tracker.Position.Y < {pullToRefreshDistance}");

            resistanceCondition.SetReferenceParameter("tracker", _tracker);

            ExpressionAnimation resistanceAlternateValue = _compositor.CreateExpressionAnimation(
                "source.DeltaPosition.Y / 3");

            resistanceAlternateValue.SetReferenceParameter("source", _interactionSource);

            resistanceModifier.Condition = resistanceCondition;
            resistanceModifier.Value     = resistanceAlternateValue;

            //
            // Modifier 2: Zero the delta if we are past the pullRefreshDistance. (So we can't pan
            // past the pullRefreshDistance)
            //

            CompositionConditionalValue stoppingModifier  = CompositionConditionalValue.Create(_compositor);
            ExpressionAnimation         stoppingCondition = _compositor.CreateExpressionAnimation(
                $"-tracker.Position.Y >= {pullToRefreshDistance}");

            stoppingCondition.SetReferenceParameter("tracker", _tracker);

            ExpressionAnimation stoppingAlternateValue = _compositor.CreateExpressionAnimation("0");

            stoppingModifier.Condition = stoppingCondition;
            stoppingModifier.Value     = stoppingAlternateValue;

            //
            // Apply the modifiers to the source as a list
            //

            List <CompositionConditionalValue> modifierList =
                new List <CompositionConditionalValue>()
            {
                resistanceModifier, stoppingModifier
            };

            _interactionSource.ConfigureDeltaPositionYModifiers(modifierList);
        }
        private void ConfigureInteractionTracker()
        {
            _interactionSource = VisualInteractionSource.Create(_rootContainer);
            _interactionSource.ScaleSourceMode     = InteractionSourceMode.EnabledWithInertia;
            _interactionSource.PositionXSourceMode = InteractionSourceMode.EnabledWithInertia;

            _tracker          = InteractionTracker.CreateWithOwner(_compositor, this);
            _tracker.MinScale = 0.6f;
            _tracker.MaxScale = 5.0f;

            _tracker.MaxPosition = new Vector3((float)Root.ActualWidth * 1.5f, 0, 0);
            _tracker.MinPosition = _tracker.MaxPosition * -1;

            _tracker.ScaleInertiaDecayRate = 0.96f;

            _tracker.InteractionSources.Add(_interactionSource);

            var tracker = _tracker.GetReference();

            //
            // Here's the trick: we take the scale output from the tracker, and convert it into a
            // value that represents Z.  Then we bind it to the world container's Z position.
            //

            var scaleExpression = EF.Lerp(0, 1000, (1 - tracker.Scale) / (1 - tracker.MaxScale));

            _worldContainer.StartAnimation("Offset.Z", scaleExpression);

            //
            // Bind the output of the tracker to the world container's XY position.
            //

            _worldContainer.StartAnimation("Offset.XY", -tracker.Position.XY);


            //
            // Scaling usually affects position.  This depends on the center point of the scale.
            // But for our UI, we want don't scale to adjust the position (since we're using scale
            // to change Offset.Z).  So to prevent scale from affecting position, we must always use
            // the top-left corner of the WorldContainer as the center point (note: we could also
            // use the tracker's negated position, since that's where WorldContainer is getting its
            // offset).
            //
            // Create input modifiers to override the center point value.
            //

            var centerpointXModifier = CompositionConditionalValue.Create(_compositor);
            var centerpointYModifier = CompositionConditionalValue.Create(_compositor);

            centerpointXModifier.Condition = _compositor.CreateExpressionAnimation("true");
            centerpointXModifier.Value     = _compositor.CreateExpressionAnimation("world.Offset.X");
            centerpointXModifier.Value.SetReferenceParameter("world", _worldContainer);

            _interactionSource.ConfigureCenterPointXModifiers(new[] { centerpointXModifier });
            _tracker.ConfigureCenterPointXInertiaModifiers(new[] { centerpointXModifier });


            centerpointYModifier.Condition = _compositor.CreateExpressionAnimation("true");
            centerpointYModifier.Value     = _compositor.CreateExpressionAnimation("world.Offset.Y");
            centerpointYModifier.Value.SetReferenceParameter("world", _worldContainer);

            _interactionSource.ConfigureCenterPointYModifiers(new[] { centerpointYModifier });
            _tracker.ConfigureCenterPointYInertiaModifiers(new[] { centerpointYModifier });
        }
 /// <summary>
 /// Use the value of specified ExpressionNode as the value for this composition conditional value
 /// </summary>
 /// <param name="modifier">The modifier.</param>
 /// <param name="expressionNode">The root ExpressionNode that represents the ExpressionAnimation.</param>
 public static void SetValue(this CompositionConditionalValue modifier, ExpressionNode expressionNode)
 {
     modifier.Value = CreateExpressionAnimationFromNode(modifier.Compositor, expressionNode);
 }
        private void MainPage_Loaded(object sender, RoutedEventArgs e)
        {
            ThumbnailList.ItemsSource = new List <Item>
            {
                new Item {
                    Name = "Daren"
                },
                new Item {
                    Name = "Kendra"
                },
                new Item {
                    Name = "Gavin"
                },
                new Item {
                    Name = "Naia"
                },
                new Item {
                    Name = "Frodo"
                },
                new Item {
                    Name = "Stella"
                },
                new Item {
                    Name = "DJ"
                },
                new Item {
                    Name = "Stasch"
                }
            };

            // InteractionTracker and VisualInteractionSource setup.
            _root = ElementCompositionPreview.GetElementVisual(Root);
            _contentPanelVisual = ElementCompositionPreview.GetElementVisual(ContentPanel);
            _compositor         = _root.Compositor;
            _tracker            = InteractionTracker.Create(_compositor);
            _interactionSource  = VisualInteractionSource.Create(_root);
            _interactionSource.PositionYSourceMode   = InteractionSourceMode.EnabledWithInertia;
            _interactionSource.PositionYChainingMode = InteractionChainingMode.Always;
            _tracker.InteractionSources.Add(_interactionSource);
            var refreshPanelHeight = (float)RefreshPanel.ActualHeight;

            _tracker.MaxPosition = new Vector3((float)Root.ActualWidth, 0, 0);
            _tracker.MinPosition = new Vector3(-(float)Root.ActualWidth, -refreshPanelHeight, 0);

            // Use the Tacker's Position (negated) to apply to the Offset of the Image.
            // The -{refreshPanelHeight} is to hide the refresh panel
            m_positionExpression =
                _compositor.CreateExpressionAnimation($"-tracker.Position.Y - {refreshPanelHeight} ");
            m_positionExpression.SetReferenceParameter("tracker", _tracker);
            _contentPanelVisual.StartAnimation("Offset.Y", m_positionExpression);

            var resistanceModifier  = CompositionConditionalValue.Create(_compositor);
            var resistanceCondition = _compositor.CreateExpressionAnimation(
                $"-tracker.Position.Y < {pullToRefreshDistance}");

            resistanceCondition.SetReferenceParameter("tracker", _tracker);
            var resistanceAlternateValue = _compositor.CreateExpressionAnimation(
                "source.DeltaPosition.Y / 3");

            resistanceAlternateValue.SetReferenceParameter("source", _interactionSource);
            resistanceModifier.Condition = resistanceCondition;
            resistanceModifier.Value     = resistanceAlternateValue;

            var stoppingModifier  = CompositionConditionalValue.Create(_compositor);
            var stoppingCondition = _compositor.CreateExpressionAnimation(
                $"-tracker.Position.Y >= {pullToRefreshDistance}");

            stoppingCondition.SetReferenceParameter("tracker", _tracker);
            var stoppingAlternateValue = _compositor.CreateExpressionAnimation("0");

            stoppingModifier.Condition = stoppingCondition;
            stoppingModifier.Value     = stoppingAlternateValue;
            //Now add the 2 source modifiers to the InteractionTracker.
            var modifierList = new List <CompositionConditionalValue> {
                resistanceModifier, stoppingModifier
            };

            _interactionSource.ConfigureDeltaPositionYModifiers(modifierList);

            //The PointerPressed handler needs to be added using AddHandler method with the //handledEventsToo boolean set to "true"
            //instead of the XAML element's "PointerPressed=Window_PointerPressed",
            //because the list view needs to chain PointerPressed handled events as well.
            ContentPanel.AddHandler(PointerPressedEvent, new PointerEventHandler(Window_PointerPressed), true);
        }