Skip to content

Commit

Permalink
Fix #4214 - Update AttachedDropShadow visual when element layout chan…
Browse files Browse the repository at this point in the history
…ges and visibility changes
  • Loading branch information
michael-hawker committed Sep 8, 2021
1 parent 0ce4553 commit fb5b405
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 4 deletions.
72 changes: 68 additions & 4 deletions Microsoft.Toolkit.Uwp.UI/Shadows/AttachedDropShadow.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System;
using System.Linq;
using System.Numerics;
using Windows.Foundation;
Expand Down Expand Up @@ -166,6 +167,16 @@ protected internal override void OnElementContextUninitialized(AttachedShadowEle
_container.Children.Remove(context.SpriteVisual);
}

context.SpriteVisual?.StopAnimation("Size");

context.Element.LayoutUpdated -= Element_LayoutUpdated;

if (context.VisibilityToken != null)
{
context.Element.UnregisterPropertyChangedCallback(UIElement.VisibilityProperty, context.VisibilityToken.Value);
context.VisibilityToken = null;
}

base.OnElementContextUninitialized(context);
}

Expand All @@ -176,6 +187,50 @@ protected override void SetElementChildVisual(AttachedShadowElementContext conte
{
_container.Children.InsertAtTop(context.SpriteVisual);
}

// Handles size changing and other elements around it updating.
context.Element.LayoutUpdated -= Element_LayoutUpdated;
context.Element.LayoutUpdated += Element_LayoutUpdated;

if (context.VisibilityToken != null)
{
context.Element.UnregisterPropertyChangedCallback(UIElement.VisibilityProperty, context.VisibilityToken.Value);
context.VisibilityToken = null;
}

context.VisibilityToken = context.Element.RegisterPropertyChangedCallback(UIElement.VisibilityProperty, Element_VisibilityChanged);
}

private void Element_LayoutUpdated(object sender, object e)
{
// Update other shadows to account for layout changes
CastToElement_SizeChanged(null, null);
}

private void Element_VisibilityChanged(DependencyObject sender, DependencyProperty dp)
{
if (sender is FrameworkElement element)
{
var context = GetElementContext(element);

if (element.Visibility == Visibility.Collapsed)
{
if (_container != null && _container.Children.Contains(context.SpriteVisual))
{
_container.Children.Remove(context.SpriteVisual);
}
}
else
{
if (_container != null && !_container.Children.Contains(context.SpriteVisual))
{
_container.Children.InsertAtTop(context.SpriteVisual);
}
}
}

// Update other shadows to account for layout changes
CastToElement_SizeChanged(null, null);
}

/// <inheritdoc/>
Expand Down Expand Up @@ -255,12 +310,24 @@ protected override CompositionBrush GetShadowMask(AttachedShadowElementContext c
}

// Position our shadow in the correct spot to match the corresponding element.
context.SpriteVisual.Size = context.Element.RenderSize.ToVector2();
context.SpriteVisual.Offset = context.Element.CoordinatesFrom(CastTo).ToVector3();

BindSizeAndScale(context.SpriteVisual, context.Element);

return mask;
}

private static void BindSizeAndScale(CompositionObject source, UIElement target)
{
var visual = ElementCompositionPreview.GetElementVisual(target);
var bindSizeAnimation = source.Compositor.CreateExpressionAnimation($"{nameof(visual)}.Size * {nameof(visual)}.Scale.XY");

bindSizeAnimation.SetReferenceParameter(nameof(visual), visual);

// Start the animation
source.StartAnimation("Size", bindSizeAnimation);
}

private void CustomMaskedElement_Loaded(object sender, RoutedEventArgs e)
{
var context = GetElementContext(sender as FrameworkElement);
Expand All @@ -274,9 +341,6 @@ private void CustomMaskedElement_Loaded(object sender, RoutedEventArgs e)
/// <inheritdoc/>
protected internal override void OnSizeChanged(AttachedShadowElementContext context, Size newSize, Size previousSize)
{
var sizeAsVec2 = newSize.ToVector2();

context.SpriteVisual.Size = sizeAsVec2;
context.SpriteVisual.Offset = context.Element.CoordinatesFrom(CastTo).ToVector3();

UpdateShadowClip(context);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ public sealed class AttachedShadowElementContext

private Dictionary<string, object> _resources;

internal long? VisibilityToken { get; set; }

/// <summary>
/// Gets a value indicating whether or not this <see cref="AttachedShadowElementContext"/> has been initialized.
/// </summary>
Expand Down

0 comments on commit fb5b405

Please sign in to comment.