Poznámka:
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
Analýza aplikací je nástroj, který vývojářům poskytuje oznámení o problémech s výkonem. Analýza aplikace spouští kód aplikace na základě sady pokynů k výkonu a osvědčených postupů.
Analýza aplikací identifikuje problémy ze sady pravidel běžných problémů s výkonem, na které aplikace narazí. V případě potřeby bude analýza aplikací odkazovat na nástroj časové osy sady Visual Studio, informace o zdroji a dokumentaci, které vám poskytnou prostředky k prozkoumání.
Pravidla v analýze aplikací odkazují na vodítko nebo osvědčený postup, kterým se vaše aplikace kontroluje.
Dekódovaná velikost obrázku větší než velikost vykreslení
Obrázky se zaznamenávají ve velmi vysokém rozlišení, což může vést k tomu, že aplikace při dekódování dat obrázku a více paměti po načtení z disku využívají více procesoru. Nedává smysl dekódovat a uložit obrázek s vysokým rozlišením do paměti, pokud ho pak zobrazíte v menším rozměru, než je jeho původní velikost. Místo toho vytvořte verzi obrázku s přesnou velikostí, která bude nakreslena na obrazovce pomocí vlastností DecodePixelWidth a DecodePixelHeight.
Dopad
Zobrazení imagí v jiných než nativních velikostech může negativně ovlivnit čas procesoru (kvůli dekódování na správnou velikost a čas stahování) a paměti.
Příčiny a řešení
Obrázek se nenastavuje asynchronně
Aplikace místo SetSourceAsync() používá SetSource(). Vždy byste se měli vyhnout použití SetSource a místo toho použít SetSourceAsync při nastavování datového proudu dekódovat obrázky asynchronně.
K obrázku je přistupováno, když ImageSource není součástí aktivního stromu.
BitmapImage je připojen k živému stromu XAML po nastavení obsahu pomocí SetSourceAsync nebo UriSource. Před nastavením zdroje byste vždy měli k živému stromu připojit BitmapImage. Pokaždé, když je prvek obrázku nebo štětec zadán v kódu, bude to automaticky případ. Příklady jsou uvedené níže.
Příklady živých stromů
Příklad 1 (dobrý) – identifikátor URI (Uniform Resource Identifier) zadaný v kódu
<Image x:Name="myImage" UriSource="Assets/cool-image.png"/>
Příklad 2 kódu značkování – URI specifikováno v kódu na pozadí.
<Image x:Name="myImage"/>
Příklad 2 vnitřního kódu (dobrý) – připojení BitmapImage ke stromu před nastavením jeho Uri zdroje.
var bitmapImage = new BitmapImage();
myImage.Source = bitmapImage;
bitmapImage.UriSource = new URI("ms-appx:///Assets/cool-image.png", UriKind.RelativeOrAbsolute);
Příklad 2 v zákulisí kódu (špatný) – nastavování UriSource BitmapImage před připojením ke stromu.
var bitmapImage = new BitmapImage();
bitmapImage.UriSource = new URI("ms-appx:///Assets/cool-image.png", UriKind.RelativeOrAbsolute);
myImage.Source = bitmapImage;
Obrázkový štětec není obdélníkový
Při použití obrázku pro neobdélníkový štětec obrázek použije softwarovou rasterizační cestu, která obrázky nebude vůbec škálovat. Kromě toho musí uložit kopii image do softwarové i hardwarové paměti. Pokud je například obrázek použit jako štětec pro elipsu, potenciálně velký celý obrázek se interně uloží dvakrát. Při použití neúdvoúhlého štětce by vaše aplikace měla předem škálovat obrázky na velikost, na kterou se budou vykreslovat.
Případně můžete nastavit explicitní dekódovací velikost pomocí vlastností DecodePixelWidth a DecodePixelHeight k vytvoření verze obrázku v přesné velikosti, kterou bude kreslen na obrazovce.
<Image>
<Image.Source>
<BitmapImage UriSource="ms-appx:///Assets/highresCar.jpg"
DecodePixelWidth="300" DecodePixelHeight="200"/>
</Image.Source>
</Image>
Jednotky pro DecodePixelWidth a DecodePixelHeight jsou ve výchozím nastavení fyzické pixely. Vlastnost DecodePixelType lze použít ke změně tohoto chování: nastavení DecodePixelType na Logické vede k automatickému účtování velikosti dekódování aktuálního faktoru škálování systému, podobně jako u jiného obsahu XAML. Proto by bylo obecně vhodné nastavit DecodePixelType na Logical, pokud například chcete, aby DecodePixelWidth a DecodePixelHeight odpovídaly vlastnostem výšky a šířky ovládacího prvku obrázku, ve kterém bude obrázek zobrazen. Při výchozím chování při použití fyzických pixelů musíte zohlednit aktuální faktor škálování systému sami a v případě, že uživatel změní předvolby zobrazení, měli byste naslouchat oznámením o změnách měřítka.
V některých případech, kdy nelze předem určit odpovídající velikost dekódování, byste se měli spolehnout na automatické dekódování vhodné velikosti v XAMLu, které se pokusí dekódovat obraz na odpovídající velikost, pokud není explicitně zadán DecodePixelWidth/DecodePixelHeight.
Pokud znáte velikost obsahu obrázku předem, měli byste nastavit explicitní dekódovací velikost. Měli byste také v kombinaci nastavit DecodePixelType na logické, pokud je zadaná velikost dekódování relativní k jiným velikostem elementů XAML. Pokud například explicitně nastavíte velikost obsahu pomocí Image.Width a Image.Height, můžete DecodePixelType nastavit na DecodePixelType.Logical, aby se použily stejné logické pixelové rozměry jako control Image, a pak explicitně použít BitmapImage.DecodePixelWidth a/nebo BitmapImage.DecodePixelHeight, aby se určila velikost obrázku a dosáhlo se tak potenciálně velkých úspor paměti.
Všimněte si, že Při určování velikosti dekódovaného obsahu by se měla zvážit možnost Image.Stretch.
Obrázky používané uvnitř BitmapIcons se vrátí k dekódování na přirozenou velikost
Nastavte explicitní dekódovací velikost pro vytvoření verze obrázku s přesnou velikostí, kterou bude kreslit na obrazovce, pomocí vlastností DecodePixelWidth a DecodePixelHeight.
Obrázky, které se na obrazovce zobrazují velmi velké, se vrátí k dekódování na přirozenou velikost
Obrázky, které se na obrazovce zobrazují velmi velké, se vrátí k dekódování na přirozenou velikost. Nastavte explicitní dekódovací velikost pro vytvoření verze obrázku s přesnou velikostí, kterou bude kreslit na obrazovce, pomocí vlastností DecodePixelWidth a DecodePixelHeight.
Obrázek je skrytý.
Obrázek je skrytý nastavením neprůhlednosti na 0 nebo viditelnosti na 'zneviditelněno' na hostitelském prvku obrázku, štětce nebo jakéhokoli nadřazeného prvku. Obrázky, které nejsou na obrazovce viditelné kvůli výřezu nebo průhlednosti, se můžou vrátit k dekódování na přirozenou velikost.
Image používá vlastnost NineGrid
Pokud se obrázek používá pro NineGrid, obrázek bude používat softwarovou rasterizační cestu, která obrázky vůbec nebude škálovat. Kromě toho musí uložit kopii image do softwarové i hardwarové paměti. Při použití NineGridby vaše aplikace měla předem přizpůsobit velikost svých obrázků přibližně na tu, ve které se budou vykreslovat.
Obrázky, které používají vlastnost NineGrid, se vrátí k dekódování na přirozenou velikost. Zvažte přidání efektu ninegrid do původního obrázku.
DecodePixelWidth nebo DecodePixelHeight jsou nastaveny na velikost větší než obrázek se zobrazí na obrazovce.
Pokud jsou DecodePixelWidth/Height explicitně nastaveny větší než obrázek, který se zobrazí na obrazovce, bude aplikace zbytečně používat nadbytečnou paměť až 4 bajty na pixel, což se u velkých obrázků rychle stane nákladným. Obrázek bude také zmenšen pomocí bilineárního škálování, což by mohlo způsobit, že se bude jevit rozmazaně pro vysoké faktory škálování.
Obrázek je dekódován při vytváření obrázku pro přetahování.
Nastavte explicitní dekódovací velikost pro vytvoření verze obrázku s přesnou velikostí, kterou bude kreslit na obrazovce, pomocí vlastností DecodePixelWidth a DecodePixelHeight.
Sbalené prvky při načítání
Běžným vzorem v aplikacích je zpočátku skrytí prvků v uživatelském rozhraní a jejich pozdější zobrazení. Ve většině případů by se tyto prvky měly odložit pomocí x:Load nebo x:DeferLoadStrategy, aby se zabránilo placení nákladů na vytvoření prvku v době načtení.
To zahrnuje případy, kdy se k skrytí položek do pozdějšího času používá logický převaděč viditelnosti.
Dopad
Sbalené prvky se načítají spolu s ostatními prvky a přispívají ke zvýšení doby načítání.
Příčina
Toto pravidlo se aktivovalo, protože prvek byl při načítání sbalený. Sbalení elementu nebo nastavení jeho neprůhlednosti na hodnotu 0 nezabrání vytvoření prvku. Toto pravidlo může být způsobeno aplikací, která používá převodník logických hodnot na viditelnost, jenž má výchozí hodnotu nepravda.
Řešení
Pomocí atributu x:Load nebo x:DeferLoadStrategymůžete zpozdit načítání části uživatelského rozhraní a v případě potřeby ho načíst. Je to dobrý způsob, jak zpozdit zpracování uživatelského rozhraní, které není viditelné v prvním snímku. Můžete se rozhodnout načíst prvek podle potřeby, nebo jako součást sady zpožděné logiky. Chcete-li spustit načítání, zavolejte funkci findName na elementu, který chcete načíst. x:Load rozšiřuje možnosti x:DeferLoadStrategy, čímž umožňuje odložení načítání prvků a ovládání stavu načítání prostřednictvím x:Bind.
V některých případech nemusí být odpovědí použití funkce findName k zobrazení části uživatelského rozhraní. To platí, pokud očekáváte, že na kliknutí na tlačítko s velmi nízkou latencí zjistíte významnou část uživatelského rozhraní. V tomto případě můžete chtít vyměnit rychlejší odezvu uživatelského rozhraní za cenu zvýšeného využití paměti; pokud ano, měli byste použít x:DeferLoadStrategy a nastavit Viditelnost na Skrytý u prvku, který chcete realizovat. Po načtení stránky a uvolnění vlákna uživatelského rozhraní můžete podle potřeby zavolat funkci findName k načtení prvků. Prvky nebudou uživateli viditelné, dokud nenastavíte viditelnost prvku na Visible.
ListView není virtualizovaný
Virtualizace uživatelského rozhraní je nejdůležitější vylepšení, které můžete provést ke zlepšení výkonu sbírky. To znamená, že prvky uživatelského rozhraní představující položky se vytvářejí na vyžádání. U ovládacího prvku položky vázaného na kolekci 1000 položek by to bylo plýtvání prostředky k vytvoření uživatelského rozhraní pro všechny položky najednou, protože se nedají zobrazit ve stejnou dobu. ListView a GridView (a další standardní ovládací prvky odvozené od ItemsControl) provádějí virtualizaci uživatelského rozhraní za vás. Když jsou položky blízko k tomu, aby byly viditelné po posunu stránky (pár stránek dopředu), rámec vygeneruje uživatelské rozhraní pro tyto položky a uloží je do mezipaměti. Pokud je nepravděpodobné, že se položky znovu zobrazí, rámec uvolňuje paměť.
Virtualizace uživatelského rozhraní je jen jedním z několika klíčových faktorů pro zlepšení výkonu kolekce. Snížení složitosti položek kolekce a virtualizace dat jsou dalšími dvěma důležitými aspekty zlepšení výkonu kolekce. Další informace o zlepšení výkonu kolekce v ListViews a GridViews naleznete v článcích o Optimalizace uživatelského rozhraní ListView a GridView a Virtualizace dat ListView a GridView.
Dopad
Nevirtualizovaný ovládací prvek ItemsControl zvýší čas načítání a spotřebu prostředků tím, že načte více podřízených položek, než je nutné.
Příčina
Koncept oblasti zobrazení je pro virtualizaci uživatelského rozhraní kritický, protože architektura musí vytvořit prvky, které se budou pravděpodobně zobrazovat. Obecně platí, že oblast zobrazení ItemsControl je rozsah logického ovládacího prvku. Například oblast zobrazení ListView je šířka a výška prvku ListView. Některé panely umožňují podřízeným prvkům neomezený prostor, jako jsou například ScrollViewer a Grid s řádky nebo sloupci, které se automaticky přizpůsobují velikosti. Když je virtualizovaný ItemsControl umístěn na panelu, jako ten, zabírá dostatek místa, aby zobrazil všechny své položky, což ruší virtualizaci.
Řešení
Obnovte virtualizaci nastavením šířky a výšky na itemsControl, který používáte.
Vlákno uživatelského rozhraní během načítání blokováno nebo nečinné
Blokování vlákna uživatelského rozhraní se týká synchronních volání funkcí, které se vykonávají v jiném vlákně a blokují vlákno uživatelského rozhraní.
Úplný seznam osvědčených postupů pro zlepšení výkonu při spuštění aplikace najdete v tématu Osvědčené postupy pro zlepšení výkonu při spuštění vaší aplikace a Udržování vlákna uživatelského rozhraní responzivního.
Dopad
Blokované nebo nečinné vlákno uživatelského rozhraní během načítání zabrání rozložení a dalším operacím uživatelského rozhraní, což zvýší dobu spuštění.
Příčina
Kód platformy pro uživatelské rozhraní a kód vaší aplikace pro uživatelské rozhraní se spouští ve stejném vlákně uživatelského rozhraní. Na daném vlákně se může spustit pouze jedna instrukce, takže pokud zpracování události trvá příliš dlouho, architektura nemůže spustit rozložení nebo vyvolat nové události představující interakci uživatele. Rychlost odezvy aplikace souvisí s dostupností vlákna uživatelského rozhraní pro zpracování.
Řešení
Vaše aplikace může být interaktivní, i když existují části aplikace, které nejsou plně funkční. Pokud například vaše aplikace zobrazuje data, která nějakou dobu trvá načtení, můžete tento kód provést nezávisle na spouštěcím kódu aplikace načtením dat asynchronně. Jakmile jsou data dostupná, naplňte uživatelské rozhraní aplikace daty. Aby byla aplikace responzivní, poskytuje platforma asynchronní verze mnoha jeho rozhraní API. Asynchronní rozhraní API zajišťuje, že vaše aktivní prováděcí vlákno se nikdy po dlouhou dobu nezablokuje. Při volání rozhraní API z vlákna uživatelského rozhraní použijte asynchronní verzi, pokud je k dispozici.
{Binding} se používá místo {x:Bind}
Toto pravidlo je aktivováno, když vaše aplikace používá deklaraci {Binding}. Aby se zlepšil výkon aplikace, měli byste zvážit použití aplikace {x:Bind}.
Dopad
{Binding} běží déle a spotřebovává více paměti než {x:Bind}.
Příčina
Aplikace místo {x:Bind} používá {Binding}. {Binding} s sebou nese netriviální pracovní sadu a režii procesoru. Vytvoření {Binding} způsobí řadu přidělení a aktualizace cíle vazby může způsobit reflexi a balení.
Řešení
Použijte rozšíření značek {x:Bind}, které vazby kompiluje v době sestavení. Vazby {x:Bind} (často označované jako kompilované vazby) mají skvělý výkon, zajišťují ověřování v době kompilace pro výrazy vazby a podporují ladění tím, že umožňují nastavit zarážky v souborech kódu generovaných jako částečnou třídu pro vaši stránku.
Všimněte si, že x:Bind není vhodný ve všech případech, jako jsou scénáře s pozdní vazbou. Pro úplný seznam případů, které nejsou pokryty funkcí {x:Bind}, viz dokumentaci k {x:Bind}.
x:Name se používá místo x:Key.
Slovníky prostředků se obvykle používají k ukládání prostředků na poněkud globální úrovni, tedy prostředků, na které vaše aplikace chce odkazovat na více míst; například styly, štětce, šablony atd. Obecně jsme optimalizovali ResourceDictionaries tak, aby nevytvářely instance prostředků, pokud nejsou vyžádány. Ale existuje několik míst, kde musíte být trochu opatrní.
Dopad
Jakmile je vytvořen ResourceDictionary, jakýkoli prostředek s x:Name bude inicializován. K tomu dochází, protože x:Name platformě říká, že vaše aplikace potřebuje přístup na úrovni pole k tomuto prostředku, takže platforma musí vytvořit něco, na co bude možné se odkazovat.
Příčina
Vaše aplikace nastavuje pro prostředek x:Name.
Řešení
Místo x:Name použijte x:Key, pokud neodkazujete na prostředky z backendového kódu.
Ovládací prvek Kolekce používá ne virtualizační panel.
Pokud zadáte vlastní šablonu panelu položek (viz ItemsPanel), ujistěte se, že používáte virtualizační panel, například ItemsWrapGrid nebo ItemsStackPanel. Pokud používáte VariableSizedWrapGrid, WrapGrid nebo StackPanel, nebudete dostávat virtualizaci. Kromě toho jsou následující události ListView vyvolány pouze při použití ItemsWrapGrid nebo ItemsStackPanel: ChoosingGroupHeaderContainer, ChoosingItemContainer a ContainerContentChanging.
Virtualizace uživatelského rozhraní je nejdůležitější vylepšení, které můžete provést ke zlepšení výkonu sbírky. To znamená, že prvky uživatelského rozhraní představující položky se vytvářejí na vyžádání. U ovládacího prvku položky vázaného na kolekci 1000 položek by to bylo plýtvání prostředky k vytvoření uživatelského rozhraní pro všechny položky najednou, protože se nedají zobrazit ve stejnou dobu. ListView a GridView (a další standardní ovládací prvky odvozené od ItemsControl) provádějí virtualizaci uživatelského rozhraní za vás. Když jsou položky blízko k tomu, aby byly viditelné po posunu stránky (pár stránek dopředu), rámec vygeneruje uživatelské rozhraní pro tyto položky a uloží je do mezipaměti. Pokud je nepravděpodobné, že se položky znovu zobrazí, rámec uvolňuje paměť.
Virtualizace uživatelského rozhraní je jen jedním z několika klíčových faktorů pro zlepšení výkonu kolekce. Snížení složitosti položek kolekce a virtualizace dat jsou dalšími dvěma důležitými aspekty zlepšení výkonu kolekce. Další informace o zlepšení výkonu kolekce v ListViews a GridViews naleznete v článcích o Optimalizace uživatelského rozhraní ListView a GridView a Virtualizace dat ListView a GridView.
Dopad
Nevirtualizovaný ovládací prvek ItemsControl zvýší čas načítání a spotřebu prostředků tím, že načte více podřízených položek, než je nutné.
Příčina
Používáte panel, který nepodporuje virtualizaci.
Řešení
Použijte virtualizační panel, například ItemsWrapGrid nebo ItemsStackPanel.
Přístupnost: Prvky UIA bez názvu
V jazyce XAML můžete zadat název nastavením AutomationProperties.Name. Mnoho automatizačních uzlů poskytuje výchozí jméno UIA, pokud AutomationProperties.Name není nastaven.
Dopad
Pokud uživatel dosáhne prvku bez názvu, často nebude mít žádný způsob, jak zjistit, k čemu se prvek vztahuje.
Příčina
Název UIA elementu je null nebo prázdný. Toto pravidlo zkontroluje, co UIA vidí, nikoliv hodnotu AutomationProperties.Name.
Řešení
Nastavte vlastnost AutomationProperties.Name v kódu XAML ovládacího prvku na odpovídající lokalizovaný řetězec.
Někdy správná úprava aplikace není v zadání názvu, ale v odstranění prvku UIA ze všech stromů kromě těch nezpracovaných. To můžete udělat v XAML nastavením AutomationProperties.AccessibilityView = "Raw".
Přístupnost: Prvky UIA se stejným typem Control by neměly mít stejný název.
Dva prvky UIA se stejným nadřazeným objektem UIA nesmí mít stejný název a ControlType. Pokud mají různé typy ControlType, je v pořádku mít dva ovládací prvky se stejným názvem.
Toto pravidlo nekontroluje duplicitní jména s různými nadřazenými prvky. Ve většině případů byste ale neměli duplikovat názvy a typy ControlType v celém okně, a to ani u různých nadřazených prvků. Případy, kdy jsou duplicitní názvy v okně přijatelné, jsou dva seznamy s identickými položkami. V tomto případě se očekává, že položky seznamu budou mít identické názvy a typy ControlType.
Dopad
Pokud uživatel dosáhne prvku se stejným názvem a ControlType jako jiný prvek se stejným nadřazeným prvkem UIA, uživatel nemusí být schopen rozlišit rozdíl mezi prvky.
Příčina
Prvky UIA se stejným nadřazeným objektem UIA mají stejný název a ControlType.
Řešení
Nastavte název v JAZYCE XAML pomocí AutomationProperties.Name. V seznamech, kde k tomu běžně dochází, použijte vazbu k vytvoření vazby hodnoty AutomationProperties.Name ke zdroji dat.