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.
Erstellen Sie UWP-Apps (Universelle Windows-Plattform) mit reibungslosen Animationen, hoher Bildfrequenz und leistungsstarker Medienaufnahme und -wiedergabe.
Animationen sanft gestalten
Ein wichtiger Aspekt von UWP-Apps ist eine reibungslose Interaktion. Dazu gehören Fingereingabemanipulationen, die an Ihrem Finger haften bleiben, reibungslose Übergänge und Animationen sowie kleine Bewegungen, die Rückmeldungen liefern. Im XAML-Framework gibt es einen Thread namens Kompositionsthread, der der Komposition und Animation der visuellen Elemente einer App zugeordnet ist. Da der Kompositionsthread vom UI-Thread (dem Thread, der Framework- und Entwicklercode ausführt) getrennt ist, können Apps unabhängig von komplizierten Layoutdurchläufen oder erweiterten Berechnungen eine konsistente Framerate und reibungslose Animationen erzielen. In diesem Abschnitt wird gezeigt, wie Sie den Kompositionsthread verwenden, um die Animationen einer App butterweich zu halten. Weitere Informationen zu Animationen finden Sie in der Übersicht über Animationen. Weitere Informationen zum Erhöhen der Reaktionsfähigkeit einer App bei intensiven Berechnungen finden Sie unter "Reaktionsfähigkeit des UI-Threads beibehalten".
Verwenden Sie unabhängige statt abhängige Animationen
Unabhängige Animationen können zum Zeitpunkt der Erstellung von Anfang bis Ende berechnet werden, da sich Änderungen an der animierten Eigenschaft nicht auf die restlichen Objekte in einer Szene auswirken. Unabhängige Animationen können daher im Kompositionsthread anstelle des UI-Threads ausgeführt werden. Dadurch wird sichergestellt, dass sie weiterhin reibungslos funktionieren, da der Kompositionsthread in gleichmäßigem Rhythmus aktualisiert wird.
Alle diese Arten von Animationen sind garantiert unabhängig:
Objektanimationen mithilfe von Keyframes
Animationen mit Nulldauer
Animationen für die Eigenschaften Canvas.Left und Canvas.Top
Animationen für die eigenschaft UIElement.Opacity
Animationen für Eigenschaften vom Typ Brush bei der Zielbestimmung für die SolidColorBrush.Color--Untereigenschaft
Animationen für die folgenden UIElement- Eigenschaften bei der Zielbestimmung von Untereigenschaften dieser Rückgabewerttypen:
Abhängige Animationen wirken sich auf das Layout aus, was daher ohne zusätzliche Eingaben aus dem UI-Thread nicht berechnet werden kann. Abhängige Animationen umfassen Änderungen an Eigenschaften wie Breite und Höhe. Abhängige Animationen werden standardmäßig nicht ausgeführt und erfordern eine Zustimmung des App-Entwicklers. Wenn dies aktiviert ist, werden sie reibungslos ausgeführt, wenn der UI-Thread nicht blockiert bleibt, aber sie beginnen zu stuttern, wenn das Framework oder die App viele andere Aufgaben im UI-Thread ausführt.
Fast alle Animationen im XAML-Framework sind standardmäßig unabhängig, es gibt jedoch einige Aktionen, die Sie ausführen können, um diese Optimierung zu deaktivieren. Seien Sie besonders vorsichtig bei diesen Szenarien:
- Festlegen der EnableDependentAnimation-Eigenschaft, damit eine abhängige Animation im UI-Thread ausgeführt werden kann. Konvertieren Sie diese Animationen in eine unabhängige Version. Animieren Sie beispielsweise ScaleTransform.ScaleX und ScaleTransform.ScaleY anstelle der Breite und Höhe eines Objekts. Scheuen Sie sich nicht, Objekte wie Bilder und Text zu skalieren. Das Framework wendet bilineare Skalierung nur während der Animation von ScaleTransform an. Das Bild/der Text wird in der endgültigen Größe neurasterisiert, um sicherzustellen, dass es immer klar ist.
- Erstellen von Aktualisierungen pro Frame, die effektiv abhängige Animationen sind. Ein Beispiel hierfür ist das Anwenden von Transformationen im Handler des CompositonTarget.Rendering-Ereignisses.
- Ausführen einer animation, die in einem Element als unabhängig betrachtet wird, wobei die CacheMode-eigenschaft auf BitmapCache-festgelegt ist. Dies gilt als abhängig, da der Cache für jeden Frame neu gerastert werden muss.
Animieren Sie ein WebView- oder MediaPlayerElement nicht.
Webinhalte innerhalb eines WebView--Steuerelements werden nicht direkt vom XAML-Framework gerendert und erfordern zusätzliche Arbeit, um in die restliche Szene integriert zu werden. Diese zusätzliche Arbeit sammelt sich beim Animieren des Steuerelements auf dem Bildschirm an und kann möglicherweise Synchronisierungsprobleme auftreten lassen (z. B. der HTML-Inhalt wird möglicherweise nicht synchron mit dem Rest des XAML-Inhalts auf der Seite). Wenn Sie ein WebView- Steuerelement animieren müssen, tauschen Sie es mit einem WebViewBrush- für die Dauer der Animation aus.
Das Animieren eines MediaPlayerElement ist ebenso eine schlechte Idee. Über die Leistungseinbuße hinaus kann es zu Zerreißen oder anderen Artefakten in den wiedergegebenen Videoinhalten führen.
Hinweis Die Empfehlungen in diesem Artikel für MediaPlayerElement gelten auch für MediaElement. MediaPlayerElement ist nur in Windows 10, Version 1607, verfügbar. Wenn Sie also eine App für eine frühere Version von Windows erstellen, müssen Sie MediaElement verwenden.
Sparsames Verwenden von endlosen Animationen
Die meisten Animationen werden für einen bestimmten Zeitraum ausgeführt, aber durch Festlegen der Timeline.Duration-Eigenschaft auf Forever kann eine Animation unbegrenzt ausgeführt werden. Es wird empfohlen, die Verwendung unendlicher Animationen zu minimieren, da sie kontinuierlich CPU-Ressourcen verbrauchen und verhindern können, dass die CPU in einen Niedrigstrom- oder Leerlaufzustand wechselt, was zu einer schnelleren Entladung führt.
Das Hinzufügen eines Handlers für CompositionTarget.Rendering ist vergleichbar mit dem Ausführen einer endlosen Animation. Normalerweise ist der UI-Thread nur aktiv, wenn es Arbeit gibt, aber das Hinzufügen eines Handlers für dieses Ereignis erzwingt, dass es bei jedem Frame läuft. Entfernen Sie den Handler, wenn keine Arbeit erforderlich ist, und registrieren Sie ihn erneut, wenn er erneut benötigt wird.
Verwenden Sie die Animationsbibliothek
Der Windows.UI.Xaml.Media.Animation Namespace enthält eine Bibliothek mit leistungsstarken, reibungslosen Animationen, deren Erscheinungsbild und Gefühl mit anderen Windows-Animationen übereinstimmt. Die relevanten Klassen haben "Thema" in ihrem Namen und werden in Animationsübersichtbeschrieben. Diese Bibliothek unterstützt viele gängige Animationsszenarien, z. B. das Animieren der ersten Ansicht der App und das Erstellen von Zustands- und Inhaltsübergängen. Wir empfehlen, diese Animationsbibliothek so oft wie möglich zu verwenden, um die Leistung und Konsistenz für die UWP-Benutzeroberfläche zu erhöhen.
Anmerkung Die Animationsbibliothek kann nicht alle möglichen Eigenschaften animieren. Xaml-Szenarien, in denen die Animationsbibliothek nicht angewendet wird, finden Sie unter Storyboardanimationen.
CompositeTransform3D-Eigenschaften unabhängig animieren
Sie können jede Eigenschaft eines CompositeTransform3D- unabhängig animieren, sodass Sie nur die benötigten Animationen anwenden. Beispiele und weitere Informationen finden Sie unter UIElement.Transform3D. Weitere Informationen zum Animieren von Transformationen finden Sie unter Storyboardanimationen und Keyframe- und Beschleunigungsfunktionsanimationen.
Optimieren von Medienressourcen
Audio, Video und Bilder sind überzeugende Formen von Inhalten, die von den meisten Apps verwendet werden. Da die Medienaufnahmeraten steigen und Inhalte von der Standarddefinition in high definition verschoben werden, erhöht sich die Menge der Ressourcen, die zum Speichern, Decodieren und Wiedergeben dieser Inhalte erforderlich sind. Das XAML-Framework baut auf den neuesten Features auf, die den UWP-Medienmodulen hinzugefügt wurden, damit Apps diese Verbesserungen kostenlos erhalten. Hier erläutern wir einige zusätzliche Tricks, mit denen Sie das Beste aus den Medien in Ihrer UWP-App herausholen können.
Freigabe der Medienströme
Mediendateien sind einige der am häufigsten verwendeten und kostspieligsten Ressourcen, die in der Regel von Apps verwendet werden. Da Mediendateiressourcen die Größe des Speicherbedarfs Ihrer App erheblich erhöhen können, müssen Sie daran denken, das Handle für Medien freizugeben, sobald die App sie nicht mehr benötigt.
Wenn Ihre App z. B. mit einem RandomAccessStream- oder einem IInputStream--Objekt arbeitet, achten Sie darauf, die Close-Methode für das Objekt aufzurufen, wenn die App die Verwendung abgeschlossen hat, um das zugrunde liegende Objekt freizugeben.
Nach Möglichkeit Videowiedergabe im Vollbildmodus anzeigen
Verwenden Sie in UWP-Apps immer die IsFullWindow-Eigenschaft für das MediaPlayerElement-, um das Rendering im Vollbildmodus zu aktivieren und zu deaktivieren. Dadurch wird sichergestellt, dass Optimierungen auf Systemebene während der Medienwiedergabe verwendet werden.
Das XAML-Framework kann die Anzeige von Videoinhalten optimieren, wenn es das einzige Element ist, das gerendert wird, was zu einer Erfahrung führt, die weniger Leistung verwendet und höhere Frameraten liefert. Legen Sie für die effizienteste Medienwiedergabe die Größe eines MediaPlayerElements auf die Breite und Höhe des Bildschirms fest und zeigen keine anderen XAML-Elemente an.
Es gibt legitime Gründe, XAML-Elemente auf einem MediaPlayerElement- zu überlagern, das die volle Breite und Höhe des Bildschirms einnimmt, z. B. Untertitel oder vorübergehende Transportsteuerelemente. Stellen Sie sicher, dass diese Elemente (festgelegt auf Visibility="Collapsed"
) ausgeblendet werden, wenn sie nicht benötigt werden, um die Medienwiedergabe zurück in den effizientesten Zustand zu setzen.
Bildschirm deaktivieren und Energie sparen
Um zu verhindern, dass die Anzeige deaktiviert wird, wenn eine Benutzeraktion nicht mehr erkannt wird, z. B. wenn eine App Video wiedergibt, können Sie DisplayRequest.RequestActiveaufrufen.
Um Energie und Akkulaufzeit zu sparen, sollten Sie DisplayRequest.RequestRelease aufrufen, um die Anzeigeanforderung freizugeben, sobald sie nicht mehr benötigt wird.
Hier sind einige Situationen, in denen Sie die Anzeigeanforderung freigeben sollten:
- Die Videowiedergabe wird angehalten, z. B. durch Benutzeraktion, Pufferung oder Anpassung aufgrund begrenzter Bandbreite.
- Die Wiedergabe wird beendet. Beispielsweise wird die Wiedergabe des Videos abgeschlossen, oder die Präsentation ist vorbei.
- Ein Wiedergabefehler ist aufgetreten. Beispielsweise netzwerkkonnektivitätsprobleme oder eine beschädigte Datei.
Platzieren anderer Elemente an der Seite des eingebetteten Videos
Häufig bieten Apps eine eingebettete Ansicht, in der Videos auf einer Seite wiedergegeben werden. Nun haben Sie offensichtlich die Vollbildoptimierung verloren, da das MediaPlayerElement
Zeichnen Sie KEINE XAML-Elemente über dem Video, wenn sie sich im eingebetteten Modus befinden. Wenn Sie dies tun, ist das Framework gezwungen, etwas mehr Arbeit zu leisten, um die Szene zusammenzustellen. Das Platzieren von Transportsteuerelementen unter einem eingebetteten Medienelement anstelle des Videos ist ein gutes Beispiel für die Optimierung für diese Situation. In diesem Bild zeigt der rote Balken eine Reihe von Transportsteuerelementen an (Wiedergabe, Anhalten, Beenden usw.).
Platzieren Sie diese Steuerelemente nicht auf Medien, die nicht im Vollbildmodus angezeigt werden. Platzieren Sie die Transportsteuerung stattdessen außerhalb des Bereichs, in dem die Medien gerendert werden. In der nächsten Abbildung werden die Steuerelemente unterhalb der Medien platziert.
Das Festlegen der Quelle für ein MediaPlayerElement verzögern
Medienmodule sind teure Objekte, und das XAML-Framework verzögert das Laden von DLL-Dateien und das Erstellen großer Objekte so lange wie möglich. Die MediaPlayerElement- muss diese Arbeit erledigen, nachdem die Quelle über die Eigenschaft Source festgelegt wurde. Wenn Sie dies einstellen, sobald der Benutzer wirklich bereit ist, Medien wiederzugeben, wird die Mehrheit der Kosten, die mit dem MediaPlayerElement verbunden sind, so lange wie möglich verzögert.
Festlegen von "MediaPlayerElement.PosterSource"
Durch das Einstellen von MediaPlayerElement.PosterSource kann XAML einige GPU-Ressourcen freigeben, die ansonsten genutzt worden wären. Diese API ermöglicht es einer App, so wenig Arbeitsspeicher wie möglich zu verwenden.
Medien-Scrubbing verbessern
Das Scrubbing ist für Medienplattformen immer eine große Herausforderung, um wirklich benutzerfreundlich zu sein. Im Allgemeinen erreichen Menschen dies, indem sie den Wert eines Schiebereglers ändern. Hier sind ein paar Tipps, wie Sie dies so effizient wie möglich gestalten:
- Aktualisieren Sie den Wert von Slider- basierend auf einem Timer, der die Position auf dem MediaPlayerElement.MediaPlayer-abfragt. Stellen Sie sicher, dass Sie eine angemessene Aktualisierungshäufigkeit für Ihren Timer verwenden. Die Eigenschaft Position wird nur alle 250 Millisekunden während der Wiedergabe aktualisiert.
- Die Größe der Schrittfrequenz auf dem Schieberegler muss mit der Länge des Videos skaliert werden.
- Abonnieren Sie die PointerPressed, PointerMoved, PointerReleased Ereignisse auf dem Schieberegler, um die PlaybackRate Eigenschaft auf 0 festzulegen, wenn der Benutzer den Daumen des Schiebereglers zieht.
- Legen Sie im PointerReleased Ereignishandler die Medienposition manuell auf die Schiebereglerposition fest, für ein optimales Einrasten des Daumens während des Scrubbens.
Zuordnen der Videoauflösung zur Geräteauflösung
Das Decodieren von Videos benötigt viel Arbeitsspeicher und GPU-Zyklen. Wählen Sie daher ein Videoformat in der Nähe der Auflösung aus, bei der es angezeigt wird. Es macht keinen Sinn, die Ressourcen zum Decodieren von 1080-Videos zu verwenden, wenn sie auf eine viel kleinere Größe skaliert werden. Viele Apps verfügen nicht über dasselbe Video, das in unterschiedlichen Auflösungen codiert ist. Wenn sie verfügbar ist, verwenden Sie jedoch eine Codierung, die der Auflösung nahe ist, in der sie angezeigt wird.
Auswählen empfohlener Formate
Die Auswahl von Medienformaten kann ein sensibles Thema sein und wird häufig von Geschäftsentscheidungen gesteuert. Aus UWP-Leistungsperspektive empfehlen wir H.264-Videos als primäres Videoformat und AAC und MP3 als bevorzugte Audioformate. Für die lokale Dateiwiedergabe ist MP4 der bevorzugte Dateicontainer für Videoinhalte. Die H.264-Decodierung wird durch die neueste Grafikhardware beschleunigt. Auch wenn die Hardwarebeschleunigung für die VC-1-Decodierung allgemein verfügbar ist, ist die Beschleunigung bei einer Vielzahl von Grafikhardware auf dem Markt in vielen Fällen auf eine partielle Beschleunigungsstufe (oder IDCT-Ebene) beschränkt und erreicht nicht den vollständigen Hardware-Offload (d. h. VLD-Modus).
Wenn Sie die volle Kontrolle über den Prozess der Videoinhaltsgenerierung haben, müssen Sie herausfinden, wie Sie ein gutes Gleichgewicht zwischen Komprimierungseffizienz und GOP-Struktur behalten. Relativ kleinere GOP-Größe mit B-Bildern kann die Leistung im Such- oder Trickmodus erhöhen.
Verwenden Sie WAV-Dateien mit unkomprimierten PCM-Daten, um den Verarbeitungsaufwand zu verringern, der für komprimierte Audioformate typisch ist, wenn Sie kurze Audioeffekte mit geringer Latenz verwenden, z. B. in Spielen.
Optimieren von Bildressourcen
Bilder auf die richtige Größe skalieren
Bilder werden mit sehr hohen Auflösungen erfasst, was dazu führen kann, dass Apps mehr CPU verwenden, wenn sie die Bilddaten decodieren und mehr Arbeitsspeicher nach dem Laden vom Datenträger. Es ist jedoch nicht sinnvoll, ein hochauflösendes Bild im Arbeitsspeicher zu decodieren und zu speichern, nur um es kleiner als seine ursprüngliche Größe anzuzeigen. Erstellen Sie stattdessen eine Version des Bilds in der exakten Größe, wie es auf dem Bildschirm angezeigt wird, mithilfe der Eigenschaften DecodePixelWidth und DecodePixelHeight.
Führen Sie dies nicht aus:
<Image Source="ms-appx:///Assets/highresCar.jpg"
Width="300" Height="200"/> <!-- BAD CODE DO NOT USE.-->
Gehen Sie stattdessen wie folgt vor:
<Image>
<Image.Source>
<BitmapImage UriSource="ms-appx:///Assets/highresCar.jpg"
DecodePixelWidth="300" DecodePixelHeight="200"/>
</Image.Source>
</Image>
Die Einheiten für DecodePixelWidth und DecodePixelHeight sind standardmäßig physische Pixel. Die Eigenschaft DecodePixelType kann verwendet werden, um dieses Verhalten zu ändern: Wenn man DecodePixelType auf Logical setzt, wird die Decodierungsgröße automatisch unter Berücksichtigung des aktuellen Skalierungsfaktors des Systems angepasst, ähnlich wie bei anderen XAML-Inhalten. Daher wäre es in der Regel sinnvoll, DecodePixelType auf Logical festzulegen, wenn Sie z. B. möchten, dass DecodePixelWidth und DecodePixelHeight den Eigenschaften "Height" und "Width" des Bildsteuerelements entsprechen, in dem das Bild angezeigt wird. Mit dem Standardverhalten der Verwendung physischer Pixel müssen Sie den aktuellen Skalierungsfaktor des Systems selbst berücksichtigen. und Sie sollten auf Skalierungsänderungsbenachrichtigungen lauschen, falls der Benutzer seine Anzeigeeinstellungen ändert.
Wenn DecodePixelWidth/Height explizit größer festgelegt ist als das Bild auf dem Bildschirm angezeigt wird, verwendet die App unnötig zusätzlichen Arbeitsspeicher – bis zu 4 Bytes pro Pixel – was für große Bilder schnell teuer wird. Das Bild wird durch bilineare Skalierung verkleinert, was dazu führen könnte, dass es bei großen Skalierungsfaktoren verschwommen angezeigt wird.
Wenn DecodePixelWidth/DecodePixelHeight explizit kleiner festgelegt sind, als das Bild auf dem Bildschirm dargestellt werden soll, wird es vergrößert und könnte pixelig erscheinen.
In einigen Fällen, in denen eine geeignete Decodierungsgröße nicht im Voraus bestimmt werden kann, sollten Sie sich auf XAMLs automatische Anpassung an die richtige Größe verlassen, die versucht, das Bild in der entsprechenden Größe zu decodieren, wenn kein expliziter DecodePixelWidth/DecodePixelHeight angegeben ist.
Sie sollten eine explizite Decodierungsgröße festlegen, wenn Sie die Größe des Bildinhalts vorab kennen. Sie sollten außerdem in Verbindung mit DecodePixelType auf Logische festlegen, wenn die angegebene Decodierungsgröße relativ zu anderen XAML-Elementgrößen ist. Wenn Sie beispielsweise die Inhaltsgröße explizit mit Image.Width und Image.Height festlegen, können Sie DecodePixelType auf DecodePixelType.Logical festlegen, um dieselben logischen Pixelabmessungen wie ein Bildsteuerelement zu verwenden und dann explizit BitmapImage.DecodePixelWidth und/oder BitmapImage.DecodePixelHeight zu verwenden, um die Größe des Bilds zu steuern, um potenziell große Speichereinsparungen zu erzielen.
Beachten Sie, dass Image.Stretch beim Bestimmen der Größe des decodierten Inhalts berücksichtigt werden sollte.
Decodierung der richtigen Größe
Wenn Sie keine explizite Decodierungsgröße festlegen, versucht XAML, Speicherplatz zu sparen, indem es ein Bild auf die exakte Größe decodiert, die es entsprechend dem anfänglichen Layout der Seite auf dem Bildschirm erscheint. Sie werden empfohlen, Ihre Anwendung so zu schreiben, dass sie dieses Feature nach Möglichkeit nutzen kann. Dieses Feature wird deaktiviert, wenn eine der folgenden Bedingungen erfüllt ist.
- Die BitmapImage- wird mit dem Live-XAML-Baum verbunden, nachdem der Inhalt mit SetSourceAsync- oder UriSource-festgelegt wurde.
- Das Bild wird mit synchroner Decodierung wie SetSourcedecodiert.
- Das Bild wird ausgeblendet, indem die
auf 0 gesetzt oder dieDeckkraft aufSichtbarkeit Collapsed eingestellt wird, am Hostbildelement, Pinsel oder einem übergeordneten Element. - Das Bildsteuerelement oder Pinsel verwendet eine Stretch- von None.
- Das Bild wird als NineGridverwendet.
-
CacheMode="BitmapCache"
wird für das Bildelement oder für jedes übergeordnete Element festgelegt. - Der Bildpinsel ist nicht rechteckig (z. B. wenn er auf eine Form oder auf Text angewendet wird).
In den oben genannten Szenarien ist das Festlegen einer expliziten Decodierungsgröße die einzige Möglichkeit, Speichereinsparungen zu erzielen.
Sie sollten immer ein BitmapImage an den lebenden Baum anhängen, bevor Sie die Quelle festlegen. Jedes Mal, wenn ein Bildelement oder Pinsel im Markup angegeben wird, ist dies automatisch der Fall. Beispiele finden Sie unten unter der Überschrift "Live-Baum-Beispiele". Sie sollten immer SetSource- vermeiden und stattdessen SetSourceAsync- verwenden, wenn Sie eine Streamquelle festlegen. Und es ist ratsam, das Ausblenden von Bildinhalten (entweder mit null Deckkraft oder mit verringerter Sichtbarkeit) zu vermeiden, während auf das ImageOpened-Ereignis gewartet wird, dass ausgelöst wird. Dies ist eine Ermessensentscheidung: Sie profitieren nicht von der automatisch angemessen dimensionierten Decodierung, wenn diese durchgeführt wird. Wenn Die App zunächst Bildinhalte ausblenden muss, sollte sie auch die Decodierungsgröße explizit festlegen, falls möglich.
Beispiele für lebende Bäume
Beispiel 1 (gut) – Uniform Resource Identifier (URI), der im Markup angegeben ist.
<Image x:Name="myImage" UriSource="Assets/cool-image.png"/>
Beispiel 2-Markup – URI, die in Code-Behind angegeben ist.
<Image x:Name="myImage"/>
Beispiel 2 Code-Behind (gut) – Verbinden des BitmapImage mit dem Baum, bevor die UriSource festgelegt wird.
var bitmapImage = new BitmapImage();
myImage.Source = bitmapImage;
bitmapImage.UriSource = new URI("ms-appx:///Assets/cool-image.png", UriKind.RelativeOrAbsolute);
Beispiel 2 Codebehind (schlecht) – Festlegen der UriSource von BitmapImage vor dem Verbinden mit dem Elementbaum.
var bitmapImage = new BitmapImage();
bitmapImage.UriSource = new URI("ms-appx:///Assets/cool-image.png", UriKind.RelativeOrAbsolute);
myImage.Source = bitmapImage;
Zwischenspeicherungsoptimierungen
Caching-Optimierungen gelten für Bilder, die UriSource- verwenden, um Inhalte aus einem App-Paket oder aus dem Web zu laden. Der URI wird verwendet, um den zugrunde liegenden Inhalt eindeutig zu identifizieren, und intern lädt das XAML-Framework den Inhalt nicht mehrmals herunter oder decodiert den Inhalt nicht. Stattdessen werden die zwischengespeicherten Software- oder Hardwareressourcen verwendet, um den Inhalt mehrmals anzuzeigen.
Die Ausnahme bei dieser Optimierung besteht darin, dass das Bild mehrmals mit unterschiedlichen Auflösungen angezeigt wird (die explizit oder über die automatische Decodierung der rechten Größe angegeben werden können). Jeder Cacheeintrag speichert auch die Auflösung des Bilds, und wenn XAML kein Bild mit einem Quell-URI finden kann, der der erforderlichen Auflösung entspricht, wird eine neue Version in dieser Größe decodiert. Die codierten Bilddaten werden jedoch nicht erneut heruntergeladen.
Daher sollten Sie UriSource- beim Laden von Bildern aus einem App-Paket nutzen, und vermeiden Sie, einen Dateidatenstrom und SetSourceAsync- zu verwenden, wenn dies nicht erforderlich ist.
Bilder in virtualisierten Panels (z. B. ListView)
Wenn ein Bild aus der Baumstruktur entfernt wird – entweder weil die App es explizit entfernt hat oder weil es sich in einem modernen virtualisierten Bereich befindet und beim Wegscrollen implizit aus der Ansicht entfernt wurde – optimiert XAML die Speicherauslastung, indem die Hardwareressourcen für das Bild freigegeben werden, da diese nicht mehr benötigt werden. Der Speicher wird nicht sofort freigegeben, sondern während der Frame-Aktualisierung, die eine Sekunde nachdem das Bildelement nicht mehr im Baum ist, stattfindet.
Daher sollten Sie versuchen, moderne virtualisierte Panels zu verwenden, um Listen von Bildinhalten zu hosten.
Software-gerasterte Bilder
Wenn ein Bild für einen nicht rechteckigen Pinsel oder für ein NineGrid-verwendet wird, verwendet das Bild einen Softwarerasterungspfad, der keine Bilder skaliert. Darüber hinaus muss es eine Kopie des Images sowohl im Software- als auch im Hardwarespeicher speichern. Wenn beispielsweise ein Bild als Pinsel für eine Ellipse verwendet wird, wird das potenziell große Vollbild zweimal intern gespeichert. Wenn Sie NineGrid oder einen nicht rechteckigen Pinsel verwenden, dann sollte Ihre App ihre Bilder auf ungefähr die Größe vorskalieren, in der sie gerendert werden.
Laden von Hintergrundbildern
XAML verfügt über eine interne Optimierung, die es ermöglicht, den Inhalt eines Bilds asynchron auf eine Oberfläche im Hardwarespeicher zu decodieren, ohne dass eine Zwischenoberfläche im Softwarespeicher erforderlich ist. Dies reduziert die Spitzenspeicherauslastung und die Rendering-Latenz. Dieses Feature wird deaktiviert, wenn eine der folgenden Bedingungen erfüllt ist.
- Das Bild wird als NineGridverwendet.
-
CacheMode="BitmapCache"
wird für das Bildelement oder für jedes übergeordnete Element festgelegt. - Der Bildpinsel ist nicht rechteckig (z. B. wenn er auf eine Form oder auf Text angewendet wird).
SoftwareBitmapSource
Die SoftwareBitmapSource Klasse austauscht interoperable nicht komprimierte Bilder zwischen verschiedenen WinRT-Namespaces wie BitmapDecoder, Kamera-APIs und XAML. Diese Klasse macht eine zusätzliche Kopie überflüssig, die in der Regel mit WriteableBitmap-erforderlich wäre, wodurch die Spitzenspeichernutzung und die Quelle-zu-Bildschirm-Latenz reduziert werden.
Die SoftwareBitmap-, die Quellinformationen bereitstellt, kann auch so konfiguriert werden, dass ein benutzerdefinierter IWICBitmap- verwendet wird, um einen neu ladbaren Sicherungsspeicher bereitzustellen, der es der App ermöglicht, den Speicher nach Bedarf neu zuzuordnen. Dies ist ein erweiterter C++-Anwendungsfall.
Ihre App sollte SoftwareBitmap und SoftwareBitmapSource verwenden, um mit anderen WinRT-APIs zu arbeiten, die Bilder erzeugen und nutzen. Und Ihre App sollte SoftwareBitmapSource verwenden, beim Laden unkomprimierter Bilddaten, anstatt WriteableBitmapzu verwenden.
Verwenden Sie GetThumbnailAsync für Miniaturansichten
Ein Anwendungsfall zum Skalieren von Bildern ist das Erstellen von Miniaturansichten. Obwohl Sie DecodePixelWidth und DecodePixelHeight verwenden können, um kleinere Bildversionen bereitzustellen, bietet UWP noch effizientere APIs zum Abrufen von Thumbnails. GetThumbnailAsync stellt die Miniaturansichten für Bilder bereit, die das Dateisystem bereits im Cache gespeichert hat. Dies bietet noch bessere Leistung als die XAML-APIs, da das Bild nicht geöffnet oder decodiert werden muss.
FileOpenPicker picker = new FileOpenPicker();
picker.FileTypeFilter.Add(".bmp");
picker.FileTypeFilter.Add(".jpg");
picker.FileTypeFilter.Add(".jpeg");
picker.FileTypeFilter.Add(".png");
picker.SuggestedStartLocation = PickerLocationId.PicturesLibrary;
StorageFile file = await picker.PickSingleFileAsync();
StorageItemThumbnail fileThumbnail = await file.GetThumbnailAsync(ThumbnailMode.SingleItem, 64);
BitmapImage bmp = new BitmapImage();
bmp.SetSource(fileThumbnail);
Image img = new Image();
img.Source = bmp;
Dim picker As New FileOpenPicker()
picker.FileTypeFilter.Add(".bmp")
picker.FileTypeFilter.Add(".jpg")
picker.FileTypeFilter.Add(".jpeg")
picker.FileTypeFilter.Add(".png")
picker.SuggestedStartLocation = PickerLocationId.PicturesLibrary
Dim file As StorageFile = Await picker.PickSingleFileAsync()
Dim fileThumbnail As StorageItemThumbnail = Await file.GetThumbnailAsync(ThumbnailMode.SingleItem, 64)
Dim bmp As New BitmapImage()
bmp.SetSource(fileThumbnail)
Dim img As New Image()
img.Source = bmp
Bilder einmal decodieren
Um zu verhindern, dass Bilder mehrmals decodiert werden, weisen Sie die Image.Source-Eigenschaft einem URI zu, anstatt Speicherströme zu verwenden. Das XAML-Framework kann denselben Uri an mehreren Stellen einem decodierten Bild zuordnen. Es kann jedoch nicht dasselbe mit mehreren Speicherdatenströmen tun, die die gleichen Daten enthalten, und erstellt für jeden Speicherdatenstrom ein anderes decodiertes Bild.