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; }