Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
Composition Visuals bilden die visuelle Baumstruktur, die alle anderen Features der Microsoft.UI.Composition-API verwenden und darauf aufbauen. Mit der API können Entwickler ein oder mehrere visuelle Objekte definieren und erstellen, die jeweils einen einzelnen Knoten in einer visuellen Struktur darstellen.
Visuelle Elemente
Es gibt mehrere visuelle Typen, aus denen die visuelle Struktur besteht, sowie eine Basispinselklasse mit mehreren Unterklassen, die sich auf den Inhalt eines visuellen Elements auswirken:
- Visual – Basisobjekt, der Großteil der Eigenschaften sind hier und von den anderen visuellen Objekten geerbt.
-
ContainerVisual – abgeleitet von Visual und fügt die Möglichkeit zum Erstellen von untergeordneten Elementen hinzu.
- SpriteVisual – wird von ContainerVisual abgeleitet. Verfügt über die Möglichkeit, einen Pinsel zuzuordnen, sodass das Visuelle Pixel, einschließlich Bildern, Effekten oder einer Volltonfarbe, rendern kann.
- LayerVisual – abgeleitet von ContainerVisual. Kinder des Visuals werden in einer einzigen Ebene abgeflacht.
- ShapeVisual – abgeleitet von ContainerVisual. Ein visueller Strukturknoten, der der Stamm einer CompositionShape ist.
- RedirectVisual – abgeleitet von ContainerVisual. Das Visuelle ruft seinen Inhalt aus einem anderen visuellen Element ab.
- SceneVisual – abgeleitet von ContainerVisual. Eine Container-Visualisierung für die Knoten einer 3D-Szene.
Sie können Inhalte und Effekte auf SpriteVisuals mithilfe von CompositionBrush und deren Unterklassen anwenden, einschließlich compositionColorBrush, CompositionSurfaceBrush und CompositionEffectBrush. Weitere Informationen zu Pinsel finden Sie unter CompositionBrush Overview.
Das CompositionVisual-Beispiel
Hier sehen wir uns einen WinUI 3-Beispielcode an, der die drei verschiedenen zuvor aufgeführten visuellen Typen veranschaulicht. Dieses Beispiel deckt zwar keine Konzepte wie Animationen oder komplexere Effekte ab, enthält aber die Bausteine, die alle diese Systeme verwenden. (Der vollständige Beispielcode wird am Ende dieses Artikels aufgeführt.)
Im Beispiel handelt es sich um eine Reihe von Volltonfarbenen Quadraten, auf die geklickt und die über den Bildschirm gezogen werden können. Wenn auf ein Quadrat geklickt wird, kommt es nach vorne, dreht sich um 45 Grad und wird undurchsichtig, wenn es gezogen wird.
Dies zeigt eine Reihe grundlegender Konzepte für die Arbeit mit der API, einschließlich:
- Erstellen eines Kompositors
- Erstellen eines SpriteVisuals mithilfe eines CompositionColorBrush
- Beschneiden des visuellen Elements
- Drehen des visuellen Elements
- Festlegen der Deckkraft
- Ändern der Position des visuellen Elements in der Auflistung.
Erstellen eines Kompositors
Das Erstellen eines Kompositors und das Speichern in einer Variablen für die Verwendung als Factory ist eine einfache Aufgabe. In einer WinUI-App rufen Sie in der Regel den Kompositor aus einem XAML-Element ab, das bereits mit der visuellen Struktur verbunden ist:
Compositor compositor = ElementCompositionPreview.GetElementVisual(MyHost).Compositor;
Wenn Sie einen Kompositor benötigen und kein UIElement verfügbar sind, können Sie es stattdessen verwenden CompositionTarget.GetCompositorForCurrentThread() .
Erstellen eines SpriteVisual- und ColorBrush-Elements
Mit dem Kompositor ist es einfach, Objekte zu erstellen, wann immer Sie sie benötigen, wie zum Beispiel ein SpriteVisual und ein CompositionColorBrush:
var visual = _compositor.CreateSpriteVisual();
visual.Brush = _compositor.CreateColorBrush(Color.FromArgb(0xFF, 0xFF, 0xFF, 0xFF));
Dies ist zwar nur ein paar Codezeilen, veranschaulicht aber ein leistungsfähiges Konzept: SpriteVisual-Objekte sind das Herzstück des Effektsystems. Das SpriteVisual ermöglicht eine hohe Flexibilität und Interaktion bei der Farb-, Bild- und Effekterstellung. SpriteVisual ist ein einzelner visueller Typ, der ein 2D-Rechteck mit einem Pinsel füllen kann, in diesem Fall eine Volltonfarbe.
Beschneiden eines visuellen Elements
Der Kompositor kann auch zum Erstellen von Clips für eine Visualisierung verwendet werden. Im Folgenden finden Sie ein Beispiel für die Verwendung von InsetClip, um jede Seite des Visuals zu kürzen.
var clip = _compositor.CreateInsetClip();
clip.LeftInset = 1.0f;
clip.RightInset = 1.0f;
clip.TopInset = 1.0f;
clip.BottomInset = 1.0f;
_currentVisual.Clip = clip;
Wie andere Objekte in der API kann InsetClip Animationen auf seine Eigenschaften anwenden.
Drehen eines Clips
Ein Visual kann durch eine Drehung transformiert werden. Beachten Sie, dass RotationAngle sowohl Bogenmaß als auch Grad unterstützt. Standardmäßig wird Bogenmaß verwendet, aber es ist einfach, Grad anzugeben, wie im folgenden Codeausschnitt gezeigt:
child.RotationAngleInDegrees = 45.0f;
Drehung ist nur ein Beispiel für eine Reihe von Transformationskomponenten, die von der API bereitgestellt werden, um diese Aufgaben zu vereinfachen. Andere umfassen Offset, Scale, Orientation, RotationAxis und 4x4 TransformMatrix.
Festlegen der Deckkraft
Das Festlegen der Deckkraft eines visuellen Elements ist ein einfacher Vorgang mit einem Float-Wert. In der Stichprobe beginnen beispielsweise alle Quadrate bei 0,8 Deckkraft:
visual.Opacity = 0.8f;
Wie die Drehung kann die Opazität animiert werden.
Ändern der Position des visuellen Elements in der Auflistung
Die Kompositions-API ermöglicht es, die Position eines visuellen Elements in einer VisualCollection auf verschiedene Arten zu ändern. Es kann über einem anderen Visual mit InsertAbove platziert werden, darunter mit InsertBelow, nach oben mit InsertAtTop oder unten mit InsertAtBottom verschoben werden.
Im Beispiel wird ein visuelles Element, das angeklickt wurde, nach oben sortiert.
parent.Children.InsertAtTop(_currentVisual);
Vollständiges Beispiel
Im vollständigen WinUI-Beispiel werden alle oben genannten Konzepte zusammen verwendet, um einen einfachen Baum aus Visual-Objekten zu konstruieren und zu durchlaufen, um die Deckkraft ohne benutzerdefiniertes DirectX-Rendering zu modifizieren. Das Beispiel verwendet eine WinUI Grid für Zeigereingaben und hostet den Kompositionsbaum mit ElementCompositionPreview.
<Page
x:Class="CompositionVisualSample.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid
x:Name="MyHost"
Background="Transparent"
PointerPressed="OnPointerPressed"
PointerMoved="OnPointerMoved"
PointerReleased="OnPointerReleased" />
</Page>
using System;
using System.Numerics;
using Microsoft.UI.Composition;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Hosting;
using Microsoft.UI.Xaml.Input;
using Windows.Foundation;
using Windows.UI;
namespace CompositionVisualSample
{
public sealed partial class MainPage : Page
{
private readonly Random _random = new();
private Compositor _compositor;
private ContainerVisual _root;
private ContainerVisual _currentVisual;
private Vector2 _offsetBias;
private bool _dragging;
public MainPage()
{
InitializeComponent();
Loaded += OnLoaded;
}
private void OnLoaded(object sender, RoutedEventArgs e)
{
if (_root != null)
{
return;
}
_compositor = ElementCompositionPreview.GetElementVisual(MyHost).Compositor;
_root = _compositor.CreateContainerVisual();
ElementCompositionPreview.SetElementChildVisual(MyHost, _root);
for (int index = 0; index < 20; index++)
{
_root.Children.InsertAtTop(CreateChildElement());
}
}
private ContainerVisual CreateChildElement()
{
var element = _compositor.CreateContainerVisual();
element.Size = new Vector2(100.0f, 100.0f);
var maxX = (float)Math.Max(MyHost.ActualWidth - element.Size.X, 0.0);
var maxY = (float)Math.Max(MyHost.ActualHeight - element.Size.Y, 0.0);
element.Offset = new Vector3(
(float)(_random.NextDouble() * maxX),
(float)(_random.NextDouble() * maxY),
0.0f);
var outer = _compositor.CreateSpriteVisual();
outer.Size = new Vector2(100.0f, 100.0f);
outer.Brush = _compositor.CreateColorBrush(Colors.White);
element.Children.InsertAtTop(outer);
var inner = _compositor.CreateSpriteVisual();
inner.Offset = new Vector3(3.0f, 3.0f, 0.0f);
inner.Size = new Vector2(94.0f, 94.0f);
byte red = (byte)(0xFF * (0.2f + (_random.NextDouble() / 0.8f)));
byte green = (byte)(0xFF * (0.2f + (_random.NextDouble() / 0.8f)));
byte blue = (byte)(0xFF * (0.2f + (_random.NextDouble() / 0.8f)));
inner.Brush = _compositor.CreateColorBrush(Color.FromArgb(0xFF, red, green, blue));
outer.Children.InsertAtTop(inner);
element.Opacity = 0.8f;
return element;
}
private void OnPointerPressed(object sender, PointerRoutedEventArgs e)
{
Point position = e.GetCurrentPoint(MyHost).Position;
_currentVisual = null;
foreach (var child in _root.Children)
{
Vector3 offset = child.Offset;
Vector2 size = child.Size;
if ((position.X >= offset.X) &&
(position.X < offset.X + size.X) &&
(position.Y >= offset.Y) &&
(position.Y < offset.Y + size.Y))
{
_currentVisual = child as ContainerVisual;
_offsetBias = new Vector2(
(float)(offset.X - position.X),
(float)(offset.Y - position.Y));
}
}
if (_currentVisual != null)
{
ContainerVisual parent = (ContainerVisual)_currentVisual.Parent;
parent.Children.Remove(_currentVisual);
parent.Children.InsertAtTop(_currentVisual);
}
}
private void OnPointerMoved(object sender, PointerRoutedEventArgs e)
{
if (_currentVisual == null)
{
return;
}
if (!_dragging)
{
_currentVisual.Opacity = 1.0f;
foreach (var child in _currentVisual.Children)
{
child.RotationAngleInDegrees = 45.0f;
child.CenterPoint = new Vector3(_currentVisual.Size.X / 2, _currentVisual.Size.Y / 2, 0.0f);
break;
}
var clip = _compositor.CreateInsetClip();
clip.LeftInset = 1.0f;
clip.RightInset = 1.0f;
clip.TopInset = 1.0f;
clip.BottomInset = 1.0f;
_currentVisual.Clip = clip;
_dragging = true;
}
Point position = e.GetCurrentPoint(MyHost).Position;
_currentVisual.Offset = new Vector3(
(float)(position.X + _offsetBias.X),
(float)(position.Y + _offsetBias.Y),
0.0f);
}
private void OnPointerReleased(object sender, PointerRoutedEventArgs e)
{
if (_currentVisual == null)
{
return;
}
if (_dragging)
{
foreach (var child in _currentVisual.Children)
{
child.RotationAngle = 0.0f;
child.CenterPoint = new Vector3(0.0f, 0.0f, 0.0f);
break;
}
_currentVisual.Opacity = 0.8f;
_currentVisual.Clip = null;
_dragging = false;
}
_currentVisual = null;
}
}
}
Wenn Sie ein Kompositor-Objekt initialisieren müssen, bevor Sie über ein XAML-Hostelement verfügen, verwenden Sie CompositionTarget.GetCompositorForCurrentThread() und fügen Sie die visuellen Elemente dann an Ihre Benutzeroberfläche an, wenn ein Hostelement verfügbar wird.
Windows developer