Utilisation de la couche visuelle avec XAML

La plupart des applications qui consomment des fonctionnalités de couche visuelle utilisent XAML pour définir le contenu principal de l’interface utilisateur. Dans la mise à jour anniversaire Windows 10, il existe de nouvelles fonctionnalités dans l’infrastructure XAML et la couche visuelle qui facilitent la combinaison de ces deux technologies pour créer de superbes expériences utilisateur. Les fonctionnalités d’interopérabilité XAML et Visual Layer peuvent être utilisées pour créer des animations et des effets avancés non disponibles à l’aide d’API XAML seules. notamment :

  • Effets de pinceau comme le flou et le verre gelé
  • Effets d’éclairage dynamique
  • Animations pilotées par défilement et parallax
  • Animations de disposition automatique
  • Ombres portées parfaites en pixels

Ces effets et animations peuvent être appliqués au contenu XAML existant. Vous n’avez donc pas à restructurer considérablement votre application XAML pour tirer parti des nouvelles fonctionnalités. Les animations de disposition, les ombres et les effets flous sont abordés dans la section Recettes ci-dessous. Pour obtenir un exemple de code implémentant parallax, consultez l’exemple ParallaxingListItems. Le référentiel WindowsCompositionSamples contient également plusieurs autres exemples d’implémentation d’animations, d’ombres et d’effets.

Classe XamlCompositionBrushBase

XamlCompositionBrush fournit une classe de base pour les pinceaux XAML qui peintnt une zone avec un CompositionBrush. Cela peut être utilisé pour appliquer facilement des effets de composition tels que du flou ou du verre gelé aux éléments d’interface utilisateur XAML.

Pour plus d’informations sur l’utilisation des pinceaux avec l’interface utilisateur XAML, consultez la section Pinceaux .

Pour obtenir des exemples de code, consultez la page de référence de la classe XamlCompositionBrushBase.

Classe XamlLight

XamlLight fournit une classe de base pour les effets d’éclairage XAML qui éclairent dynamiquement une zone avec un Objet CompositionLight.

Consultez la section Éclairage pour plus d’informations sur l’utilisation des lumières, notamment sur les éléments d’interface utilisateur XAML d’éclairage.

Pour obtenir des exemples de code, consultez la page de référence pour XamlLight.

Classe ElementCompositionPreview

ElementCompositionPreview est une classe statique qui fournit des fonctionnalités d’interopérabilité XAML et Visual Layer. Pour obtenir une vue d’ensemble de la couche visuelle et de ses fonctionnalités, consultez Couche visuelle. La classe ElementCompositionPreview fournit les méthodes suivantes :

  • GetElementVisual : Obtenir un visuel « document » utilisé pour afficher cet élément
  • SetElementChildVisual : définit un visuel « handin » comme dernier enfant de l’arborescence visuelle de cet élément. Ce visuel dessine en haut du reste de l’élément.
  • GetElementChildVisual : Récupérer l’ensemble visuel à l’aide de SetElementChildVisual
  • GetScrollViewerManipulationPropertySet : Obtenir un objet qui peut être utilisé pour créer des animations 60fps en fonction du décalage de défilement dans un ScrollViewer

Remarques sur ElementCompositionPreview.GetElementVisual

ElementCompositionPreview.GetElementVisual retourne un visuel « document » utilisé pour afficher l’uiElement donné. Les propriétés telles que Visual.Opacity, Visual.Offset et Visual.Size sont définies par l’infrastructure XAML en fonction de l’état de UIElement. Cela permet des techniques telles que les animations de repositionnement implicite (voir Recettes).

Notez que, étant donné que le décalage et la taille sont définis à la suite de la disposition de l’infrastructure XAML, les développeurs doivent être prudents lors de la modification ou de l’animation de ces propriétés. Les développeurs doivent uniquement modifier ou animer Offset lorsque le coin supérieur gauche de l’élément a la même position que celui de son parent dans la disposition. La taille ne doit généralement pas être modifiée, mais l’accès à la propriété peut être utile. Par exemple, les exemples Drop Shadow et Frosted Glass ci-dessous utilisent la taille d’un visuel de document comme entrée dans une animation.

En guise d’avertissement supplémentaire, les propriétés mises à jour du visuel de document ne sont pas reflétées dans l’uiElement correspondant. Par exemple, la définition de UIElement.Opacity sur 0.5 définit l’opacité du document correspondant sur 0,5. Toutefois, la définition de l’opacité du visuel de document sur 0,5 entraîne l’affichage du contenu à une opacité de 50 %, mais ne modifie pas la valeur de la propriété Opacity de l’uiElement correspondante.

Exemple d’animation offset

Incorrect

<Border>
      <Image x:Name="MyImage" Margin="5" />
</Border>
// Doesn’t work because Image has a margin!
ElementCompositionPreview.GetElementVisual(MyImage).StartAnimation("Offset", parallaxAnimation);

Correct

<Border>
    <Canvas Margin="5">
        <Image x:Name="MyImage" />
    </Canvas>
</Border>
// This works because the Canvas parent doesn’t generate a layout offset.
ElementCompositionPreview.GetElementVisual(MyImage).StartAnimation("Offset", parallaxAnimation);

Méthode ElementCompositionPreview.SetElementChildVisual

ElementCompositionPreview.SetElementChildVisual permet au développeur de fournir un visuel « handin » qui apparaîtra dans l’arborescence visuelle d’un élément. Cela permet aux développeurs de créer un « Île de composition » où le contenu visuel peut apparaître à l’intérieur d’une interface utilisateur XAML. Les développeurs doivent être prudents quant à l’utilisation de cette technique, car le contenu visuel n’aura pas la même accessibilité et la même expérience utilisateur garantit le contenu XAML. Par conséquent, il est généralement recommandé d’utiliser cette technique uniquement si nécessaire pour implémenter des effets personnalisés tels que ceux trouvés dans la section Recettes ci-dessous.

Méthodes GetAlphaMask

Image, TextBlock et Shape implémentent chacune une méthode appelée GetAlphaMask qui retourne un Objet CompositionBrush représentant une image de nuances de gris avec la forme de l’élément. Cette CompositionBrush peut servir d’entrée pour un DropShadow composition, de sorte que l’ombre peut refléter la forme de l’élément au lieu d’un rectangle. Cela permet aux pixels d’ombres parfaites basées sur les contours pour le texte, les images avec alpha et les formes. Consultez Drop Shadow ci-dessous pour obtenir un exemple de cette API.

Recettes

Repositionner l’animation

À l’aide des animations implicites de composition, un développeur peut animer automatiquement les modifications dans la disposition d’un élément par rapport à son parent. Par exemple, si vous modifiez la marge du bouton ci-dessous, elle s’anime automatiquement à sa nouvelle position de disposition.

Vue d’ensemble de l’implémentation

  1. Obtenir le visuel de document pour l’élément cible
  2. Créer un ImplicitAnimationCollection qui anime automatiquement les modifications dans la propriété Offset
  3. Associer l’objet ImplicitAnimationCollection au visuel de stockage
<Button x:Name="RepositionTarget" Content="Click Me" />
public MainPage()
{
    InitializeComponent();
    InitializeRepositionAnimation(RepositionTarget);
}

private void InitializeRepositionAnimation(UIElement repositionTarget)
{
    var targetVisual = ElementCompositionPreview.GetElementVisual(repositionTarget);
    Compositor compositor = targetVisual.Compositor;

    // Create an animation to animate targetVisual's Offset property to its final value
    var repositionAnimation = compositor.CreateVector3KeyFrameAnimation();
    repositionAnimation.Duration = TimeSpan.FromSeconds(0.66);
    repositionAnimation.Target = "Offset";
    repositionAnimation.InsertExpressionKeyFrame(1.0f, "this.FinalValue");

    // Run this animation when the Offset Property is changed
    var repositionAnimations = compositor.CreateImplicitAnimationCollection();
    repositionAnimations["Offset"] = repositionAnimation;

    targetVisual.ImplicitAnimations = repositionAnimations;
}

Ombre portée

Appliquez une ombre déroulante parfaite en pixels à un UIElement, par exemple un Ellipse contenant une image. Étant donné que l’ombre nécessite un SpriteVisual créé par l’application, nous devons créer un élément « host » qui contiendra le SpriteVisual à l’aide de ElementCompositionPreview.SetElementChildVisual.

Vue d’ensemble de l’implémentation

  1. Obtenir le visuel de document pour l’élément hôte
  2. Créer un dropShadow Windows.UI.Composition
  3. Configurer dropShadow pour obtenir sa forme à partir de l’élément cible via un masque
    • DropShadow est rectangulaire par défaut. Cela n’est donc pas nécessaire si la cible est rectangulaire
  4. Attacher l’ombre à un nouveau SpriteVisual et définir spriteVisual comme enfant de l’élément hôte
  5. Lier la taille du SpriteVisual à la taille de l’hôte à l’aide d’une expressionAnimation
<Grid Width="200" Height="200">
    <Canvas x:Name="ShadowHost" />
    <Ellipse x:Name="CircleImage">
        <Ellipse.Fill>
            <ImageBrush ImageSource="Assets/Images/2.jpg" Stretch="UniformToFill" />
        </Ellipse.Fill>
    </Ellipse>
</Grid>
public MainPage()
{
    InitializeComponent();
    InitializeDropShadow(ShadowHost, CircleImage);
}

private void InitializeDropShadow(UIElement shadowHost, Shape shadowTarget)
{
    Visual hostVisual = ElementCompositionPreview.GetElementVisual(shadowHost);
    Compositor compositor = hostVisual.Compositor;

    // Create a drop shadow
    var dropShadow = compositor.CreateDropShadow();
    dropShadow.Color = Color.FromArgb(255, 75, 75, 80);
    dropShadow.BlurRadius = 15.0f;
    dropShadow.Offset = new Vector3(2.5f, 2.5f, 0.0f);
    // Associate the shape of the shadow with the shape of the target element
    dropShadow.Mask = shadowTarget.GetAlphaMask();

    // Create a Visual to hold the shadow
    var shadowVisual = compositor.CreateSpriteVisual();
    shadowVisual.Shadow = dropShadow;

    // Add the shadow as a child of the host in the visual tree
   ElementCompositionPreview.SetElementChildVisual(shadowHost, shadowVisual);

    // Make sure size of shadow host and shadow visual always stay in sync
    var bindSizeAnimation = compositor.CreateExpressionAnimation("hostVisual.Size");
    bindSizeAnimation.SetReferenceParameter("hostVisual", hostVisual);

    shadowVisual.StartAnimation("Size", bindSizeAnimation);
}

Les deux listes suivantes montrent les équivalents C++/WinRT et C++/CX du code C# précédent à l’aide de la même structure XAML.

#include <winrt/Windows.UI.Composition.h>
#include <winrt/Windows.UI.Xaml.h>
#include <winrt/Windows.UI.Xaml.Hosting.h>
#include <winrt/Windows.UI.Xaml.Shapes.h>
...
MainPage()
{
    InitializeComponent();
    InitializeDropShadow(ShadowHost(), CircleImage());
}

int32_t MyProperty();
void MyProperty(int32_t value);

void InitializeDropShadow(Windows::UI::Xaml::UIElement const& shadowHost, Windows::UI::Xaml::Shapes::Shape const& shadowTarget)
{
    auto hostVisual{ Windows::UI::Xaml::Hosting::ElementCompositionPreview::GetElementVisual(shadowHost) };
    auto compositor{ hostVisual.Compositor() };

    // Create a drop shadow
    auto dropShadow{ compositor.CreateDropShadow() };
    dropShadow.Color(Windows::UI::ColorHelper::FromArgb(255, 75, 75, 80));
    dropShadow.BlurRadius(15.0f);
    dropShadow.Offset(Windows::Foundation::Numerics::float3{ 2.5f, 2.5f, 0.0f });
    // Associate the shape of the shadow with the shape of the target element
    dropShadow.Mask(shadowTarget.GetAlphaMask());

    // Create a Visual to hold the shadow
    auto shadowVisual = compositor.CreateSpriteVisual();
    shadowVisual.Shadow(dropShadow);

    // Add the shadow as a child of the host in the visual tree
    Windows::UI::Xaml::Hosting::ElementCompositionPreview::SetElementChildVisual(shadowHost, shadowVisual);

    // Make sure size of shadow host and shadow visual always stay in sync
    auto bindSizeAnimation{ compositor.CreateExpressionAnimation(L"hostVisual.Size") };
    bindSizeAnimation.SetReferenceParameter(L"hostVisual", hostVisual);

    shadowVisual.StartAnimation(L"Size", bindSizeAnimation);
}
#include "WindowsNumerics.h"

MainPage::MainPage()
{
    InitializeComponent();
    InitializeDropShadow(ShadowHost, CircleImage);
}

void MainPage::InitializeDropShadow(Windows::UI::Xaml::UIElement^ shadowHost, Windows::UI::Xaml::Shapes::Shape^ shadowTarget)
{
    auto hostVisual = Windows::UI::Xaml::Hosting::ElementCompositionPreview::GetElementVisual(shadowHost);
    auto compositor = hostVisual->Compositor;

    // Create a drop shadow
    auto dropShadow = compositor->CreateDropShadow();
    dropShadow->Color = Windows::UI::ColorHelper::FromArgb(255, 75, 75, 80);
    dropShadow->BlurRadius = 15.0f;
    dropShadow->Offset = Windows::Foundation::Numerics::float3(2.5f, 2.5f, 0.0f);
    // Associate the shape of the shadow with the shape of the target element
    dropShadow->Mask = shadowTarget->GetAlphaMask();

    // Create a Visual to hold the shadow
    auto shadowVisual = compositor->CreateSpriteVisual();
    shadowVisual->Shadow = dropShadow;

    // Add the shadow as a child of the host in the visual tree
    Windows::UI::Xaml::Hosting::ElementCompositionPreview::SetElementChildVisual(shadowHost, shadowVisual);

    // Make sure size of shadow host and shadow visual always stay in sync
    auto bindSizeAnimation = compositor->CreateExpressionAnimation("hostVisual.Size");
    bindSizeAnimation->SetReferenceParameter("hostVisual", hostVisual);

    shadowVisual->StartAnimation("Size", bindSizeAnimation);
}

Verre gelé

Créez un effet qui flout et teinte le contenu d’arrière-plan. Notez que les développeurs doivent installer le package NuGet Win2D pour utiliser des effets. Pour obtenir des instructions d’installation, consultez la page d’accueil Win2D.

Vue d’ensemble de l’implémentation

  1. Obtenir le visuel de document pour l’élément hôte
  2. Créer une arborescence d’effets flou à l’aide de Win2D et CompositionEffectSourceParameter
  3. Créer un CompositionEffectBrush basé sur l’arborescence d’effets
  4. Définissez l’entrée de CompositionEffectBrush sur un CompositionBackdropBrush, ce qui permet d’appliquer un effet au contenu derrière un SpriteVisual
  5. Définissez CompositionEffectBrush comme contenu d’un nouveau SpriteVisual et définissez spriteVisual comme enfant de l’élément hôte. Vous pouvez également utiliser un XamlCompositionBrushBase.
  6. Lier la taille du SpriteVisual à la taille de l’hôte à l’aide d’une expressionAnimation
<Grid Width="300" Height="300" Grid.Column="1">
    <Image
        Source="Assets/Images/2.jpg"
        Width="200"
        Height="200" />
    <Canvas
        x:Name="GlassHost"
        Width="150"
        Height="300"
        HorizontalAlignment="Right" />
</Grid>
public MainPage()
{
    InitializeComponent();
    InitializeFrostedGlass(GlassHost);
}

private void InitializeFrostedGlass(UIElement glassHost)
{
    Visual hostVisual = ElementCompositionPreview.GetElementVisual(glassHost);
    Compositor compositor = hostVisual.Compositor;

    // Create a glass effect, requires Win2D NuGet package
    var glassEffect = new GaussianBlurEffect
    { 
        BlurAmount = 15.0f,
        BorderMode = EffectBorderMode.Hard,
        Source = new ArithmeticCompositeEffect
        {
            MultiplyAmount = 0,
            Source1Amount = 0.5f,
            Source2Amount = 0.5f,
            Source1 = new CompositionEffectSourceParameter("backdropBrush"),
            Source2 = new ColorSourceEffect
            {
                Color = Color.FromArgb(255, 245, 245, 245)
            }
        }
    };

    //  Create an instance of the effect and set its source to a CompositionBackdropBrush
    var effectFactory = compositor.CreateEffectFactory(glassEffect);
    var backdropBrush = compositor.CreateBackdropBrush();
    var effectBrush = effectFactory.CreateBrush();

    effectBrush.SetSourceParameter("backdropBrush", backdropBrush);

    // Create a Visual to contain the frosted glass effect
    var glassVisual = compositor.CreateSpriteVisual();
    glassVisual.Brush = effectBrush;

    // Add the blur as a child of the host in the visual tree
    ElementCompositionPreview.SetElementChildVisual(glassHost, glassVisual);

    // Make sure size of glass host and glass visual always stay in sync
    var bindSizeAnimation = compositor.CreateExpressionAnimation("hostVisual.Size");
    bindSizeAnimation.SetReferenceParameter("hostVisual", hostVisual);

    glassVisual.StartAnimation("Size", bindSizeAnimation);
}

Ressources complémentaires