Beispiel #1
0
        internal override void UpdateLayoutTransitionCore(FrameworkElement child, FrameworkElement root, object tag, TagData newTagData)
        {
            TagData tagData;
            bool    gotData = TagDictionary.TryGetValue(tag, out tagData);

            if (!gotData)
            {
                tagData = new TagData();
                TagDictionary.Add(tag, tagData);
            }

            tagData.ParentRect = newTagData.ParentRect;
            tagData.AppRect    = newTagData.AppRect;
            tagData.Parent     = newTagData.Parent;
            tagData.Child      = newTagData.Child;
            tagData.Timestamp  = newTagData.Timestamp;
        }
        internal override void UpdateLayoutTransitionCore(FrameworkElement child, FrameworkElement root, object tag, TagData newTagData)
        {
            TagData tagData;
            Rect    previousRect;
            bool    parentChange      = false;
            bool    usingBeforeLoaded = false;
            object  initialTag        = GetInitialIdentityTag(child);

            // Locate the previous tag, and the parent-relative previous rect. The previous rect is computed using the app-relative rect if switching parents.
            // Note that we do not use the app-relative rect all time time, because when the parent itself moves, it accounts for all the motion and we do not have to.
            bool gotData = TagDictionary.TryGetValue(tag, out tagData);

            // if spawn point has changed then throw away the old one
            if (gotData && tagData.InitialTag != initialTag)
            {
                gotData = false;
                TagDictionary.Remove(tag);
            }
            if (!gotData)
            {
                TagData spawnData;

                if (initialTag != null && TagDictionary.TryGetValue(initialTag, out spawnData))
                {
                    previousRect      = TranslateRect(spawnData.AppRect, root, newTagData.Parent);
                    parentChange      = true;
                    usingBeforeLoaded = true;
                }
                else
                {
                    previousRect = Rect.Empty;
                }

                tagData = new TagData()
                {
                    ParentRect = Rect.Empty, AppRect = Rect.Empty, Parent = newTagData.Parent, Child = child, Timestamp = DateTime.Now, InitialTag = initialTag
                };
                TagDictionary.Add(tag, tagData);
            }
            else if (tagData.Parent != VisualTreeHelper.GetParent(child))
            {
                previousRect = TranslateRect(tagData.AppRect, root, newTagData.Parent);
                parentChange = true;
            }
            else
            {
                previousRect = tagData.ParentRect;
            }

            FrameworkElement originalChild = child;

            if ((!FluidMoveBehavior.IsEmptyRect(previousRect) && !FluidMoveBehavior.IsEmptyRect(newTagData.ParentRect)) && (!IsClose(previousRect.Left, newTagData.ParentRect.Left) || !IsClose(previousRect.Top, newTagData.ParentRect.Top)) ||
                (child != tagData.Child && transitionStoryboardDictionary.ContainsKey(tag)))
            {
                Rect currentRect     = previousRect;
                bool forceFloatAbove = false;

                // If this element was animating before, append its current transform to the start position and kill the old animation.
                // Note that in an overlay scenario, the animation is on the image in the overlay.
                Storyboard oldTransitionStoryboard = null;
                if (transitionStoryboardDictionary.TryGetValue(tag, out oldTransitionStoryboard))
                {
                    object           tagOverlay       = GetOverlay(tagData.Child);
                    AdornerContainer adornerContainer = (AdornerContainer)tagOverlay;

                    forceFloatAbove = (tagOverlay != null); // if floating before, we need to keep floating
                    FrameworkElement elementWithTransform = tagData.Child;

                    if (tagOverlay != null)
                    {
                        Canvas overlayCanvas = adornerContainer.Child as Canvas;
                        if (overlayCanvas != null)
                        {
                            elementWithTransform = overlayCanvas.Children[0] as FrameworkElement;
                        }
                    }

                    // if we're picking a specific starting point, don't append this transform
                    if (!usingBeforeLoaded)
                    {
                        Transform transform = GetTransform(elementWithTransform);
                        currentRect = transform.TransformBounds(currentRect);
                    }

                    transitionStoryboardDictionary.Remove(tag);
                    oldTransitionStoryboard.Stop();
                    oldTransitionStoryboard = null;
                    RemoveTransform(elementWithTransform);

                    if (tagOverlay != null)
                    {
                        System.Windows.Documents.AdornerLayer.GetAdornerLayer(root).Remove(adornerContainer);
                        TransferLocalValue(tagData.Child, FluidMoveBehavior.cacheDuringOverlayProperty, FrameworkElement.RenderTransformProperty);
                        SetOverlay(tagData.Child, null);
                    }
                }

                object overlay = null;

                // If we need to float this element, then we have to:
                // 1. Take a picture of it
                // 2. Put that picture in an Image in a popup
                // 3. Hide the original element (opacity=0 so we do not disturb layout)
                // 4. Animate the image
                // 5. Keep track of all the info we need to unwind this later
                if (forceFloatAbove || (parentChange && this.FloatAbove))
                {
                    Canvas canvas = new Canvas()
                    {
                        Width = newTagData.ParentRect.Width, Height = newTagData.ParentRect.Height, IsHitTestVisible = false
                    };

                    Rectangle rectangle = new Rectangle()
                    {
                        Width = newTagData.ParentRect.Width, Height = newTagData.ParentRect.Height, IsHitTestVisible = false
                    };
                    rectangle.Fill = new VisualBrush(child);
                    canvas.Children.Add(rectangle);
                    AdornerContainer adornerContainer = new AdornerContainer(child)
                    {
                        Child = canvas
                    };
                    overlay = adornerContainer;

                    // remember this overlay so we can get info from it
                    SetOverlay(originalChild, overlay);

                    System.Windows.Documents.AdornerLayer adorners = System.Windows.Documents.AdornerLayer.GetAdornerLayer(root);
                    adorners.Add(adornerContainer);

                    // Note: Not using this approach currently because the bitmap is not ready yet
                    // To remove use of VisualBrush, have to fill in bitmap after a render
                    //RenderTargetBitmap bitmap = new RenderTargetBitmap((int)child.ActualWidth, (int)child.ActualHeight, 96, 96, PixelFormats.Pbgra32);
                    //bitmap.Render(parent);
                    //image.Source = bitmap;

                    // can't animate this or it will flash, have to set the value outright
                    TransferLocalValue(child, FrameworkElement.RenderTransformProperty, FluidMoveBehavior.cacheDuringOverlayProperty);
                    child.RenderTransform  = new TranslateTransform(-10000, -10000);
                    canvas.RenderTransform = new TranslateTransform(10000, 10000);

                    // change value here so that the animations will be applied to the image
                    child = rectangle;
                }

                // OK, now build the actual animation
                Rect       parentRect           = newTagData.ParentRect;
                Storyboard transitionStoryboard = CreateTransitionStoryboard(child, usingBeforeLoaded, ref parentRect, ref currentRect);

                // Put this storyboard in the running dictionary so we can detect reentrancy
                transitionStoryboardDictionary.Add(tag, transitionStoryboard);

                transitionStoryboard.Completed += delegate(object sender, EventArgs e)
                {
                    Storyboard currentlyRunningStoryboard;
                    if (transitionStoryboardDictionary.TryGetValue(tag, out currentlyRunningStoryboard) && currentlyRunningStoryboard == transitionStoryboard)
                    {
                        transitionStoryboardDictionary.Remove(tag);
                        transitionStoryboard.Stop();
                        RemoveTransform(child);
                        child.InvalidateMeasure();

                        if (overlay != null)
                        {
                            System.Windows.Documents.AdornerLayer.GetAdornerLayer(root).Remove((AdornerContainer)overlay);
                            TransferLocalValue(originalChild, FluidMoveBehavior.cacheDuringOverlayProperty, FrameworkElement.RenderTransformProperty);
                            SetOverlay(originalChild, null);
                        }
                    }
                };

                transitionStoryboard.Begin();
            }

            // Store current tag status
            tagData.ParentRect = newTagData.ParentRect;
            tagData.AppRect    = newTagData.AppRect;
            tagData.Parent     = newTagData.Parent;
            tagData.Child      = newTagData.Child;
            tagData.Timestamp  = newTagData.Timestamp;
        }