Search code examples
c#gridviewuwpshadow

Dynamically resizing shadow in UWP


I am working on attaching a shadow to the GridView items. The code below does that, however my GridView items can resize depending on the window size. And the shadow does not resize with it. I understand why it doesn't, since I'm just setting a static size on the shadow, but I can't figure out how to make the shadow resize with the grid that it's behind.

Here is my code:

private void Item_Loaded(object sender, RoutedEventArgs e)
{
    var root = (UIElement)sender;
    InitializeShadowAnimation(root, FindVisualChild<Canvas>(root));
}

private void InitializeShadowAnimation(UIElement root, UIElement shadowHost)
{
    var rootVisual = ElementCompositionPreview.GetElementVisual(root);
    var shadowHostVisual = ElementCompositionPreview.GetElementVisual(shadowHost);
    var compositor = shadowHostVisual.Compositor;

    var shadow = compositor.CreateDropShadow();
    shadow.BlurRadius = 35f;
    shadow.Offset = new Vector3(15, 15, 5);

    var shadowVisual = compositor.CreateSpriteVisual();
    shadowVisual.Shadow = shadow;

    var size = new Vector2(0, 0);

    if (root is FrameworkElement element)
    {
        size = new Vector2((float)element.ActualWidth - 50, (float)element.ActualHeight - 50);
    }

    shadowVisual.Size = size;

    ElementCompositionPreview.SetElementChildVisual(shadowHost, shadowVisual);
}

And here is the corresponding xaml code for the data template:

<DataTemplate x:Key="CardViewItemTemplate" x:DataType="data:MyData">

    <Grid x:Name="MainGrid" Loaded="Item_Loaded" Tag="{Binding}" >

        <Canvas x:Name="ShadowContainer"/>
        
    </Grid>
    
</DataTemplate>

Thanks in advance.


Solution

  • My solution, though maybe not most elegant, is to add a method for the size changed event and reset the shadow.

    private void Item_SizeChanged(object sender, SizeChangedEventArgs e)
    {
        var root = (UIElement)sender;
        UIElement shadowHost = FindVisualChild<Canvas>(root);
        var shadowVisual = ElementCompositionPreview.GetElementChildVisual(shadowHost);
    
        if (shadowVisual == null)
        {
            return;
        }
    
        var size = new Vector2(0, 0);
    
        if (root is FrameworkElement element)
        {
            size = new Vector2((float)element.ActualWidth - 50, (float)element.ActualHeight - 50);
        }
    
        shadowVisual.Size = size;
    }