Dela via


Använda det visuella lagret med WinUI XAML

De flesta WinUI- och Windows App SDK-appar som använder visualiseringslagerfunktioner använder XAML för att definiera huvudinnehållet i användargränssnittet. WinUI innehåller funktioner i XAML-ramverket och det visuella lagret som gör det enklare att kombinera dessa två tekniker för att skapa fantastiska användarupplevelser. XAML- och Visual Layer-interopfunktioner kan användas för att skapa avancerade animeringar och effekter som inte är tillgängliga enbart med XAML-API:er. Detta omfattar:

  • Penseleffekter som oskärpa och frostat glas
  • Dynamiska ljuseffekter
  • Animeringar som styrs av rullning och parallax
  • Automatiska layoutanimeringar
  • Pixelperfekta skuggeffekter

Dessa effekter och animeringar kan tillämpas på befintligt XAML-innehåll, så du behöver inte dramatiskt omstrukturera din WinUI-app för att dra nytta av funktionerna. Layoutanimationer, skuggor och oskärpa visas i avsnittet Recept nedan. Ett kodexempel som implementerar parallax finns i exemplet ParallaxingListItems. WindowsCompositionSamples-lagringsplatsen har också flera andra exempel för att implementera animeringar, skuggor och effekter.

Klassen "XamlCompositionBrushBase"

Microsoft.UI.Xaml.Media.XamlCompositionBrushBase tillhandahåller en basklass för XAML-penslar som målar ett område med en CompositionBrush. Detta kan användas för att enkelt tillämpa kompositionseffekter som oskärpa eller frostat glas på XAML-gränssnittselement.

Mer information om hur du använder penslar med XAML-användargränssnitt finns i avsnittet Penslar .

Kodexempel finns på referenssidan för XamlCompositionBrushBase.

XamlLight-klassen

Microsoft.UI.Xaml.Media.XamlLight tillhandahåller en basklass för XAML-ljuseffekter som dynamiskt tänder ett område med ett CompositionLight.

Mer information om hur du använder lampor finns i avsnittet Belysning , inklusive belysning av XAML-gränssnittselement.

Kodexempel finns på referenssidan för XamlLight.

Arbeta med WinUI XAML

ElementCompositionPreview är en statisk klass som tillhandahåller XAML- och Visual Layer-interop-funktioner. En översikt över det visuella lagret och dess funktioner finns i Visual Layer. Klassen ElementCompositionPreview innehåller följande WinUI-interopmetoder:

  • GetElementVisual: Hämta en Visual som används för att återge det här elementet
  • SetElementChildVisual: Anger ett visuellt "handin"-objekt som det sista barn i det här elementets visuella träd. Det här visuella objektet kommer att ritas ovanpå resten av elementet.
  • GetElementChildVisual: Hämta den visuella uppsättningen med SetElementChildVisual
  • GetScrollViewerManipulationPropertySet: Hämta ett objekt som kan användas för att skapa 60fps-animeringar baserat på rullningsförskjutning i en ScrollViewer

GetElementVisual

ElementCompositionPreview.GetElementVisual returnerar ett visuellt referensobjekt som används för att rendera det angivna UIElementet. Egenskaper som Visual.Opacity, Visual.Offset och Visual.Size anges av XAML-ramverket baserat på tillståndet för UIElement. Detta möjliggör tekniker som implicita ompositioneringsanimationer (se Recept).

Observera att eftersom förskjutning och storlek har angetts som ett resultat av XAML-ramverkslayouten bör utvecklare vara försiktiga när de ändrar eller animerar dessa egenskaper. Utvecklare bör bara ändra eller animera offset när elementets övre vänstra hörn har samma position som dess överordnade i layouten. Storleken bör vanligtvis inte ändras, men det kan vara användbart att få tillgång till egenskapen. Exemplen Drop Shadow och Frosted Glass nedan använder Storlek på en handoutvisualisering som inmatning till en animering.

Som en ytterligare förbehåll återspeglas inte uppdaterade egenskaper för visualiseringsobjektet i motsvarande UIElement. Om du till exempel sätter UIElement.Opacity till 0,5 kommer det att ställa in den motsvarande visuella handoutens opacitet till 0,5. Om du ställer in handoutens Visuals opacitet till 0,5 kommer innehållet att visas med 50% opacitet, men det ändrar inte UIElement-objektets egenskapsvärde för Opacity.

Exempel på offset-animering

Felaktig

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

Korrekt

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

SetElementChildVisual

ElementCompositionPreview.SetElementChildVisual gör att utvecklaren kan tillhandahålla ett "handin"-visuellt objekt som visas som en del av ett elements visuella träd. På så sätt kan utvecklare skapa en "Sammansättningsö" där visuellt innehåll kan visas i ett XAML-användargränssnitt. Utvecklare bör vara försiktiga med att använda den här tekniken eftersom visuellt innehåll inte har samma tillgänglighets- och användarupplevelsegarantier för XAML-innehåll. Därför rekommenderar vi vanligtvis att den här tekniken endast används när det behövs för att implementera anpassade effekter, till exempel de som finns i avsnittet Recept nedan.

GetAlphaMask-metoder

Bild, TextBlock och Form implementerar var och en en metod med namnet GetAlphaMask som returnerar en CompositionBrush som representerar en gråskalebild med elementets form. Den här CompositionBrush kan fungera som en indata för en Composition DropShadow, så skuggan kan återspegla formen på elementet i stället för en rektangel. Detta möjliggör pixelperfekta, konturbaserade skuggor för text, bilder med alfa och former. Se Skuggning nedan för ett exempel på det här API:et.

Recept

Ompositionera animering

Med hjälp av implicita animeringar för sammansättning kan en utvecklare automatiskt animera ändringar i ett elements layout i förhållande till dess överordnade. Om du till exempel ändrar knappens marginal nedan animeras den automatiskt till sin nya layoutposition.

Översikt över implementering

  1. Hämta Visual-materialet för målelementet
  2. Skapa en ImplicitAnimationCollection som automatiskt animerar ändringar i egenskapen Offset
  3. Associera ImplicitAnimationCollection med det visuella objektet som backas upp
<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;
}

Skugga

Använd en pixel-perfekt dropskugga på ett UIElement, till exempel en Ellips som innehåller en bild. Eftersom skuggan kräver en SpriteVisual som har skapats av appen måste vi skapa ett "värdelement" för att innehålla SpriteVisual med hjälp av ElementCompositionPreview.SetElementChildVisual.

Översikt över implementering

  1. Hämta handouten Visual för valuelementet
  2. Skapa en Microsoft.UI.Composition DropShadow
  3. Konfigurera DropShadow för att hämta formen från målelementet via en mask
    • DropShadow är rektangulär som standard, så detta är inte nödvändigt om målet är rektangulärt
  4. Koppla skugga till en ny SpriteVisual och ange SpriteVisual som underordnad hostingelementet
  5. Binda storleken på SpriteVisual till värdens storlek med hjälp av en 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);
}

I följande lista visas C++/WinRT-motsvarigheten till den tidigare C#-koden med samma XAML-struktur.

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

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

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

    // Create a drop shadow
    auto dropShadow{ compositor.CreateDropShadow() };
    dropShadow.Color(Microsoft::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
    Microsoft::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);
}

Frostat glas

Skapa en effekt som suddar ut och tonar bakgrundsinnehåll. Observera att utvecklare måste installera Win2D NuGet-paketet för att kunna använda effekter. Se Win2D-startsidan för installationsinstruktioner.

Översikt över implementering

  1. Hämta handout Visual för värdeelementet
  2. Skapa ett oskärpeffektträd med Win2D och CompositionEffectSourceParameter
  3. Skapa en CompositionEffectBrush baserat på effektträdet
  4. Ange indata för CompositionEffectBrush till en CompositionBackdropBrush, vilket gör att en effekt kan tillämpas på innehållet bakom en SpriteVisual
  5. Ange CompositionEffectBrush som innehållet i en ny SpriteVisual och ange SpriteVisual som underordnad till värdelementet. Du kan alternativt använda en XamlCompositionBrushBase.
  6. Binda storleken på SpriteVisual till värdens storlek med hjälp av en 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);
}

Ytterligare resurser