Beispiel #1
0
        private static AnimatedWrapPanelAttachedData GetAnimatedWrapPanelAttachedData(DependencyObject obj)
        {
            // This uses a standard attached DP lazy-init pattern that will create the default value
            // for this property and set it if GetValue returned null. That means that this method
            // will never return null.

            object value = obj.GetValue(AnimatedWrapPanelAttachedDataProperty);

            if (value == null)
            {
                AnimatedWrapPanelAttachedData data = new AnimatedWrapPanelAttachedData();
                SetAnimatedWrapPanelAttachedData(obj, data);
                return(data);
            }
            else
            {
                return((AnimatedWrapPanelAttachedData)value);
            }
        }
Beispiel #2
0
        /// <summary>
        /// A "normal" ArrangeOverride would just put things where they belong. What this one does
        /// is to move the children towards their destinations according to the virtual animation
        /// data that has been attached to each element. When they get there, the virtual animation
        /// is turned off.
        /// </summary>
        protected override Size ArrangeOverride(Size finalSize)
        {
            DateTime now = DateTime.Now;

            foreach (UIElement child in Children)
            {
                AnimatedWrapPanelAttachedData data = GetAnimatedWrapPanelAttachedData(child);

                TimeSpan elapsed = data.GetElapsed(now);

                if (elapsed < Duration || data.TargetPosition != data.CurrentPosition)
                {
                    // The virtual animation is not done yet, so figure out how far along it is...
                    double progress = (Duration.TimeSpan != TimeSpan.Zero) ? Math.Min(elapsed.TotalMilliseconds / Duration.TimeSpan.TotalMilliseconds, 1.0) : 1;

                    // ...and what the next position is.
                    Point newPosition = BlendPoint(_interpolation, data.StartPosition, data.TargetPosition, progress);
                    child.Arrange(new Rect(newPosition.X, newPosition.Y, child.DesiredSize.Width, _rowHeights[data.Row]));
                    data.CurrentPosition = newPosition;
                }
                else
                {
                    // This element is not animating, but it might have become invalid on its own, so it still
                    // needs to be arranged. The layout system will do as little as possible.
                    child.Arrange(new Rect(data.CurrentPosition.X, data.CurrentPosition.Y, child.DesiredSize.Width, _rowHeights[data.Row]));
                    if (data.IsAnimating)
                    {
                        --_animatingElements;

                        // This is the only place where IsAnimating is set to false. This turns off the virtual animation.
                        data.IsAnimating = false;
                    }
                }
            }

            return(finalSize);
        }
Beispiel #3
0
 private static void SetAnimatedWrapPanelAttachedData(DependencyObject obj, AnimatedWrapPanelAttachedData value)
 {
     obj.SetValue(AnimatedWrapPanelAttachedDataProperty, value);
 }
Beispiel #4
0
        /// <summary>
        /// This method is required when subclassing from Panel. It figures out how big the childre are
        /// and where they should go. It attaches an object to each child to hold the data so that the
        /// panel itself does not have to maintain state.
        /// </summary>
        protected override Size MeasureOverride(Size availableSize)
        {
            // Measure each child first. This is inefficient, but it is necessary in order
            // to have smooth animations of new children. Otherwise, the animations may jump
            // due to the time that template expansion can take.

            foreach (FrameworkElement child in Children)
            {
                child.Measure(availableSize);
            }

            double rowHeight = 0;
            int    row       = 0;

            _rowHeights.Clear();

            Size desiredSize = Size.Empty;

            Point    nextChildPosition = new Point(0, 0);
            DateTime now = DateTime.Now;

            _animatingElements = 0;

            // Now each the position from each child is computed. If the child is not where it is supposed
            // to be, set up a virtual animation to move it there.

            foreach (FrameworkElement child in Children)
            {
                if (nextChildPosition.X + child.DesiredSize.Width > availableSize.Width)
                {
                    // Save old row information
                    _rowHeights.Add(rowHeight);
                    ++row;

                    nextChildPosition.X  = 0;
                    nextChildPosition.Y += rowHeight;
                    rowHeight            = 0;
                }

                AnimatedWrapPanelAttachedData data = GetAnimatedWrapPanelAttachedData(child);

                // If this is a new element, then start it off of the screen
                if (data.CurrentPosition == AnimatedWrapPanelAttachedData.Unset)
                {
                    data.CurrentPosition = new Point(-child.DesiredSize.Width, -child.DesiredSize.Height);
                }

                if (data.TargetPosition != nextChildPosition)
                {
                    // The target of this element is either brand new or has moved, so we need to
                    // recalculate everything, and set up a virtual animation.

                    data.StartTime      = now;
                    data.StartPosition  = data.CurrentPosition;
                    data.TargetPosition = nextChildPosition;
                    data.Row            = row;

                    // IsAnimating only gets set to true right here. This begins the virtual animation
                    // for this element.
                    data.IsAnimating = true;

                    ++_animatingElements;
                }
                else if (data.IsAnimating)
                {
                    // This item is still animating, so keep track of it, but since
                    // the target position has not changed, don't do anything else.

                    ++_animatingElements;
                }

                desiredSize.Width  = Math.Max(desiredSize.Width, nextChildPosition.X + child.DesiredSize.Width);
                desiredSize.Height = Math.Max(desiredSize.Height, nextChildPosition.Y + child.DesiredSize.Height);

                // Keep track of the maximum height for this line.
                rowHeight = Math.Max(rowHeight, child.DesiredSize.Height);

                // Advance the position of the next element.
                nextChildPosition.X += child.DesiredSize.Width;
            }

            _rowHeights.Add(rowHeight);

            // Debug.WriteLine("Animating {0} elements", _animatingElements);

            return(desiredSize);
        }