Omówienie analizy XAML

Analiza XAML to narzędzie, które powiadamia o problemach z wydajnością w aplikacji. Sprawdza kod aplikacji pod kątem zestawu wytycznych dotyczących wydajności i najlepszych rozwiązań oraz identyfikuje problemy z zestawu reguł typowych problemów.

Gdy narzędzie wykryje problem, wskazuje narzędzia diagnostyczne Visual Studio, informacje o źródle i dokumentację, aby można było zbadać i rozwiązać problem.

Zdekodowany rozmiar obrazu większy niż rozmiar renderowania

Obrazy przechwycone w wysokiej rozdzielczości mogą spowodować, że aplikacja będzie używać większej ilości procesora CPU podczas dekodowania i większej ilości pamięci po załadowaniu z dysku. Nie ma żadnej korzyści z dekodowania obrazu o wysokiej rozdzielczości, jeśli wyświetlasz go tylko w mniejszym rozmiarze. Zamiast tego utwórz wersję obrazu w rozmiarze, w jakim jest rysowany na ekranie, używając właściwości DecodePixelWidth i DecodePixelHeight.

Wpływ

Wyświetlanie obrazów o rozmiarach innych niż ich rozmiar macierzysty może negatywnie wpłynąć na czas procesora CPU (dekodowanie i pobieranie) i pamięć.

Przyczyny i rozwiązania

Obraz nie jest ustawiany asynchronicznie

Aplikacja używa SetSource() zamiast SetSourceAsync(). Zawsze używaj polecenia SetSourceAsync podczas ustawiania strumienia w celu asynchronicznego dekodowania obrazów.

Źródło obrazu jest ustawiane, zanim element znajdzie się w aktywnym drzewie

Element BitmapImage jest połączony z aktywnym drzewem XAML po ustawieniu zawartości za pomocą SetSourceAsync lub UriSource. Przed ustawieniem źródła zawsze dołączaj element BitmapImage do aktywnego drzewa. Po określeniu w znacznikach elementu obrazu lub pędzla dołączenie następuje automatycznie.

Dobrze — źródło określone w znacznikach za pomocą BitmapImage:

<Image x:Name="myImage">
    <Image.Source>
        <BitmapImage UriSource="Assets/cool-image.png"/>
    </Image.Source>
</Image>

Poprawnie — dołączanie obiektu BitmapImage do drzewa przed ustawieniem jego właściwości UriSource:

Image myImage = new Image();
var bitmapImage = new BitmapImage();
myImage.Source = bitmapImage;
bitmapImage.UriSource = new Uri("ms-appx:///Assets/cool-image.png", UriKind.RelativeOrAbsolute);

Nieprawidłowe — ustawienie właściwości UriSource obiektu BitmapImage przed dołączeniem go do drzewa:

Image myImage = new Image();
var bitmapImage = new BitmapImage();
bitmapImage.UriSource = new Uri("ms-appx:///Assets/cool-image.png", UriKind.RelativeOrAbsolute);
myImage.Source = bitmapImage;

Szczotka obrazu nie jest prostokątna

Gdy używasz obrazu jako pędzla o nieregularnym kształcie, obraz korzysta z programowej ścieżki rasteryzacji, która nie skaluje obrazów. Ponadto system przechowuje kopię obrazu zarówno w pamięci oprogramowania, jak i sprzętu. Jeśli używasz pędzla nie prostokątnego, wstępnie przeskaluj obrazy do rozmiaru, na który są renderowane.

Alternatywnie ustaw jawny rozmiar dekodowania przy użyciu właściwości DecodePixelWidth i DecodePixelHeight :

<Image>
    <Image.Source>
    <BitmapImage UriSource="ms-appx:///Assets/highresCar.jpg"
                 DecodePixelWidth="300" DecodePixelHeight="200"/>
    </Image.Source>
</Image>

Jednostki dla DecodePixelWidth i DecodePixelHeight są domyślnie pikselami fizycznymi. Ustaw wartość DecodePixelType na Wartość Logiczna , aby rozmiar dekodowania był automatycznie uwzględniany dla bieżącego współczynnika skalowania systemu, podobnie jak w przypadku innego elementu zawartości XAML.

Jeśli nie możesz z góry określić odpowiedniego rozmiaru dekodowania, polegaj na funkcji automatycznego dekodowania do odpowiedniego rozmiaru w XAML, która dokłada starań, aby zdekodować obraz w odpowiednim rozmiarze.

Obrazy używane wewnątrz bitmapiconów wracają do naturalnego rozmiaru

Ustaw jawny rozmiar dekodowania za pomocą właściwości DecodePixelWidth i DecodePixelHeight.

DecodePixelWidth lub DecodePixelHeight są większe niż rozmiar wyświetlania

W przypadku jawnego ustawienia DecodePixelWidth lub DecodePixelHeight większego niż rozmiar ekranu obrazu aplikacja używa dodatkowej pamięci (do 4 bajtów na piksel), co staje się kosztowne w przypadku dużych obrazów.

Obraz jest ukryty

Obraz jest ukryty po ustawieniu Opacity na 0 lub ustawieniu Visibility na Collapsed w elemencie obrazu hosta, pędzlu albo elemencie nadrzędnym. Obrazy niewidoczne na ekranie z powodu przycięcia lub przezroczystości mogą zostać zdekodowane w ich naturalnym rozmiarze.

Obraz używa właściwości NineGrid

W przypadku używania obrazu z usługą NineGrid obraz używa ścieżki rasteryzacji oprogramowania. Wstępnie przeskaluj obrazy do rozmiaru, na który są renderowane.

Zwinięte elementy w czasie ładowania

Typowym wzorcem jest początkowe ukrywanie elementów interfejsu użytkownika i wyświetlanie ich później. W większości przypadków należy odroczyć tworzenie tych elementów za pomocą x:Load, aby uniknąć kosztu związanego z utworzeniem elementu podczas ładowania.

Wpływ

Zwinięte elementy ładują się wraz z innymi elementami i zwiększają czas ładowania.

Solution

Użyj atrybutu x:Load , aby opóźnić ładowanie interfejsu użytkownika. Element jest ładowany, gdy jest potrzebny, co zmniejsza początkowe przetwarzanie. Możesz również użyć x:Bind polecenia , aby kontrolować stan ładowania.

Element ListView nie jest zwirtualizowany

Wirtualizacja interfejsu użytkownika to najważniejsza poprawa wydajności kolekcji. Elementy interfejsu użytkownika reprezentujące elementy są tworzone na żądanie. W przypadku kontrolki powiązanej z kolekcją 1000 elementów tworzenie całego interfejsu użytkownika jednocześnie traci zasoby, ponieważ nie można jednocześnie wyświetlić wszystkich elementów. ListView i GridView obsługują wirtualizację interfejsu użytkownika — generują interfejs użytkownika dla elementów znajdujących się w pobliżu widoku i odzyskują pamięć dla elementów przewiniętych z widoku.

Wpływ

Niezwirtualizowany ItemsControl zwiększa czas ładowania i użycie zasobów przez załadowanie większej liczby elementów podrzędnych niż jest to konieczne.

Solution

Ustaw szerokość i wysokość dla elementu ItemsControl, aby zdefiniować obszar widoku. Gdy umieścisz zwirtualizowaną kontrolkę w panelu z nieograniczoną przestrzenią (na przykład ScrollViewer lub Grid z wierszami o automatycznym rozmiarze), kontrolka zajmie tyle miejsca, aby pomieścić wszystkie elementy, co niweczy działanie wirtualizacji.

Wątek interfejsu użytkownika zablokowany lub bezczynny podczas ładowania

Blokowanie wątku interfejsu użytkownika występuje, gdy synchroniczne wywołania funkcji wykonywanych w innym wątku blokują wątek interfejsu użytkownika. Zapewnij responsywność wątku UI za pomocą asynchronicznych interfejsów API. Aby uzyskać więcej informacji, zobacz Dbanie o responsywność wątku interfejsu użytkownika.

Użyj {x:Bind} zamiast {Binding}

{Binding} używa więcej czasu i pamięci niż {x:Bind}. Utworzenie obiektu {Binding} powoduje serię alokacji, a aktualizacja miejsca docelowego powiązania może obejmować użycie mechanizmu refleksji i opakowywanie. Użyj {x:Bind}, co pozwala kompilować powiązania w czasie kompilacji, zapewniając lepszą wydajność i weryfikację podczas kompilacji.

Note

{x:Bind} nie jest odpowiedni dla wszystkich przypadków, takich jak scenariusze związane z późnym opóźnieniem. Aby uzyskać szczegółowe informacje, zobacz dokumentację programu {x:Bind} .

Użyj x:Key zamiast x:Name w słownikach zasobów

Gdy używasz x:Name w odniesieniu do zasobu, platforma natychmiast tworzy jego instancję, ponieważ x:Name tworzy odwołanie do pola. Użyj zamiast tego x:Key, jeśli nie musisz odwoływać się do zasobu z kodu zaplecza.

Używanie paneli wirtualizacji dla kolekcji

Jeśli podasz szablon panelu elementów niestandardowych (zobacz ItemsPanel), użyj panelu wirtualizacji, takiego jak ItemsWrapGrid lub ItemsStackPanel. Używanie metody VariableSizedWrapGrid, WrapGridlub StackPanel wyłącza wirtualizację.

Ułatwienia dostępu: nadaj nazwy elementom UIA

Ustaw AutomationProperties.Name w kodzie XAML kontrolki na odpowiedni zlokalizowany ciąg. Jeśli element nie powinien być wyświetlany w drzewie UIA, ustaw wartość AutomationProperties.AccessibilityView = "Raw".

Unikaj nadawania dwóm elementom UIA z tym samym elementem nadrzędnym tych samych wartości Name i ControlType. Na listach, na których często występują powtarzające się nazwy, użyj powiązania, aby ustawić AutomationProperties.Name na podstawie źródła danych.