Übersicht über die App-Analyse

App-Analyse ist ein Tool, mit dem Entwickler eine Benachrichtigung über Leistungsprobleme erhalten. Die App-Analyse prüft Ihren App-Code gegen eine Reihe von Leistungsrichtlinien und Best Practices.

Die App-Analyse identifiziert Probleme anhand eines Regelsatzes häufiger Leistungsprobleme, auf die Apps stoßen. Bei Bedarf wird die App-Analyse auf das Zeitachsentool von Visual Studio, die Quellinformationen und die Dokumentation hinweisen, um Ihnen die Möglichkeit zur Untersuchung zu geben.

Regeln in der App-Analyse beziehen sich auf eine Richtlinie oder bewährte Methode, auf die Ihre App überprüft wird.

Decodierte Bildgröße größer als die Rendergröße

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 genauen Größe, die auf dem Bildschirm gezeichnet wird, mithilfe der Eigenschaften DecodePixelWidth und DecodePixelHeight.

Auswirkung

Das Anzeigen von Bildern in ihren nicht-nativen Größen kann sich sowohl negativ auf die CPU-Zeit (aufgrund der Decodierung auf die richtige Größe und der Downloadzeit) als auch auf den Arbeitsspeicher auswirken.

Ursachen und Lösungen

Bild wird nicht asynchron gesetzt

Die App verwendet SetSource() anstelle von SetSourceAsync(). Sie sollten die Verwendung von SetSource immer vermeiden und stattdessen SetSourceAsync verwenden, wenn Sie einen Datenstrom so festlegen, dass Bilder asynchron decodiert werden.

Das Bild wird aufgerufen, wenn sich die ImageSource nicht im Live-Baum befindet.

Das BitmapImage ist, nachdem der Inhalt mit SetSourceAsync oder UriSource festgelegt wurde, mit dem Live-XAML-Baum verbunden. 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. Nachfolgend finden Sie Beispiele.

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;

Bildpinsel ist nicht rechteckig

Wenn ein Bild für einen nicht rechteckigen Pinsel 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 z. B. ein Bild als Pinsel für eine Ellipse verwendet wird, wird das potenziell große Vollbild zweimal intern gespeichert. Wenn Sie einen nicht rechteckigen Pinsel verwenden, sollte Ihre App ihre Bilder auf ungefähr die Größe vorab skalieren, in der sie gerendert werden sollen.

Alternativ, können Sie eine explizite Dekodiergröße festlegen, um eine Version des Bilds in der genauen Größe zu erstellen, die auf dem Bildschirm angezeigt wird, indem Sie die Eigenschaften DecodePixelWidth und DecodePixelHeight verwenden.

<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 empfiehlt es sich in der Regel, DecodePixelType- auf Logisch festzulegen, wenn Sie z. B. DecodePixelWidth und DecodePixelHeight- mit den Eigenschaftswerten "Höhe" und "Breite" des Bild-Steuerelements übereinstimmen möchten, 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.

In einigen Fällen, in denen eine geeignete Decodierungsgröße nicht rechtzeitig bestimmt werden kann, sollten Sie auf die automatische Größenanpassung durch XAML zurückgreifen, wodurch das Bild nach Möglichkeit in der passenden Größe dekodiert wird, 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 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.

Bilder, die in BitmapIcons verwendet werden, greifen auf die Decodierung auf natürliche Größe zurück.

Legen Sie eine explizite Decodierungsgröße fest, um eine Version des Bilds mit der genauen Größe zu erstellen, die auf dem Bildschirm gezeichnet wird, indem Sie die Eigenschaften DecodePixelWidth und DecodePixelHeight- verwenden.

Bilder, die extrem groß auf dem Bildschirm erscheinen, werden wieder in ihre natürliche Größe decodiert.

Bilder, die extrem groß auf dem Bildschirm erscheinen, fallen auf die Decodierung auf natürliche Größe zurück. Legen Sie eine explizite Decodierungsgröße fest, um eine Version des Bilds mit der genauen Größe zu erstellen, die auf dem Bildschirm gezeichnet wird, indem Sie die Eigenschaften DecodePixelWidth und DecodePixelHeight- verwenden.

Bild wurde ausgeblendet

Das Bild wird ausgeblendet, indem die Deckkraft auf 0 oder die Sichtbarkeit auf „Ausgeblendet“ gesetzt wird, entweder für das Host-Bildelement, das Brush-Element oder ein beliebiges übergeordnetes Element. Bilder, die aufgrund von Clipping oder Transparenz nicht auf dem Bildschirm sichtbar sind, können auf die Decodierung auf natürliche Größe zurückfallen.

Das Bild verwendet die NineGrid-Eigenschaft.

Wenn ein Bild für eine NineGridverwendet 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 Sie NineGrid-verwenden, sollte Ihre App die Bilder vorab auf die Größe skalieren, an der sie gerendert werden.

Bilder, die die NineGrid-Eigenschaft verwenden, greifen auf die Decodierung auf natürliche Größe zurück. Erwägen Sie das Hinzufügen des Neungittereffekts zum originalen Bild.

DecodePixelWidth oder DecodePixelHeight werden auf eine Größe eingestellt, die größer ist, als das Bild auf dem Bildschirm erscheinen wird.

Wenn DecodePixelWidth/Height explizit größer als das Bild festgelegt ist, das 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 ebenfalls durch bilineare Skalierung verkleinert, was dazu führen kann, dass es bei großen Skalierungsfaktoren verschwommen erscheint.

Ein Bild wird als Teil der Erstellung eines Drag-&-Drop-Bildes decodiert.

Legen Sie eine explizite Decodierungsgröße fest, um eine Version des Bilds mit der genauen Größe zu erstellen, die auf dem Bildschirm gezeichnet wird, indem Sie die Eigenschaften DecodePixelWidth und DecodePixelHeight- verwenden.

Eingeklappte Elemente beim Laden

Ein gängiges Muster in Apps besteht darin, Elemente in der Benutzeroberfläche zunächst auszublenden und zu einem späteren Zeitpunkt anzuzeigen. In den meisten Fällen sollten diese Elemente mithilfe von "x:Load" oder "x:DeferLoadStrategy" zurückgestellt werden, um zu vermeiden, dass die Kosten für das Erstellen des Elements zur Ladezeit anfallen.

Dies schließt Fälle ein, in denen ein Boolescher-zu-Sichtbarkeits-Konverter verwendet wird, um Elemente bis zu einem späteren Zeitpunkt auszublenden.

Auswirkung

Zusammengeklappte Elemente werden zusammen mit anderen Elementen geladen und verlängern die Ladezeit.

Ursache

Diese Regel wurde ausgelöst, weil ein Element beim Laden eingeklappt wurde. Das Einklappen eines Elements oder das Festlegen der Deckkraft auf 0 verhindert nicht, dass das Element erzeugt wird. Diese Regel kann durch eine App verursacht werden, die einen Booleschen Wert in Sichtbarkeit umwandelt und dabei standardmäßig auf "false" festgelegt ist.

Lösung

Mithilfe des x:Load-Attributs oder x:DeferLoadStrategykönnen Sie das Laden eines UI-Abschnitts verzögern und nach Bedarf laden. Dies ist eine gute Möglichkeit, die Verarbeitung der UI zu verzögern, die im ersten Frame nicht sichtbar ist. Sie können das Element bei Bedarf oder als Teil einer Reihe verzögerter Logik laden. Rufen Sie zum Auslösen des Ladens "findName" für das Element auf, das Sie laden möchten. x:Load erweitert die Funktionen von x:DeferLoadStrategy, sodass Elemente entladen werden können, und damit der Ladezustand über x:Bind gesteuert werden kann.

In einigen Fällen ist die Verwendung von findName zum Anzeigen eines Teils der Benutzeroberfläche möglicherweise nicht die Antwort. Dies ist der Fall, wenn Sie erwarten, dass ein erheblicher Teil der Benutzeroberfläche bei einem Klick auf eine Schaltfläche mit sehr geringer Latenz umgesetzt wird. In diesem Fall könnte es sinnvoll sein, eine schnellere UI-Latenz in Kauf zu nehmen, auch wenn dies mit zusätzlichem Speicherverbrauch verbunden ist. Ist dies der Fall, sollten Sie x:DeferLoadStrategy verwenden und die Sichtbarkeit des zu realisierenden Elements auf "Collapsed" setzen. Nachdem die Seite geladen wurde und der UI-Thread frei ist, können Sie bei Bedarf findName aufrufen, um die Elemente zu laden. Die Elemente werden dem Benutzer erst angezeigt, wenn Sie die Sichtbarkeit des Elements auf "Visible" festgelegt haben.

ListView ist nicht virtualisiert

Die UI-Virtualisierung ist die wichtigste Verbesserung, die Sie zur Verbesserung der Sammlungsleistung vornehmen können. Dies bedeutet, dass UI-Elemente, die die Elemente darstellen, bei Bedarf erstellt werden. Bei einem Elementsteuerelement, das an eine Sammlung von 1000 Elementen gebunden ist, wäre es eine Verschwendung von Ressourcen, die Benutzeroberfläche für alle Elemente gleichzeitig zu erstellen, da sie nicht alle gleichzeitig angezeigt werden können. ListView und GridView (und andere von ItemsControl abgeleitete Standardsteuerelemente) führen UI-Virtualisierung für Sie durch. Wenn Elemente kurz davor stehen, in die Ansicht gescrollt zu werden (nur wenige Seiten entfernt), generiert das Framework die Benutzeroberfläche für die Elemente und speichert sie zwischen. Wenn es unwahrscheinlich ist, dass die Elemente erneut angezeigt werden, beansprucht das Framework den Speicher erneut.

Die UI-Virtualisierung ist nur einer der wichtigsten Faktoren zur Verbesserung der Sammlungsleistung. Die Verringerung der Komplexität von Sammlungselementen und der Datenvirtualisierung sind zwei weitere wichtige Aspekte zur Verbesserung der Sammlungsleistung. Weitere Informationen zur Verbesserung der Sammlungsleistung in ListViews und GridViews finden Sie in den Artikeln zur Optimierung der ListView- und GridView-Benutzeroberfläche sowie zur Virtualisierung von ListView- und Gridview-Daten.

Auswirkung

Ein nicht virtualisiertes ItemsControl erhöht die Ladezeit und die Ressourcenauslastung, indem mehr untergeordnete Elemente geladen werden, als erforderlich.

Ursache

Das Konzept eines Viewports ist für die UI-Virtualisierung von entscheidender Bedeutung, da das Framework die Elemente erstellen muss, die wahrscheinlich angezeigt werden. Im Allgemeinen ist der Viewport eines ItemsControl der Umfang des logischen Steuerelements. Beispielsweise ist der Viewport eines ListView-Elements die Breite und Höhe des ListView-Elements. Einige Panels bieten untergeordneten Elementen unbegrenzten Platz, wie zum Beispiel ein ScrollViewer und ein Grid mit Zeilen oder Spalten in automatischer Größe. Wenn ein virtualisiertes ItemsControl-Element in einem Panel platziert wird, benötigt es genügend Platz, um alle zugehörigen Elemente anzuzeigen, wodurch die Virtualisierung aufgehoben wird.

Lösung

Stellen Sie die Virtualisierung wieder her, indem Sie eine Breite und Höhe für das verwendete ItemsControl-Objekt festlegen.

UI-Thread während des Ladens blockiert oder im Leerlauf

UI-Thread-Blockierung bezieht sich auf synchrone Aufrufe von Funktionen, die außerhalb des Threads ausgeführt werden und den UI-Thread blockieren.

Eine vollständige Liste der bewährten Methoden zur Verbesserung der Startleistung Ihrer App finden Sie unter Bewährte Methoden für die Startleistung Ihrer App und halten den UI-Thread reaktionsfähig.

Auswirkung

Ein blockierter oder leerer UI-Thread während der Ladezeit verhindert layout- und andere UI-Vorgänge und erhöht die Startzeit.

Ursache

Plattformcode für die UI und der Code Ihrer App für die UI werden alle im selben UI-Thread ausgeführt. Nur eine Anweisung kann jeweils für diesen Thread ausgeführt werden. Wenn der App-Code also zu lange benötigt, um ein Ereignis zu verarbeiten, kann das Framework kein Layout ausführen oder neue Ereignisse generieren, die Benutzerinteraktion darstellen. Die Reaktionsfähigkeit Ihrer App hängt von der Verfügbarkeit des UI-Threads ab, um Aufgaben zu bearbeiten.

Lösung

Ihre App kann interaktiv sein, obwohl Teile der App nicht voll funktionsfähig sind. Wenn Ihre App beispielsweise Daten anzeigt, die eine Weile zum Abrufen dauern, können Sie diesen Code unabhängig vom Startcode der App ausführen, indem Sie die Daten asynchron abrufen. Wenn die Daten verfügbar sind, füllen Sie die Benutzeroberfläche der App mit den Daten auf. Um ihre App reaktionsfähig zu halten, stellt die Plattform asynchrone Versionen vieler apIs bereit. Eine asynchrone API stellt sicher, dass Ihr aktiver Ausführungsthread niemals für einen erheblichen Zeitraum blockiert. Wenn Sie eine API aus dem UI-Thread aufrufen, verwenden Sie die asynchrone Version, wenn sie verfügbar ist.

{Binding} wird anstelle von {x:Bind} verwendet.

Diese Regel wird ausgelöst, wenn Ihre App eine {Binding}-Anweisung verwendet. Um die App-Leistung zu verbessern, sollten Apps die Verwendung von {x:Bind} in Betracht ziehen.

Auswirkung

{Binding} benötigt mehr Zeit und Arbeitsspeicher als {x:Bind}.

Ursache

Die App verwendet {Binding} anstelle von {x:Bind}. {Binding} bringt einen nicht trivialen Arbeitssatz und CPU-Overhead mit sich. Das Erstellen eines {Binding} verursacht eine Reihe von Allokationen, und das Aktualisieren eines Bindungsziels kann zu Reflexion und Boxing führen.

Lösung

Verwenden Sie die {x:Bind}-Markuperweiterung, die Bindungen zur Buildzeit kompiliert. {x:Bind}-Bindungen (häufig als kompilierte Bindungen bezeichnet) bieten eine hervorragende Leistung, stellen eine Kompilierungszeitüberprüfung Ihrer Bindungsausdrücke bereit und unterstützen das Debuggen, indem Sie Haltepunkte in den Codedateien festlegen können, die als Teilklasse für Ihre Seite generiert werden.

Beachten Sie, dass x:Bind nicht in allen Fällen, wie zum Beispiel bei spät gebundenen Szenarien, geeignet ist. Eine vollständige Liste der Fälle, die nicht von {x:Bind} abgedeckt werden, finden Sie in der {x:Bind}-Dokumentation.

x:Name wird anstelle von "x:Key" verwendet.

ResourceDictionaries werden in der Regel verwendet, um Ihre Ressourcen auf einer etwas globalen Ebene zu speichern, d. a. Ressourcen, auf die Ihre App an mehreren Stellen verweisen möchte. z. B. Stile, Pinsel, Vorlagen usw. Im Allgemeinen haben wir die ResourceDictionaries so optimiert, dass Ressourcen nicht instanziiert werden, es sei denn, sie werden angefordert. Aber es gibt nur wenige Orte, an denen Sie vorsichtig sein müssen.

Auswirkung

Jede Ressource mit x:Name wird instanziiert, sobald das ResourceDictionary erstellt wird. Dies geschieht, weil x:Name der Plattform mitteilt, dass Ihre App Feldzugriff auf diese Ressource benötigt, und die Plattform daher etwas erzeugen muss, um darauf verweisen zu können.

Ursache

Ihre App legt "x:Name" für eine Ressource fest.

Lösung

Verwenden Sie "x:Key" anstelle von "x:Name", wenn Sie nicht auf Ressourcen aus CodeBehind verweisen.

Die Sammlungssteuerung verwendet ein nicht-virtualisierendes Panel.

Wenn Sie eine benutzerdefinierte Elementpanel-Vorlage (siehe ItemsPanel) bereitstellen, stellen Sie sicher, dass Sie ein virtualisierendes Panel wie ItemsWrapGrid oder ItemsStackPanel verwenden. Wenn Sie VariableSizedWrapGrid, WrapGrid oder StackPanel verwenden, erhalten Sie keine Virtualisierung. Darüber hinaus werden die folgenden ListView-Ereignisse nur ausgelöst, wenn ein ItemsWrapGrid oder ein ItemsStackPanel verwendet wird: ChoosingGroupHeaderContainer, ChoosingItemContainer und ContainerContentChanging.

Die UI-Virtualisierung ist die wichtigste Verbesserung, die Sie zur Verbesserung der Sammlungsleistung vornehmen können. Dies bedeutet, dass UI-Elemente, die die Elemente darstellen, bei Bedarf erstellt werden. Bei einem Elementsteuerelement, das an eine Sammlung von 1000 Elementen gebunden ist, wäre es eine Verschwendung von Ressourcen, die Benutzeroberfläche für alle Elemente gleichzeitig zu erstellen, da sie nicht alle gleichzeitig angezeigt werden können. ListView und GridView (und andere von ItemsControl abgeleitete Standardsteuerelemente) führen UI-Virtualisierung für Sie durch. Wenn Elemente kurz davor stehen, in die Ansicht gescrollt zu werden (nur wenige Seiten entfernt), generiert das Framework die Benutzeroberfläche für die Elemente und speichert sie zwischen. Wenn es unwahrscheinlich ist, dass die Elemente erneut angezeigt werden, beansprucht das Framework den Speicher erneut.

Die UI-Virtualisierung ist nur einer der wichtigsten Faktoren zur Verbesserung der Sammlungsleistung. Die Verringerung der Komplexität von Sammlungselementen und der Datenvirtualisierung sind zwei weitere wichtige Aspekte zur Verbesserung der Sammlungsleistung. Weitere Informationen zur Verbesserung der Sammlungsleistung in ListViews und GridViews finden Sie in den Artikeln zur Optimierung der ListView- und GridView-Benutzeroberfläche sowie zur Virtualisierung von ListView- und Gridview-Daten.

Auswirkung

Ein nicht virtualisiertes ItemsControl erhöht die Ladezeit und die Ressourcenauslastung, indem mehr untergeordnete Elemente geladen werden, als erforderlich.

Ursache

Sie verwenden ein Panel, das die Virtualisierung nicht unterstützt.

Lösung

Verwenden Sie ein Virtualisierungspanel wie ItemsWrapGrid oder ItemsStackPanel.

Barrierefreiheit: UIA-Elemente ohne Namen

In XAML können Sie einen Namen angeben, indem Sie AutomationProperties.Name festlegen. Viele Automatisierungspeers stellen einen Standardnamen für UIA bereit, wenn AutomationProperties.Name nicht festgelegt ist.

Auswirkung

Wenn ein Benutzer ein Element ohne Namen erreicht, hat er oft keine Möglichkeit zu wissen, worauf sich das Element bezieht.

Ursache

Der UIA-Name des Elements ist null oder leer. Diese Regel überprüft, was UIA sieht, nicht den Wert des AutomationProperties.Name.

Lösung

Legen Sie die AutomationProperties.Name-Eigenschaft im XAML-Code des Steuerelements auf eine entsprechende lokalisierte Zeichenfolge fest.

Manchmal ist der richtige Anwendungsfix nicht das Angeben eines Namens, sondern das Entfernen des UIA-Elements von allen außer den Rohbäumen. Sie können dies in XAML tun, indem Sie festlegen AutomationProperties.AccessibilityView = "Raw".

Barrierefreiheit: UIA-Elemente mit demselben Controltype sollten nicht denselben Namen haben

Zwei UIA-Elemente mit demselben übergeordneten UIA-Element dürfen nicht denselben Namen und denselben Steuerungstyp haben. Es ist in Ordnung, zwei Steuerelemente mit demselben Namen zu haben, wenn sie unterschiedliche ControlTypes haben.

Diese Regel prüft nicht auf doppelte Namen mit unterschiedlichen Eltern. In den meisten Fällen sollten Sie Namen und ControlTypes jedoch nicht innerhalb eines gesamten Fensters duplizieren, auch nicht mit unterschiedlichen übergeordneten Elementen. Fälle, in denen doppelte Namen in einem Fenster zulässig sind, sind zwei Listen mit identischen Elementen. In diesem Fall sollten die Listenelemente identische Namen und ControlTypes haben.

Auswirkung

Wenn ein Benutzer ein Element mit demselben Namen und ControlType erreicht wie ein anderes Element mit demselben übergeordneten UIA-Element, kann der Benutzer den Unterschied zwischen den Elementen möglicherweise nicht unterscheiden.

Ursache

UIA-Elemente mit demselben übergeordneten UIA-Element weisen denselben Namen und ControlType auf.

Lösung

Legen Sie einen Namen in XAML mithilfe von AutomationProperties.Name fest. Verwenden Sie bei Listen, in denen dies häufig vorkommt, eine Bindung, um den Wert von AutomationProperties.Name an eine Datenquelle zu koppeln.