How can I retrieve a CompositionEffect given a FrameworkElement?

55 views Asked by At

I'm experimenting with a chained effect and set it on an Image control (TestImage) as such:

    private void TestImage_ImageOpened(object sender, RoutedEventArgs e)
    {
        /*
            (input) Backdrop -> GaussianBlur -> |
                                 ColorSource -> | Blend -> Saturation (output)
         */

        var compositor = ElementCompositionPreview.GetElementVisual(this.TestImage).Compositor;

        var blurEffect = new GaussianBlurEffect()
        {
            Name = "Blur",
            BlurAmount = 10f,
            BorderMode = EffectBorderMode.Hard,
            Optimization = EffectOptimization.Balanced,
            Source = new CompositionEffectSourceParameter("source"),
        };

        var colorEffect = new ColorSourceEffect
        {
            Name = "Tint",
        };

        var blendEffect = new BlendEffect
        {
            Background = blurEffect,
            Foreground = colorEffect,
            Mode = BlendEffectMode.Overlay,
        };

        var saturationEffect = new SaturationEffect
        {
            Name = "Saturation",
            Source = blendEffect,
            Saturation = 1.5f,
        };

        var factory = compositor.CreateEffectFactory(saturationEffect, new[]
        {
            "Blur.BlurAmount",
            "Tint.Color",
            "Saturation.Saturation",
        });

        var brush = factory.CreateBrush();
        brush.SetSourceParameter("source", compositor.CreateBackdropBrush());

        // Animatable properties
        brush.Properties.InsertScalar("Blur.BlurAmount", 10f);
        brush.Properties.InsertColor("Tint.Color", Color.FromArgb(128, 255, 0, 0));
        brush.Properties.InsertScalar("Saturation.Saturation", 1.5f);

        var sprite = compositor.CreateSpriteVisual();
        sprite.Brush = brush;
        sprite.Size = new Vector2((float)this.TestImage.ActualWidth, (float)this.TestImage.ActualHeight);
        ElementCompositionPreview.SetElementChildVisual(this.TestImage, sprite);
    }

My goal is to then retrieve that effect at a later time so I can read some of the values on that effect. How can I get the effect using only the TestImage control and the Composition layer?

1

There are 1 answers

0
Maximus On BEST ANSWER

I solved my problem using an attached property since this feature is not natively supported:

internal static SpriteVisual GetSprite(DependencyObject obj) => (SpriteVisual)obj.GetValue(SpriteProperty);

internal static void SetSprite(DependencyObject obj, SpriteVisual value) => obj.SetValue(SpriteProperty, value);

/// <summary>
/// Composition Sprite attached to a FrameworkElement.
/// </summary>
internal static readonly DependencyProperty SpriteProperty =
    DependencyProperty.RegisterAttached(
        "Sprite",
        typeof(SpriteVisual),
        typeof(MyAnimations),
        new PropertyMetadata(null));