XAML-betöltés optimalizálása WinUI és Windows App SDK esetén

Az XAML-jelölés elemzése az objektumok memóriában való létrehozásához időigényes egy összetettebb felhasználói felület esetében. Az alábbiakban néhány dolgot tehet az XAML-korrektúra elemzési és betöltési idejének, valamint a WinUI-alkalmazás memóriahatékonyságának javításához.

Az alkalmazás indításakor korlátozza a betöltött XAML jelölést, amelyre csak a kezdeti felhasználói felülethez van szükség. Vizsgálja meg a kezdeti oldalon található korrektúrát, beleértve a laperőforrásokat is, és győződjön meg arról, hogy nem tölt be azonnal felesleges elemeket. Ezek az elemek számos forrásból származhatnak, például erőforrás-szótárakból, kezdetben elrejtett állapotban lévő elemekből és más elemek fölé rajzolt elemekből.

Az XAML hatékonyságának optimalizálása kompromisszumot igényel; nincs mindig egyetlen megoldás minden helyzetben. Itt áttekintünk néhány gyakori problémát, és útmutatást adunk a WinUI-alkalmazás megfelelő kompromisszumoinek eléréséhez.

Elemek számának minimalizálása

Bár az XAML platform nagy számú elem megjelenítésére képes, az alkalmazás a kívánt vizualizációk eléréséhez szükséges legkevesebb elem használatával gyorsabban elrendezhető és renderelhető.

A felhasználói felület vezérlőinek elrendezésében meghozott döntések befolyásolják az alkalmazás indításakor létrehozott felhasználói felületi elemek számát. Az elrendezés optimalizálásáról további információt az XAML-elrendezés optimalizálása című témakörben talál.

Az elemszám rendkívül fontos az adatsablonokban, mert minden elem újra létrejön az egyes adatelemekhez. A lista vagy rács elemszámának csökkentéséről további információt a WinUI-ra vonatkozó ListView és GridView teljesítmény optimalizálása című cikkben talál.

Itt bemutatunk néhány egyéb módszert, amelyekkel csökkentheti az alkalmazás indításkor betöltendő elemeinek számát.

Elem létrehozásának halasztás

Ha az XAML-jelölés olyan elemeket tartalmaz, amelyeket nem jelenít meg azonnal, elhalaszthatja az elemek betöltését, amíg azokat meg nem jeleníti. Késleltetheti például a nem látható tartalmak, például egy másodlagos lap létrehozását egy tabulátorszerű felhasználói felületen. Előfordulhat, hogy alapértelmezés szerint rács nézetben jeleníti meg az elemeket, de megadhat egy lehetőséget, hogy a felhasználó ehelyett egy listában tekinthesse meg az adatokat. Ha szükséges, késleltetheti a lista betöltését.

A Láthatóság tulajdonság helyett az x:Load attribútummal szabályozhatja, hogy mikor jelenjen meg egy elem. Amikor egy elem láthatósága Összecsukva értékre van állítva, az a renderelési folyamat során ki van hagyva, de az objektumpéldány költségeit továbbra is meg kell fizetni a memóriában. Ha inkább x:Load parancsot használ, a keretrendszer csak akkor hozza létre az objektumpéldányt, ha szükség van rá, így a memóriaköltségek még alacsonyabbak. A hátránya, hogy kis memóriaterhelést (körülbelül 600 bájtot) kell fizetnie, ha a felhasználói felület nincs betöltve.

Megjegyzés:

A Windows App SDK-ban az x:Load a javasolt késleltetett betöltési minta az XAML-tartalomhoz, amelyre nincs szükség azonnal.

Az alábbi példák az elemek számának és a memóriahasználatnak a különbségét mutatják, ha a felhasználói felület elemeinek elrejtésére különböző technikákat használnak. Az azonos elemeket tartalmazó ListView és GridView a lap gyökérrácsába kerül. A ListView nem látható, de megjelenik a GridView. Az ezekben a példákban szereplő XAML ugyanazt a felhasználói felületet hozza létre a képernyőn. A profilkészítéshez és a teljesítményhez használható eszközökkel ellenőrizheti az elemek számát és a memóriahasználatot az alkalmazásban.

1. lehetőség – Nem hatékony

Itt a ListView be van töltve, de nem látható, mert Width az 0. A ListView és annak minden gyermekeleme a vizualizációfán jön létre, és betöltődik a memóriába.

<!-- NOTE: EXAMPLE OF INEFFICIENT CODE; DO NOT COPY-PASTE. -->
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">

    <ListView x:Name="List1" Width="0">
        <ListViewItem>Item 1</ListViewItem>
        <ListViewItem>Item 2</ListViewItem>
        <ListViewItem>Item 3</ListViewItem>
        <ListViewItem>Item 4</ListViewItem>
        <ListViewItem>Item 5</ListViewItem>
        <ListViewItem>Item 6</ListViewItem>
        <ListViewItem>Item 7</ListViewItem>
        <ListViewItem>Item 8</ListViewItem>
        <ListViewItem>Item 9</ListViewItem>
        <ListViewItem>Item 10</ListViewItem>
    </ListView>

    <GridView x:Name="Grid1">
        <GridViewItem>Item 1</GridViewItem>
        <GridViewItem>Item 2</GridViewItem>
        <GridViewItem>Item 3</GridViewItem>
        <GridViewItem>Item 4</GridViewItem>
        <GridViewItem>Item 5</GridViewItem>
        <GridViewItem>Item 6</GridViewItem>
        <GridViewItem>Item 7</GridViewItem>
        <GridViewItem>Item 8</GridViewItem>
        <GridViewItem>Item 9</GridViewItem>
        <GridViewItem>Item 10</GridViewItem>
    </GridView>
</Grid>

Élő vizualizációfa a ListView betöltéssel. Az oldal teljes elemszáma 89.

Képernyőkép a vizualizációfáról listanézettel.

A ListView és az alárendelt elemek be vannak töltve a memóriába.

Képernyőkép a Managed Memory Test App 1.exe tábláról, amely azt mutatja, hogy a ListView és annak gyermekei betöltődnek a memóriába.

2. lehetőség – Jobb

Itt a ListView Visibility beállítása Collapsed értékre történt (a többi XAML megegyezik az eredetivel). A ListView a vizuális fában jön létre, gyermekelemeit azonban nem hozza létre. Ezek azonban továbbra is betöltve vannak a memóriába, így a memóriahasználat megegyezik az előző példával.

<ListView x:Name="List1" Visibility="Collapsed">

Élő vizuális fa, amely össze van csukva a ListView-val. Az oldal teljes elemszáma 46.

Képernyőkép a vizualizációfáról összecsukott listanézettel.

A ListView és gyermekei betöltve vannak a memóriába.

Frissített képernyőkép a Managed Memory Test App 1. E X E táblájáról, amelyen a ListView és annak gyermekei be vannak töltve a memóriába.

3. lehetőség – Leghatékonyabb

Itt a ListView x:Load attribútumát False értékre állították (a másik XAML az eredetivel megegyezik). A ListView nem jön létre a vizualizációfán, és nem töltődik be a memóriába indításkor.

<ListView x:Name="List1" Visibility="Collapsed" x:Load="False">

Élő vizualizációfa, amelyen nincs betöltve a ListView. Az oldal teljes elemszáma 45.

Vizuális fa listanézettel nem került betöltésre

A ListView és komponensei nincsenek betöltve a memóriába.

Vizuális fa listanézettel

Megjegyzés:

Az elemek száma és a memóriahasználat ezekben a példákban nagyon kicsi, és csak a koncepció bemutatására mutat. Ezekben a példákban az x:Load használata nagyobb, mint a memóriamegtakarítás, így az alkalmazás nem járna előnyökkel. Az alkalmazás profilkészítési eszközeivel állapítsa meg, hogy a késleltetett betöltés segít-e.

Elrendezéspanel tulajdonságainak használata

Az elrendezéspanelek háttértulajdonságúak , ezért nem kell téglalapot elhelyezni a panel elé csak színezéshez.

Hatékony

<!-- NOTE: EXAMPLE OF INEFFICIENT CODE; DO NOT COPY-PASTE. -->
<Grid>
    <Rectangle Fill="Black"/>
</Grid>

Hatékony

<Grid Background="Black"/>

Az elrendezéspanelek beépített szegélytulajdonságokat is rendelkeznek, ezért nem kell szegélyelemet elhelyeznie az elrendezéspanelen. További információkért és példákért tekintse meg az XAML-elrendezés optimalizálása című témakört.

Képek használata vektoralapú elemek helyett

Ha elégszer újra felhasználja ugyanazt a vektoralapú elemet, hatékonyabb lesz a képelem használata. A vektoralapú elemek drágábbak lehetnek, mivel a CPU-nak külön kell létrehoznia az egyes elemeket. A képfájlt csak egyszer kell dekódolni.

Erőforrások és erőforrás-szótárak optimalizálása

Általában erőforrásszótárak használatával tárolhatja az alkalmazás több pontján hivatkozni kívánt erőforrásokat valamelyest globális szinten. Stílusok, ecsetek, sablonok stb.

A ResourceDictionary általában úgy van optimalizálva, hogy elkerülje az erőforrások példányosítását, amíg a rendszer nem kéri őket. Vannak azonban olyan helyzetek, amelyeket el kell kerülnie, hogy az erőforrások ne legyenek szükségtelenül példányosítva.

X:Névvel rendelkező erőforrások

Az x:Key attribútummal hivatkozhat az erőforrásokra. Az x:Name attribútummal rendelkező erőforrások nem fogják kihasználni a platformoptimalizálás előnyeit; ehelyett a ResourceDictionary létrehozása után azonnal példányosítva lesz. Ez azért történik, mert az x:Name azt jelzi a platformnak, hogy az alkalmazásnak mezőhozzáférésre van szüksége ehhez az erőforráshoz, ezért a platformnak létre kell hoznia valamit, hogy hivatkozhasson rá.

ResourceDictionary a UserControlban

A UserControlban definiált ResourceDictionary büntetést von maga után. A platform létrehozza az ilyen ResourceDictionary másolatát a UserControl minden példányához. Ha olyan UserControlt használ, amelyet sokat használ, helyezze ki a ResourceDictionaryt a UserControlból, és helyezze az oldalszintre.

Erőforrás- és ResourceDictionary-hatókör

Ha egy lap egy másik fájlban definiált felhasználói vezérlőre vagy erőforrásra hivatkozik, akkor a keretrendszer ezt a fájlt is elemzi.

Mivel az InitialPage.xaml az ExampleResourceDictionary.xaml egyik erőforrását használja, az ExampleResourceDictionary.xaml egészét az indításkor kell elemezni.

InitialPage.xaml

<Page x:Class="ExampleNamespace.InitialPage" ...>
    <Page.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="ExampleResourceDictionary.xaml"/>
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Page.Resources>

    <Grid>
        <TextBox Foreground="{StaticResource TextBrush}"/>
    </Grid>
</Page>

ExampleResourceDictionary.xaml

<ResourceDictionary>
    <SolidColorBrush x:Key="TextBrush" Color="#FF3F42CC"/>

    <!--This ResourceDictionary contains many other resources that
        are used in the app, but are not needed during startup.-->
</ResourceDictionary>

Ha az alkalmazás számos oldalán használ erőforrást, akkor az App.xaml-ben való tárolása ajánlott, és elkerüli a duplikációt. Az App.xaml azonban az alkalmazás indításakor van elemezve, ezért minden olyan erőforrást, amelyet csak egy oldalon használnak, kivéve, ha ez a lap a kezdeti oldal, a lap helyi erőforrásaiba kell helyezni. Ebben a példában az App.xaml olyan erőforrásokat mutat be, amelyeket csak egy olyan oldal használ, amely nem a kezdeti oldal. Ez szükségtelenül növeli az indítási időt.

App.xaml

<!-- NOTE: EXAMPLE OF INEFFICIENT CODE; DO NOT COPY-PASTE. -->
<Application ...>
     <Application.Resources>
        <SolidColorBrush x:Key="DefaultAppTextBrush" Color="#FF3F42CC"/>
        <SolidColorBrush x:Key="InitialPageTextBrush" Color="#FF3F42CC"/>
        <SolidColorBrush x:Key="SecondPageTextBrush" Color="#FF3F42CC"/>
        <SolidColorBrush x:Key="ThirdPageTextBrush" Color="#FF3F42CC"/>
    </Application.Resources>
</Application>

InitialPage.xaml

<!-- NOTE: EXAMPLE OF INEFFICIENT CODE; DO NOT COPY-PASTE. -->
<Page x:Class="ExampleNamespace.InitialPage" ...>
    <StackPanel>
        <TextBox Foreground="{StaticResource InitialPageTextBrush}"/>
    </StackPanel>
</Page>

SecondPage.xaml

<!-- NOTE: EXAMPLE OF INEFFICIENT CODE; DO NOT COPY-PASTE. -->
<Page x:Class="ExampleNamespace.SecondPage" ...>
    <StackPanel>
        <Button Content="Submit" Foreground="{StaticResource SecondPageTextBrush}"/>
    </StackPanel>
</Page>

A példa hatékonyabbá tétele érdekében lépjen SecondPageTextBrush a SecondPage.xaml fájlba, és lépjen ThirdPageTextBrush a ThirdPage.xaml fájlba. InitialPageTextBrush az App.xaml-ben maradhat, mert az alkalmazás erőforrásait minden esetben elemezni kell az alkalmazás indításakor.

Több, azonosnak tűnő ecsetet vonj össze egy erőforrásként.

Az XAML platform megpróbálja gyorsítótárazni a gyakran használt objektumokat, hogy a lehető leggyakrabban újra felhasználhatók legyenek. Az XAML azonban nem tudja könnyen megállapítani, hogy az egyik jelölőelemben deklarált ecset megegyezik-e a másikban deklarált ecsettel. Az alábbi példa a SolidColorBrush használatával mutatja be, de a GradientBrush esetében az eset valószínűbb és fontosabb. Ellenőrizze az előre definiált színeket használó keféket is; például "Orange""#FFFFA500" ugyanaz a szín.

Hatékony

<!-- NOTE: EXAMPLE OF INEFFICIENT CODE; DO NOT COPY-PASTE. -->
<Page ... >
    <StackPanel>
        <TextBlock>
            <TextBlock.Foreground>
                <SolidColorBrush Color="#FFFFA500"/>
            </TextBlock.Foreground>
        </TextBlock>
        <Button Content="Submit">
            <Button.Foreground>
                <SolidColorBrush Color="#FFFFA500"/>
            </Button.Foreground>
        </Button>
    </StackPanel>
</Page>

A duplikáció kijavításához definiálja az ecsetet erőforrásként. Ha más lapok vezérlői ugyanazt az ecsetet használják, helyezze át az App.xaml fájlba.

Hatékony

<Page ... >
    <Page.Resources>
        <SolidColorBrush x:Key="BrandBrush" Color="#FFFFA500"/>
    </Page.Resources>

    <StackPanel>
        <TextBlock Foreground="{StaticResource BrandBrush}" />
        <Button Content="Submit" Foreground="{StaticResource BrandBrush}" />
    </StackPanel>
</Page>

Túlrajzolás minimalizálása

A túlméretezettség akkor fordul elő, ha egynél több objektumot rajzolnak ugyanabban a képernyő-képpontban. Vegye figyelembe, hogy néha van kompromisszum ezen útmutató és az elemek számának minimalizálásának igénye között.

Használja a DebugSettings.IsOverdrawHeatMapEnabled-t, mint vizuális diagnosztikai eszközt. Előfordulhat, hogy olyan tárgyakat rajzolnak meg, amelyekről nem tudta, hogy a jelenetben voltak.

Áttetsző vagy rejtett elemek

Ha egy elem nem látható, mert transzparens vagy rejtett más elemek mögött, és nem járul hozzá az elrendezéshez, törölje. Ha az elem nem látható a kezdeti vizualizációs állapotban, de más vizualizációs állapotokban is látható, akkor az x:Betöltés funkcióval szabályozhatja az állapotát, vagy beállíthatja , hogy a Láthatóság összecsukva legyen az elemen, és módosítsa az értéket Látható értékre a megfelelő állapotokban. Erre a heurisztikára vannak kivételek: általában az az érték, amelyet egy tulajdonság a vizuális állapotok többségében birtokol, a legjobb, ha lokálisan van beállítva az elemen.

Összetett elemek

Több elem rétegezése helyett használjon összetett elemet egy effektus létrehozásához. Ebben a példában az eredmény egy kétárnyalatú alakzat, amelyben a felső fél fekete a Rács hátteréből, az alsó fele pedig szürke a félig átlátszó fehér Téglalapból, amely a Rács fekete hátterébe van blendelve. Itt az eredmény eléréséhez szükséges képpontok közül 150% töltődik ki.

Hatékony

<!-- NOTE: EXAMPLE OF INEFFICIENT CODE; DO NOT COPY-PASTE. -->
<Grid Background="Black">
    <Grid.RowDefinitions>
        <RowDefinition Height="*"/>
        <RowDefinition Height="*"/>
    </Grid.RowDefinitions>
    <Rectangle Grid.Row="1" Fill="White" Opacity=".5"/>
</Grid>

Hatékony

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="*"/>
        <RowDefinition Height="*"/>
    </Grid.RowDefinitions>
    <Rectangle Fill="Black"/>
    <Rectangle Grid.Row="1" Fill="#FF7F7F7F"/>
</Grid>

Elrendezés panelek

Az elrendezéspanelnek két célja lehet: egy terület színezése és a gyermekelemek elrendezése. Ha egy z-sorrendben távolabbi elem már színez egy területet, akkor az előtér elrendezési paneljének nem kell ezt a területet festenie; ehelyett a gyermekek elhelyezésére összpontosíthat. Íme egy példa.

Hatékony

<!-- NOTE: EXAMPLE OF INEFFICIENT CODE; DO NOT COPY-PASTE. -->
<GridView Background="Blue">
    <GridView.ItemTemplate>
        <DataTemplate>
            <Grid Background="Blue"/>
        </DataTemplate>
    </GridView.ItemTemplate>
</GridView>

Hatékony

<GridView Background="Blue">
    <GridView.ItemTemplate>
        <DataTemplate>
            <Grid/>
        </DataTemplate>
    </GridView.ItemTemplate>
</GridView>

Ha a rácsot tesztelhetőnek kell lennie, akkor állítson be egy háttérértéket Transparent rajta.

Határok

Szegélyelem használatával rajzoljon szegélyt egy objektum köré. Ebben a példában egy rácsot használunk ideiglenes szegélyként egy Szövegdoboz körül. De a középső cellában lévő összes képpont túl van állítva.

Hatékony

<!-- NOTE: EXAMPLE OF INEFFICIENT CODE; DO NOT COPY-PASTE. -->
<Grid Background="Blue" Width="300" Height="45">
    <Grid.RowDefinitions>
        <RowDefinition Height="5"/>
        <RowDefinition/>
        <RowDefinition Height="5"/>
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="5"/>
        <ColumnDefinition/>
        <ColumnDefinition Width="5"/>
    </Grid.ColumnDefinitions>
    <TextBox Grid.Row="1" Grid.Column="1"></TextBox>
</Grid>

Hatékony

<Border BorderBrush="Blue" BorderThickness="5" Width="300" Height="45">
    <TextBox/>
</Border>

Margók

Ügyeljen a margókra. Két szomszédos elem átfedésben lesz, esetleg véletlenül, ha a negatív margók egy másik elem renderelési határaira terjednek ki, és felülírást okoznak.

Statikus tartalom gyorsítótárazása

Az átlapolások egyik forrása egy sok egymást átfedő elemből készült alakzat. Ha a CacheMode-otBitmapCache értékre állítja az összetett alakzatot tartalmazó UIElementen , akkor a platform egyszer bitképké alakítja az elemet, és ezt a bitképet használja minden egyes keretben a túldralódás helyett.

Hatékony

<Canvas Background="White">
    <Ellipse Height="40" Width="40" Fill="Blue"/>
    <Ellipse Canvas.Left="21" Height="40" Width="40" Fill="Blue"/>
    <Ellipse Canvas.Top="13" Canvas.Left="10" Height="40" Width="40" Fill="Blue"/>
</Canvas>

Venn-diagram három szilárd körrel

A fenti kép az eredmény, de itt látható a felülírt régiók térképe. A sötétebb piros a nagyobb mértékű túldrágultságra utal.

Átfedő területeket ábrázoló Venn-diagram

Hatékony

<Canvas Background="White" CacheMode="BitmapCache">
    <Ellipse Height="40" Width="40" Fill="Blue"/>
    <Ellipse Canvas.Left="21" Height="40" Width="40" Fill="Blue"/>
    <Ellipse Canvas.Top="13" Canvas.Left="10" Height="40" Width="40" Fill="Blue"/>
</Canvas>

Figyelje meg a CacheMode használatát. Ne használja ezt a technikát, ha az alalakzatok bármelyike animálódik, mert a bitkép-gyorsítótárat valószínűleg minden egyes képkockán újra kell generálni, ez pedig ellentmond a célnak.

Lefordított XAML-kimenet használata

A Windows App SDK az XAML-t bináris reprezentációvá fordítja a build részeként, így elkerüli a futásidőben felmerülő szövegelemzési költségeket. A lefordított formátum emellett optimalizálja a betöltést és a fa létrehozását a gyakori XAML-típusok esetében, mint például a vizuális állapotok, az erőforrás-szótárak és stílusok.

A beépített WinUI-vezérlők és szótárak már élvezik ezt a folyamatot. Saját WinUI-alkalmazása esetén hagyja engedélyezve a normál XAML fordítási lépéseket, hogy a létrehozott korrektúrafordítási kimenet futásidőben is elérhető legyen.