Optimieren von Animationen, Medien und Bildern
Erstellen Sie UWP-Apps (Universelle Windows-Plattform) mit flüssigen Animationen, hoher Bildfrequenz und leistungsstarker Medienaufzeichnung und -wiedergabe.
Reibungsloses Einbinden von Animationen
Ein wesentlicher Aspekt der UWP-Apps sind reibungslose Interaktionen. Dazu zählen Fingereingabemanipulationen, die sozusagen am Finger „kleben“, flüssige Übergänge und Animationen sowie kleine Bewegungen, die Eingabefeedback liefern. Das XAML-Framework verfügt über einen so genannten Kompositionsthread, der für die Zusammenstellung und Animation der visuellen Elemente einer App vorgesehen ist. Da der Kompositionsthread vom UI-Thread (dem Thread, der den Framework- und den Entwicklercode ausführt) getrennt ist, können Apps unabhängig von komplizierten Layoutdurchläufen oder erweiterten Berechnungen eine gleichmäßige Bildfrequenz und flüssige Animationen erzielen. In diesem Abschnitt erfahren Sie, wie Sie mithilfe des Kompositionsthreads butterweiche App-Animationen auf den Bildschirm zaubern. Weitere Informationen zu Animationen finden Sie unter Übersicht über Animationen. Informationen zum Verbessern der Reaktionsfähigkeit bei rechenintensiven Vorgängen finden Sie unter Sicherstellen der Reaktionsfähigkeit des UI-Threads.
Verwenden unabhängiger Animationen anstelle von abhängigen 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 einer Szene auswirken. Unabhängige Animationen können daher im Kompositionsthread und nicht im UI-Thread ausgeführt werden. Dadurch ist gewährleistet, dass die Animationen flüssig verlaufen, denn der Kompositionsthread wird in einem gleichmäßigen Rhythmus aktualisiert.
Alle diese Animationsarten sind garantiert unabhängig:
Objektanimationen mit Keyframes
Animationen ohne Dauer
Animationen der Eigenschaften Canvas.Left und Canvas.Top
Animationen der UIElement.Opacity-Eigenschaft
Animationen von Eigenschaften vom Typ Brush, wenn auf die untergeordnete Eigenschaft SolidColorBrush.Color abgezielt wird
Animationen der folgenden UIElement-Eigenschaften, wenn auf untergeordneten Eigenschaften dieser Rückgabewerttypen abgezielt wird:
Abhängige Animationen wirken sich auf das Layout aus und können nicht ohne zusätzliche Angaben aus dem UI-Thread berechnet werden. Abhängige Animationen umfassen Änderungen an Eigenschaften wie Width und Height. Abhängige Animationen werden standardmäßig nicht ausgeführt und erfordern die Zustimmung des App-Entwicklers. Werden sie aktiviert, laufen sie flüssig ab, solange der UI-Thread nicht blockiert wird. Ist das Framework oder die App dagegen stark mit anderen Vorgängen des UI-Threads ausgelastet, beginnen die Animationen zu ruckeln.
Nahezu alle Animationen im XAML-Framework sind standardmäßig unabhängig. Sie können diese Optimierung jedoch mithilfe einiger Schritte deaktivieren. Vorsicht ist besonders bei folgenden Szenarien geboten:
- Beim Festlegen der EnableDependentAnimation-Eigenschaft, um die Ausführung einer abhängigen Animation im UI-Thread zu ermöglichen. Beim Konvertieren dieser Animationen in eine unabhängige Version. Animieren Sie beispielsweise ScaleTransform.ScaleX und ScaleTransform.ScaleY anstelle der Eigenschaften Width und Height eines Objekts. Objekte wie Bilder und Text können ohne Weiteres skaliert werden. Das Framework wendet die bilineare Skalierung nur während der Animierung von ScaleTransform an. Bilder/Texte werden in der endgültigen Größe neu gerastert, um zu gewährleisten, dass sie stets gut erkennbar sind.
- Bei Verwendung framespezifischer Updates. Hierbei handelt es sich de facto um abhängige Animationen. Ein Beispiel hierfür ist das Anwenden von Transformationen im Handler des CompositonTarget.Rendering-Ereignisses.
- Beim Ausführen einer beliebigen, als unabhängig geltenden Animation in einem Element, bei dem die CacheMode-Eigenschaft auf BitmapCache festgelegt ist. Dies wird als abhängige Animation betrachtet, da der Cache für jeden Frame neu gerastert werden muss.
Animieren Sie keine WebView- oder MediaPlayerElement-Objekte.
Webinhalte innerhalb eines WebView-Steuerelements werden nicht direkt vom XAML-Framework gerendert. Zudem ist das Zusammenfügen mit dem Rest der Szene mit zusätzlichem Aufwand verbunden. Dieser Zusatzaufwand erhöht sich, wenn das animierte Steuerelement über den Bildschirm bewegt wird. Dies kann unter Umständen zu Synchronisierungsproblemen führen (der HTML-Inhalt könnte z. B. nicht synchron mit dem restlichen XAML-Inhalt der Seite sein). Wenn Sie ein WebView-Steuerelement animieren müssen, ersetzen Sie es für die Dauer der Animation durch ein WebViewBrush-Objekt.
Auch das Animieren eines MediaPlayerElement-Objekts ist nicht empfehlenswert. Abgesehen von den Leistungsbeeinträchtigungen kann dies im wiedergegebenen Videoinhalt zu Bildstörungen und anderen Artefakten 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 daher eine App für eine frühere Version von Windows verwenden, müssen Sie MediaElement verwenden.
Setzen Sie Endlosanimationen sparsam ein.
Die meisten Animationen werden für einen bestimmten Zeitraum ausgeführt. Wenn Sie die Timeline.Duration-Eigenschaft jedoch auf „Forever“ festlegen, kann die Animation ohne zeitliche Begrenzung ausgeführt werden. Wir empfehlen, Endlosanimationen möglichst sparsam einzusetzen, da solche Animationen fortlaufend CPU-Ressourcen verbrauchen. Dadurch kann die CPU unter Umständen nicht in den Stromsparmodus oder in den Leerlauf wechseln, was wiederum einen höheren Energieverbrauch zur Folge hat.
Das Hinzufügen eines Handlers für CompositionTarget.Rendering ist vergleichbar mit dem Ausführen eines Endlosanimation. Normalerweise ist der UI-Thread nur aktiv, wenn es etwas für ihn zu tun gibt. Fügen Sie jedoch einen Handler für dieses Ereignis hinzu, muss er in jedem Frame ausgeführt werden. Entfernen Sie den Handler, wenn es nichts zu tun gibt, und registrieren Sie ihn erneut, wenn er wieder benötigt wird.
Nutzen Sie die Animationsbibliothek.
Der Windows.UI.Xaml.Media.Animation-Namespace umfasst eine Bibliothek mit schnellen Hochleistungsanimationen, deren Erscheinungsbild mit anderen Windows-Animation konsistent ist. Die relevanten Klassen enthalten „Design“ in ihrem Namen und werden in Übersicht über Animationen beschrieben. Diese Bibliothek unterstützt viele gängige Animationsszenarien, z. B. die Animation der ersten Ansicht einer App oder die Erstellung von Zustands- und Inhaltsübergängen. Wir empfehlen, die Animationsbibliothek so oft wie möglich zu nutzen, um die Leistung und Konsistenz für UWP-UI zu verbessern.
Hinweis Von der Animationsbibliothek können nicht alle möglichen Eigenschaften animiert werden. Informationen zu XAML-Szenarien, bei denen die Animationsbibliothek nicht verwendet werden kann, finden Sie unter Storyboardanimationen.
Eigenständiges Animieren von CompositeTransform3D-Eigenschaften
Sie können jede CompositeTransform3D-Eigenschaft eigenständig animieren. Wenden Sie daher nur die Animationen an, die Sie benötigen. Beispiele und weitere Informationen finden Sie unter UIElement.Transform3D. Weitere Informationen zum Animieren von Transformationen finden Sie unter Storyboardanimationen und Keyframeanimationen und Animationen für Beschleunigungsfunktionen.
Optimieren von Medienressourcen
Audio, Video und Bilder sind verlockende Arten von Inhalten, die in den meisten Apps zum Einsatz kommen. Da immer mehr Medieninhalte aufgezeichnet und anstelle von SD-Qualität immer häufiger HD-Qualität verwendet wird, steigt der Ressourcenbedarf für die Speicherung, Decodierung und Wiedergabe dieser Inhalte. Das XAML-Framework nutzt die neuesten Features der UWP-Medienmodule, sodass Apps kostenlos von diesen Verbesserungen profitieren. Hier werden einige zusätzliche Tricks erläutert, mit denen Sie Medien in Ihrer UWP-App optimal nutzen können.
Freigeben von Mediendatenströmen
Mediendateien sind die gängigsten und aufwendigsten Ressourcen, die von Apps genutzt werden. Da Mediendateien den Speicherbedarf Ihrer App beträchtlich steigern können, ist es wichtig, das Handle für die Medien unverzüglich freizugeben, sobald die App sie nicht mehr verwendet.
Wenn Ihre App also beispielsweise ein RandomAccessStream- oder IInputStream-Objekt verwendet, müssen Sie die close-Methode für das Objekt aufrufen, sobald die App es nicht mehr verwendet. Dadurch wird das zugrundeliegende Objekt freigegeben.
Anzeigen der Videowiedergabe im Vollbildmodus (sofern möglich)
Verwenden Sie in UWP-Apps stets die IsFullWindow-Eigenschaft für das MediaPlayerElement, um das vollständige Rendern des Fensters zu aktivieren bzw. zu deaktivieren. Dies stellt sicher, dass während der Medienwiedergabe Optimierungen auf Systemebene genutzt werden.
Das XAML-Framework kann die Darstellung von Videoinhalten optimieren, wenn nur das Video gerendert wird. Dies senkt den Energieverbrauch und erhöht die Bildfrequenz. Um eine möglichst effiziente Medienwiedergabe zu erhalten, legen Sie die Größe eines MediaPlayerElement-Objekts auf die Breite und Höhe des Bildschirms fest. Zeigen Sie außerdem keine weiteren XAML-Elemente an.
Es gibt durchaus berechtigte Gründe für die Überlagerung von XAML-Elementen auf einem MediaPlayerElement-Objekt, das die gesamte Höhe und Breite des Bildschirms einnimmt, beispielsweise für Untertitel oder kurzzeitig angezeigte Transportsteuerelemente. Stellen Sie sicher, dass diese Elemente ausgeblendet werden (durch Festlegen von Visibility="Collapsed"
), wenn sie nicht benötigt werden, um die Medienwiedergabe wieder in den effizientesten Zustand zu versetzen.
Deaktivieren des Displays und Einsparen von Energie
Um ein Deaktivieren des Displays zu verhindern, wenn keine Benutzeraktion mehr festgestellt werden kann (z. B. bei der Wiedergabe eines Videos in einer App), können Sie DisplayRequest.RequestActive aufrufen.
Um Energie zu sparen und den Akku zu schonen, wird empfohlen, DisplayRequest.RequestRelease aufzurufen und die Displayanforderung freizugeben, sobald diese nicht mehr benötigt wird.
Unten sind einige Situationen aufgeführt, in denen Sie die Displayanforderung freigeben sollten:
- Die Videowiedergabe wird angehalten, z. B. per Benutzeraktion, wird gepuffert oder aufgrund begrenzter Bandbreite angepasst.
- Die Wiedergabe wird gestoppt. Beispielsweise ist die Wiedergabe des Videos beendet oder die Darstellung vorüber.
- Ein Wiedergabefehler ist aufgetreten. Es können beispielsweise Probleme mit der Netzwerkverbindung bestehen, oder eine Datei kann beschädigt sein.
Platzieren anderer Elemente neben dem eingebetteten Video
Apps bieten häufig eine eingebettete Ansicht, bei der das Video innerhalb einer Seite wiedergegeben wird. Es ist nun keine Vollbildoptimierung mehr verfügbar, da das MediaPlayerElement nicht die gesamte Seitengröße einnimmt und außerdem auch andere XAML-Objekte gezeichnet werden. Achten Sie darauf, nicht versehentlich in diesen Modus zu wechseln, indem Sie einen Rahmen um ein MediaPlayerElement-Objekt zeichnen.
Zeichnen Sie keine XAML-Elemente im Vordergrund des Videos, wenn sich dieses im eingebetteten Modus befindet. Andernfalls bedeutet dies einen Zusatzaufwand beim Erstellen der Szene. Ein gutes Optimierungsbeispiel für diese Situation ist das Platzieren von Transportsteuerelementen unterhalb eines eingebetteten Medienelements (anstatt im Vordergrund des Videos). In diesem Bild steht der rote Balken für eine Gruppe von Transportsteuerelementen (Wiedergabe, Pause, Stopp usw.).
Platzieren Sie diese Steuerelemente nicht im Vordergrund eines Mediums, das sich nicht im Vollbildmodus befindet. Positionieren Sie die Transportsteuerelemente stattdessen irgendwo außerhalb des Bereichs, in dem das Medium gerendert wird. Im nächsten Bild befinden sich die Steuerelemente unterhalb des Mediums.
Verzögern des Festlegens der Quelle für ein MediaPlayerElement
Medienmodule sind aufwendige Objekte, und das XAML-Framework verzögert das Laden von DLLs sowie das Erstellen großer Objekte so lange wie möglich. Das MediaPlayerElement ist gezwungen, diese Arbeit auszuführen, nachdem dessen Quelle über die Eigenschaft Source festgelegt wurde. Indem Sie dies festlegen, wenn der Benutzer wirklich ein Medium wiedergeben möchte, verzögern Sie den Großteil des Aufwands für das MediaPlayerElement-Objekt so weit wie möglich.
Festlegen von MediaElement.PosterSource
Durch Festlegen von MediaPlayerElement.PosterSource kann XAML einige GPU-Ressourcen freigeben, die andernfalls verwendet würden. Diese API ermöglicht es einer App, so wenig Arbeitsspeicher wie möglich zu beanspruchen.
Verbessern des Medien-Scrubbings
Bei Medienplattformen ist es immer eine besondere Herausforderung, dafür zu sorgen, dass das Scrubbing möglichst gut reagiert. Üblicherweise wird hierzu der Wert eines Schiebereglers geändert. Im Folgenden finden Sie einige Tipps für eine möglichst effiziente Verwendung:
- Aktualisieren Sie den Wert des Schiebereglers basierend auf einem Timer, der die Position auf MediaPlayerElement.MediaPlayer abfragt. Stellen Sie sicher, dass Sie eine geeignete Aktualisierungsfrequenz für den Timer verwenden. Die Eigenschaft Position wird während der Wiedergabe nur alle 250 Millisekunden aktualisiert.
- Die Größe der Schrittfrequenz für den Schieberegler muss gemäß der Videolänge skaliert werden.
- Abonnieren Sie die Ereignisse PointerPressed, PointerMoved und PointerReleased für den Schieberegler, um die PlaybackRate-Eigenschaft auf „0“ festzulegen, wenn der Benutzer den Ziehpunkt des Schiebereglers bewegt.
- Legen Sie die Medienposition im PointerReleased-Ereignishandler manuell auf den Wert der Schiebereglerposition fest, um beim Scrubbing eine optimale Ziehpunktausrichtung zu gewährleisten.
Anpassen der Videoauflösung an die Geräteauflösung
Die Videodecodierung benötigt sehr viel Arbeitsspeicher sowie sehr viele GPU-Zyklen. Entscheiden Sie sich daher für ein Videoformat, das der Auflösung, mit der das Video wiedergegeben wird, am nächsten kommt. Es bringt nichts, die Ressourcen zur Decodierung eines 1080-Videos zu verwenden, wenn es ohnehin auf eine deutlich geringere Größe skaliert wird. Bei vielen Apps liegt ein Video nicht in mehreren Auflösungen vor. Ist dies jedoch der Fall, verwenden Sie möglichst eine Codierung, die der Anzeigeauflösung am nächsten kommt.
Wählen empfohlener Formate
Die Wahl des Medienformats kann ein sensibles Thema sein und ist häufig abhängig von geschäftspolitischen Entscheidungen. Im Hinblick auf die Leistung von UWP empfehlen wir H.264-Video als primäres Videoformat sowie AAC und MP3 als bevorzugte Audioformate. Bei der lokalen Dateiwiedergabe ist MP4 der bevorzugte Dateicontainer für Videoinhalte. Die Decodierung von H.264 wird von den meisten aktuellen Grafikkarten beschleunigt. Zudem gilt es zu berücksichtigen, dass die Beschleunigung bei vielen der auf dem Markt erhältlichen Grafikkarten häufig auf eine partielle Beschleunigung (oder auf die IDCT-Ebene) beschränkt ist und keine Hardwareauslagerung für die gesamte Datenstromebene (VLD-Modus) stattfindet, obwohl die Hardwarebeschleunigung für die VC-1-Decodierung weitgehend verfügbar ist.
Wenn die Kontrolle über die Videoinhaltsgenerierung vollständig bei Ihnen liegt, müssen Sie ein möglichst ausgeglichenes Verhältnis zwischen Komprimierungseffizienz und GOP-Struktur finden. Eine relativ geringe GOP-Größe bei B-Bildern kann die Leistung bei Such- oder Trickmodi verbessern.
Verwenden Sie für kurze Audioeffekte mit geringer Latenz (beispielsweise in Spielen) WAV-Dateien mit nicht komprimierten PCM-Daten, um den für komprimierte Audioformate typischen Verarbeitungsmehraufwand zu reduzieren.
Optimieren von Bildressourcen
Skalieren von Bildern auf eine angemessene Größe
Bilder werden in sehr hohen Auflösungen erfasst, was dazu führen kann, dass Apps mehr CPU beim Decodieren der Bilddaten und mehr Arbeitsspeicher nach dem Laden vom Datenträger belegen. Es ist jedoch nicht sehr sinnvoll, ein Bild in hoher Auflösung zu decodieren und im Arbeitsspeicher zu speichern, nur um es dann kleiner als in seiner ursprünglichen Größe anzuzeigen. Erstellen Sie stattdessen eine Version des Bilds in der genauen Größe, in der es auf dem Bildschirm gezeichnet wird. Verwenden Sie hierzu die Eigenschaften DecodePixelWidth und DecodePixelHeight.
Nicht empfohlen:
<Image Source="ms-appx:///Assets/highresCar.jpg"
Width="300" Height="200"/> <!-- BAD CODE DO NOT USE.-->
Sondern gehen Sie stattdessen so vor:
<Image>
<Image.Source>
<BitmapImage UriSource="ms-appx:///Assets/highresCar.jpg"
DecodePixelWidth="300" DecodePixelHeight="200"/>
</Image.Source>
</Image>
Als Einheiten für DecodePixelWidth und DecodePixelHeight werden standardmäßig physische Pixel verwendet. Mit der DecodePixelType-Eigenschaft kann dieses Verhalten geändert werden: Durch Festlegen von DecodePixelType auf Logical wird bei der Decodierungsgröße automatisch der aktuelle Skalierungsfaktor des Systems ähnlich wie andere XAML-Inhalte berücksichtigt. Daher ist es in der Regel sinnvoll, DecodePixelType auf Logical festzulegen, wenn beispielsweise DecodePixelWidth und DecodePixelHeight den Eigenschaften für Höhe und Breite des Bildsteuerelements entsprechen sollen, in dem das Bild angezeigt wird. Beim Standardverhalten mit Verwendung von physischen Pixeln müssen Sie selbst den aktuellen Skalierungsfaktor des Systems berücksichtigen; für den Fall, dass der Benutzer seine Anzeigeeinstellungen ändert, sollten Sie auf Benachrichtigungen über Skalierungsänderungen achten.
Wenn „DecodePixelWidth/Height“ explizit größer als die Bildanzeige auf dem Bildschirm festgelegt sind, belegt die App unnötigen zusätzlichen Arbeitsspeicher (bis zu 4 Byte pro Pixel), was bei großen Bildern deutlich ins Gewicht fällt. Zudem wird das Bild mit bilinearer Skalierung verkleinert und kann bei großen Skalierungsfaktoren unscharf dargestellt werden.
Wenn DecodePixelWidth/DecodePixelHeight explizit kleiner als die Bilddarstellung auf dem Bildschirm festgelegt werden, wird das Bild vergrößert und kann pixelig aussehen.
In einigen Fällen, in denen es nicht möglich ist, die passende Decodierungsgröße im Voraus zu bestimmen, sollten Sie die automatische Decodierung von XAML auf die richtige Größe nutzen. Dabei wird nach Möglichkeit versucht, das Bild in der passenden Größe zu decodieren, wenn keine explizite DecodePixelWidth/DecodePixelHeight angegeben ist.
Es wird empfohlen, eine explizite Decodierungsgröße festzulegen, wenn Sie die Größe des Bildinhalts bereits vorab kennen. Legen Sie gleichzeitig DecodePixelType auf Logical fest, wenn die angegebene Decodierungsgröße in Bezug auf andere XAML-Elementgrößen relativ ist. Wenn Sie z. B. die Inhaltsgröße explizit mit Image.Width und Image.Height festlegen, legen Sie DecodePixelType auf DecodePixelType.Logical fest, um die gleichen logischen Pixeldimensionen wie ein Bildsteuerelement zu verwenden, und verwenden sie dann explizit BitmapImage.DecodePixelWidth und/oder BitmapImage.DecodePixelHeight, um die Größe des Bilds zu steuern und potenziell mehr Arbeitsspeicher einzusparen.
Beachten Sie, dass Image.Stretch beim Bestimmen der Größe des decodierten Inhalts berücksichtigt werden sollte.
Richtige Größe der Decodierung
Wenn Sie keine explizite Decodierungsgröße festlegen, versucht XAML, möglich viel Arbeitsspeicher zu sparen. Dabei wird das Bild auf die genaue Größe decodiert, in der es gemäß dem anfänglichen Layout der Seite angezeigt wird. Es wird empfohlen, die Anwendung so zu schreiben, dass dieses Feature nach Möglichkeit genutzt werden kann. Dieses Feature wird deaktiviert, wenn eine der folgenden Bedingungen erfüllt ist.
- Das BitmapImage-Objekt wird mit der Live-XAML-Struktur verbunden, nachdem der Inhalt mit SetSourceAsync oder UriSource festgelegt wurde.
- Das Bild wird mit synchroner Decodierung wie SetSource decodiert.
- Das Bild wird durch Festlegung von Opacity auf 0 oder Visibility auf Collapsed für das Hostbildelement, den Pinsel oder ein beliebiges übergeordnetes Element ausgeblendet.
- Das Bildsteuerelement bzw. der Pinsel verwendet für die Stretch-Aufzählung den Wert None.
- Das Bild wird als NineGrid verwendet.
CacheMode="BitmapCache"
wird auf das Bildelement oder ein beliebiges übergeordnetes Element festgelegt.- Der Bildpinsel ist nicht rechteckig (z. B. bei Anwendung auf eine Form oder auf Text).
In den oben genannten Szenarien ist das Festlegen einer expliziten Decodierungsgröße die einzige Möglichkeit, um Arbeitsspeichereinsparungen zu erzielen.
Fügen Sie stets ein BitmapImage-Objekt an die Live-Struktur an, bevor Sie die Quelle festlegen. Dies erfolgt jedes Mal automatisch, wenn ein Bildelement oder ein Pinsel im Markupcode angegeben wird. Beispiele finden Sie weiter unten im Abschnitt „Live-Struktur-Beispiele“. Vermeiden Sie beim Festlegen einer Datenstromquelle stets die Verwendung von SetSource, und verwenden Sie stattdessen SetSourceAsync. Zudem ist es sinnvoll, das Ausblenden von Bildinhalten (entweder durch eine Deckkraft von null oder die Sichtbarkeitseinstellung „collapsed“) zu vermeiden, während Sie darauf warten, dass das ImageOpened-Ereignis ausgelöst wird. Wägen Sie Ihre Entscheidung ab. Sie können in diesem Fall die Vorteile der automatischen Decodierung in der richtigen Größe nicht nutzen. Wenn Ihre App Bilder anfänglich ausblenden muss, sollte nach Möglichkeit auch die Decodierungsgröße explizit festgelegt werden.
Livestrukturbeispiele
Beispiel 1 (gut): URI (Uniform Resource Identifier) in Markup angegeben.
<Image x:Name="myImage" UriSource="Assets/cool-image.png"/>
Beispiel 2 – Markup: URI in CodeBehind angegeben.
<Image x:Name="myImage"/>
Beispiel 2 – CodeBehind (gut): Verbinden des BitmapImage mit der Struktur, bevor dessen 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, bevor es mit der Struktur verbunden wird.
var bitmapImage = new BitmapImage();
bitmapImage.UriSource = new URI("ms-appx:///Assets/cool-image.png", UriKind.RelativeOrAbsolute);
myImage.Source = bitmapImage;
Optimierungen der Zwischenspeicherung
Optimierungen beim Zwischenspeichern gelten für Bilder, die UriSource zum Laden von Inhalten aus einem App-Paket oder aus dem Internet verwenden. Der URI wird verwendet, um den zugrunde liegenden Inhalt eindeutig zu identifizieren. Intern sorgt er dafür, dass das XAML-Framework Inhalte nicht mehrmals herunterlädt oder decodiert. Stattdessen werden die zwischengespeicherten Software- oder Hardwareressourcen verwendet, um Inhalte mehrmals anzuzeigen.
Eine Ausnahme von dieser Optimierung besteht, wenn das Bild mehrmals in unterschiedlichen Auflösungen angezeigt wird (was explizit oder über automatische Decodierung in der richtigen Größe angegeben werden kann). Jeder Eintrag im Zwischenspeicher 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.
Aus diesem Grund sollten Sie UriSource verwenden, wenn Sie Bilder aus einem App-Paket laden. Vermeiden Sie zudem die Verwendung eines Dateidatenstroms und von SetSourceAsync, wenn diese nicht erforderlich sind.
Bilder in virtualisierten Panels (z. B. ListView)
Wenn ein Bild aus der Struktur entfernt wird (weil es von der App explizit entfernt wurde, oder weil es sich in einem modernen virtualisierten Panel befindet und implizit beim Bildlauf aus der Ansicht entfernt wurde), optimiert XAML die Speichernutzung, indem es die nicht mehr für das Bild benötigten Hardwareressourcen freigibt. Der Arbeitsspeicher wird nicht sofort freigegeben, sondern erst bei der Frameaktualisierung, die eine Sekunde nach Entfernung des Bildelements aus der Struktur stattfindet.
Folglich sollten Sie nach Möglichkeit moderne virtualisierte Panels zum Hosten von Listen mit Bildinhalten nutzen.
Softwaregerasterte Bilder
Wenn ein Bild für einen nicht rechteckigen Pinsel oder ein NineGrid verwendet wird, verwendet das Bild einen Softwarerasterungspfad, bei dem Bilder gar nicht skaliert werden. Zudem muss eine Kopie des Bilds sowohl im Arbeitsspeicher der Software als auch der Hardware gespeichert werden. Wenn z. B. ein Bild als Pinsel für eine Ellipse verwendet wird, wird das potenziell große Vollbild zweimal intern gespeichert. Bei Verwendung von NineGrid oder eines nicht rechteckigen Pinsels sollte die App die Bilder vorab auf die ungefähre Größe skalieren, in der sie gerendert werden.
Laden von Bildern in einem Hintergrundthread
XAML verfügt über eine interne Optimierung, mit der der Inhalt eines Bildes asynchron auf eine Oberfläche im Hardwarespeicher decodiert werden kann, ohne dass eine Zwischenoberfläche im Softwarespeicher benötigt wird. Dies reduziert Spitzen bei der Speicherauslastung und Renderinglatenz. Dieses Feature wird deaktiviert, wenn eine der folgenden Bedingungen erfüllt ist.
- Das Bild wird als NineGrid verwendet.
CacheMode="BitmapCache"
wird auf das Bildelement oder ein beliebiges übergeordnetes Element festgelegt.- Der Bildpinsel ist nicht rechteckig (z. B. bei Anwendung auf eine Form oder auf Text).
SoftwareBitmapSource
Die SoftwareBitmapSource-Klasse tauscht interoperable, nicht komprimierte Bilder zwischen unterschiedlichen WinRT-Namespaces aus, z. B. BitmapDecoder, Kamera-APIs und XAML. Diese Klasse vermeidet die zusätzliche Kopie, die in der Regel mit WriteableBitmap erforderlich wäre. Dadurch reduzieren sich Spitzenlasten im Speicher sowie die Quelle-zu-Bildschirm-Latenz.
Die SoftwareBitmap-Klasse, die Quellinformationen bereitstellt, kann auch für ein benutzerdefiniertes IWICBitmap-Objekt konfiguriert werden. Dadurch wird ein erneut ladbarer Sicherungsspeicher bereitgestellt, mit dem die App Arbeitsspeicher nach Bedarf neu zuordnen kann. Dies ist ein erweiterter C++-Anwendungsfall.
Ihre App sollte SoftwareBitmap und SoftwareBitmapSource für die Interoperabilität mit anderen WinRT-APIs verwenden, die Bilder produzieren und nutzen. Zudem sollte die App beim Laden von nicht komprimierten Bilddaten anstelle von WriteableBitmap die SoftwareBitmapSource-Klasse verwenden.
Verwenden von „GetThumbnailAsync“ für Miniaturansichten
Ein Anwendungsfall für die Bildskalierung ist die Erstellung von Miniaturansichten. Sie könnten kleine Bildversionen zwar auch mit DecodePixelWidth und DecodePixelHeight bereitstellen, aber die Universelle Windows-Plattform (UWP) bietet noch effizientere APIs zum Abrufen von Miniaturansichten. GetThumbnailAsync stellt die Miniaturansichten für Bilder bereit, bei denen das Dateisystem bereits zwischengespeichert wurde. Dadurch erhalten Sie eine noch bessere Leistung als bei den XAML-APIs, da das Bild weder geöffnet noch 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
Einmaliges Decodieren von Bildern
Damit Bilder nicht mehrmals decodiert werden, weisen Sie die Image.Source-Eigenschaft von einem URI aus zu, anstatt Speicherstreams zu verwenden. Das XAML-Framework kann den gleichen URI an mehreren Orten einem einzelnen decodierten Bild zuordnen. Für mehrere Speicherstreams mit den gleichen Daten ist dies allerdings nicht möglich. Hier erstellt das Framework für jeden Speicherstream ein eigenes decodiertes Bild.