最佳化您的 XAML 標記Optimize your XAML markup

剖析 XAML 標記以在記憶體建構物件,對複雜 UI 而言很耗費時間。Parsing XAML markup to construct objects in memory is time-consuming for a complex UI. 以下是一些您可執行來改善 XAML 標記剖析與載入時間及應用程式記憶體效率的動作。Here are some things you can do to improve the parse and load time of your XAML markup and the memory efficiency of your app.

在 app 啟動時,限制 XAML 標記僅針對您需要的初始 UI 載入。At app startup, limit the XAML markup that is loaded to only what you need for your initial UI. 檢查初始頁面中的標記 (包括頁面資源),並確認您沒有載入不是立即需要的額外元素。Examine the markup in your initial page (including page resources) and confirm that you aren't loading extra elements that aren't needed right away. 這些元素可能來自各種不同的來源,例如資源字典、最初既已摺疊的元素,以及繪製在其他元素上的元素。These elements can come from a variety of sources, such as resource dictionaries, elements that are initially collapsed, and elements drawn over other elements.

針對效率最佳化您的 XAML 需要做出取捨;不一定會有各種情況都適用的單一解決方案。Optimizing your XAML for efficiency requires making trade-offs; there's not always a single solution for every situation. 我們來看看一些常見的問題,並提供您可用來為應用程式進行適當權衡取捨的指導方針。Here, we look at some common issues and provide guidelines you can use to make the right trade-offs for your app.

最小化元素計數Minimize element count

雖然 XAML 平台能夠顯示大量的元素,您可以讓您的 app 配置和轉譯速度更快,方法是使用最少量的元素來達成您想要的視覺效果。Although the XAML platform is capable of displaying large numbers of elements, you can make your app lay out and render faster by using the fewest number of elements to achieve the visuals you want.

您對如何配置 UI 控制項所做的選擇會影響應用程式啟動時所建立的 UI 元素數目。The choices you make in how you lay out your UI controls will affect the number of UI elements that are created when your app starts. 如需有關最佳化版面配置的詳細資訊,請參閱最佳化您的 XAML 版面配置For more detailed information about optimizing layout, see Optimize your XAML layout.

元素計數在資料範本中極其重要,因為會針對每個資料項目重新建立各個元素。Element count is extremely important in data templates because each element is created again for each data item. 如需有關減少清單或方格中元素計數的詳細資訊,請參閱 ListView 與 GridView UI 最佳化文章中的每個項目的元素減少For info about reducing element count in a list or grid, see Element reduction per item in the ListView and GridView UI optimization article.

我們來看看一些可以減少應用程式在啟動時載入之元素數目的其他方式。Here, we look at some other ways you can reduce the number of elements your app has to load at startup.

延遲建立項目Defer item creation

如果您的 XAML 標記包含不會立即顯示的元素,您可以將這些元素延遲到要顯示時再載入。If your XAML markup contains elements that you don't show right away, you can defer loading those elements until they are shown. 比如說,您可以延遲建立不可見內容,例如索引標籤式 UI 中的次要索引標籤。For example, you can delay the creation of non-visible content such as a secondary tab in a tab-like UI. 或者,可以預設將項目顯示在網格檢視中,但提供使用者可改為在清單中檢視資料的選項。Or, you might show items in a grid view by default, but provide an option for the user to view the data in a list instead. 您可以將清單延遲到需要時再載入。You can delay loading the list until it's needed.

使用 x:Load 屬性,而非 Visibility 屬性,來控制項顯示元素的時機。Use the x:Load attribute instead of the Visibility property to control when an element is shown. 當元素的可見度設定為 Collapsed 時,系統會在轉譯階段跳過該元素,但仍然要付出物件執行個體佔用記憶體的代價。When an element's visibility is set to Collapsed, then it is skipped during the render pass, but you still pay the object instance costs in memory. 改用 x:Load 時,除非必要,否則架構不會建立物件執行個體,因此記憶體使用量甚至更低。When you use x:Load instead, the framework does not create the object instance until it is needed, so the memory costs are even lower. 缺點是未載入 UI 時,會產生少量的記憶體額外負荷 (約為 600 個位元組)。The drawback is you pay a small memory overhead (approx 600 bytes) when the UI is not loaded.

注意

您可以使用 x:Loadx:DeferLoadStrategy 屬性來延遲載入元素。You can delay loading elements using the x:Load or x:DeferLoadStrategy attribute. x:Load 屬性是在 Windows 10 Creators Update (版本 1703,SDK 組建 15063) 中開始提供。The x:Load attribute is available starting in Windows 10 Creators Update (version 1703, SDK build 15063). Visual Studio 專案設為目標的版本必須至少是 Windows 10 Creators Update (10.0,組建 15063) ,才能使用 x:Load。The min version targeted by your Visual Studio project must be Windows 10 Creators Update (10.0, Build 15063) in order to use x:Load. 若要以舊版為目標,請使用 x:DeferLoadStrategy。To target earlier versions, use x:DeferLoadStrategy.

下列範例顯示元素計數及記憶體使用量在使用不同技術隱藏 UI 元素時的差異。The following examples show the difference in element count and memory use when different techniques are used to hide UI elements. 將包含完全相同項目的 ListView 和 GridView 放置在頁面的根方格中。A ListView and a GridView containing identical items are placed in a page's root Grid. 看不到 ListView,但會顯示 GridView。The ListView is not visible, but the GridView is shown. 這其中每個範例的 XAML 都會在螢幕上產生相同的 UI。The XAML in each of these examples produces the same UI on the screen. 我們使用 Visual Studio 分析和效能的工具來檢查元素計數和記憶體使用量。We use Visual Studio's tools for profiling and performance to check the element count and memory use.

選項 1 - 效率低Option 1 - Inefficient

ListView 在此處載入,但因寬度為 0 而看不到。Here, the ListView is loaded, but is not visible because it's Width is 0. ListView 及其每個子元素已建立於視覺化樹狀結構中,並已載入記憶體中。The ListView and each of its child elements is created in the visual tree and loaded into memory.

<!-- 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>

載入 ListView 後的即時視覺化樹狀結構。Live visual tree with the ListView loaded. 頁面的元素總計數為 89。Total element count for the page is 89.

包含清單檢視的視覺化樹狀結構螢幕擷取畫面。

ListView 及其子系已載入記憶體中。ListView and its children are loaded into memory.

受控記憶體測試應用程式 .EXE 資料表的螢幕擷取畫面,其中顯示 ListView 及其子系已載入記憶體中。

選項 2 - 較佳Option 2 - Better

ListView 的可見度在此處設定為已摺疊 (其他 XAML 與原先完全相同)。Here, the ListView's Visibility is set to collapsed (the other XAML is identical to the original). 已於視覺化樹狀結構中建立 ListView,但未建立其子元素。The ListView is created in the visual tree, but its child elements are not. 不過,這些子元素是載入記憶體中,因此記憶體使用量與上一個範例的相同。However, they are loaded into memory, so memory use is identical to the previous example.

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

ListView 已摺疊的即時視覺化樹狀結構。Live visual tree with the ListView collapsed. 頁面的元素總計數為 46。Total element count for the page is 46.

包含已摺疊清單檢視的視覺化樹狀結構螢幕擷取畫面。

ListView 及其子系已載入記憶體中。ListView and its children are loaded into memory.

受控記憶體測試應用程式 .EXE 資料表的更新後螢幕擷取畫面,其中顯示 ListView 及其子系已載入記憶體中。

選項 3 - 最具效率Option 3 - Most Efficient

ListView 在此處將 x:Load 屬性設定為 False (其他 XAML 與原先完全相同)。Here, the ListView has the x:Load attribute set to False (the other XAML is identical to the original). 啟動時並未在視覺化樹狀結構中建立 ListView,也未將其載入記憶體中。The ListView is not created in the visual tree or loaded into memory at start up.

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

未載入 ListView 的即時視覺化樹狀結構。Live visual tree with the ListView not loaded. 頁面的元素總計數為 45。Total element count for the page is 45.

未載入清單檢視的視覺化樹狀結構

ListView 及其子系未載入記憶體中。ListView and its children are not loaded into memory.

包含清單檢視的視覺化樹狀結構

注意

這些範例的元素計數和記憶體使用量都很小,只是顯示來示範概念。The element counts and memory use in these examples are very small and are shown only to demonstrate the concept. 在這些範例中,使用 x:Load 的額外負荷大於節省的記憶體,因此應用程式並未受益。In these examples, the overhead of using x:Load is greater than the memory savings, so the app would not benefit. 您應該對您的應用程式使用分析工具,以判斷應用程式是否因為延遲載入而受益。You should use the profiling tools on your app to determine whether or not your app will benefit from deferred loading.

使用版面配置面板屬性Use layout panel properties

配置面板有 Background 屬性,所以不需要只是為了塗上色彩而將 Rectangle 放在面板前面。Layout panels have a Background property so there's no need to put a Rectangle in front of a Panel just to color it.

InefficientInefficient

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

EfficientEfficient

<Grid Background="Black"/>

版面配置面板還有內建的框線屬性,因此不需要在版面配置面板周圍放置 Border 元素。Layout panels also have built-in border properties, so you don't need to put a Border element around a layout panel. 如需詳細資訊和範例,請參閱最佳化您的 XAML 版面配置See Optimize your XAML layout for more info and examples.

使用影像來取代以向量為基礎的元素Use images in place of vector-based elements

如果您重複使用相同的向量元素夠多次,改為使用 Image 元素會更有效率。If you reuse the same vector-based element enough times, it becomes more efficient to use an Image element instead. 向量元素需要耗費較多的資源,因為 CPU 必須個別建立每個元素。Vector-based elements can be more expensive because the CPU must create each individual element separately. 影像檔只需要解碼一次。The image file needs to be decoded only once.

最佳化資源和資源字典Optimize resources and resource dictionaries

您通常會使用資源字典,在某些全域層級上儲存要在應用程式中多個地方參考的資源。You typically use resource dictionaries to store, at a somewhat global level, resources that you want to reference in multiple places in your app. 例如,樣式、筆刷、範本等等。For example, styles, brushes, templates, and so on.

一般而言,我們已將 ResourceDictionary 最佳化,除非有要求,否則不會將資源具現化。In general, we have optimized ResourceDictionary to not instantiate resources unless they're asked for. 但有些情況還是應該避免,不要讓資源進行無謂的具現化。But there are situations you should avoid so that resources aren’t instantiated unnecessarily.

包含 x:Name 的資源Resources with x:Name

使用 x:Key 屬性來參考您的資源。Use the x:Key attribute to reference your resources. 任何含有 x:Name 屬性的資源都無法從平台最佳化受益,反而是在 ResourceDictionary 一經建立之後,就會立即進行具現化。Any resource with the x:Name attribute will not benefit from the platform optimization; instead, it is instantiated as soon as the ResourceDictionary is created. 這是因為 x:Name 會告知平台您的 App 需要此資源的欄位存取權,因此平台需要建立可供建立參考的內容。This happens because x:Name tells the platform that your app needs field access to this resource, so the platform needs to create something to create a reference to.

UserControl 中的 ResourceDictionaryResourceDictionary in a UserControl

UserControl 內定義的 ResourceDictionary 會受到不利影響。A ResourceDictionary defined inside of a UserControl carries a penalty. 平台會針對 UserControl 的每個執行個體建立這類 ResourceDictionary 的複本。The platform creates a copy of such a ResourceDictionary for every instance of the UserControl. 如果您有一個使用頻率很高的 UserControl,則請將 ResourceDictionary 從 UserControl 中移出,然後將它放到頁面層級。If you have a UserControl that is used a lot, then move the ResourceDictionary out of the UserControl and put it at the page level.

Resource 和 ResourceDictionary 領域Resource and ResourceDictionary scope

如果頁面參照不同檔案中定義的使用者控制項或資源,則架構也會剖析該檔案。If a page references a user control or a resource defined in a different file, then the framework parses that file, too.

這裡的 InitialPage.xaml 使用來自 ExampleResourceDictionary.xaml 的某個資源,因此必須在啟動時剖析整個 ExampleResourceDictionary.xamlHere, because InitialPage.xaml uses one resource from ExampleResourceDictionary.xaml, the whole of ExampleResourceDictionary.xaml must be parsed at startup.

InitialPage.xaml。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。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>

如果您在應用程式的許多頁面上使用資源,則將其存放在 App.xaml 是很好的做法,而且可以避免重複。If you use a resource on many pages throughout your app, then storing it in App.xaml is a good practice, and avoids duplication. 但是 App.xaml 會在應用程式啟動時進行剖析,所以僅在單一頁面中使用的任何資源 (除非該頁面是初始頁面) 應該放在頁面的本機資源。But App.xaml is parsed at app startup so any resource that is used in only one page (unless that page is the initial page) should be put into the page's local resources. 此範例顯示包含僅由一個頁面 (不是初始頁面) 所使用資源的 App.xamlThis example shows App.xaml containing resources that are used by only one page (that's not the initial page). 這會無端地增加 app 啟動時間。This needlessly increases app startup time.

App.xamlApp.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。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。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>

為了讓這些範例更有效率,請將 SecondPageTextBrush 移入 SecondPage.xaml,並將 ThirdPageTextBrush 移入 ThirdPage.xamlTo make this example more efficient, move SecondPageTextBrush into SecondPage.xaml and move ThirdPageTextBrush into ThirdPage.xaml. InitialPageTextBrush 可以保留在 App.xaml 中,因為在任何情況下,應用程式資源必須在應用程式啟動時進行剖析。InitialPageTextBrush can remain in App.xaml because application resources must be parsed at app startup in any case.

將看起來相同的多個筆刷合併到一個資源Consolidate multiple brushes that look the same into one resource

XAML 平台會嘗試快取常用的物件,這樣就可以盡可能地重複使用這些物件。The XAML platform tries to cache commonly-used objects so that they can be reused as often as possible. 但是,XAML 無法清楚分辨某個標記中宣告的筆刷與另一個標記中宣告的筆刷是否相同。But XAML cannot easily tell if a brush declared in one piece of markup is the same as a brush declared in another. 此處的範例使用 SolidColorBrush 進行示範,但是 GradientBrush 的案例更類似且更重要。The example here uses SolidColorBrush to demonstrate, but the case is more likely and more important with GradientBrush. 此外,還會檢查使用預先定義色彩的筆刷;例如 "Orange""#FFFFA500" 是相同的色彩。Also check for brushes that use predefined colors; for example, "Orange" and "#FFFFA500" are the same color.

Inefficient。Inefficient.

<!-- 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>

若要修正重複,將筆刷定義為資源。To fix the duplication, define the brush as a resource. 如果其他頁面中的控制項使用相同的筆刷,請將其移至 App.xamlIf controls in other pages use the same brush, move it to App.xaml.

Efficient。Efficient.

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

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

最小化過度繪製Minimize overdrawing

過度繪製是在以相同螢幕像素繪製多個物件的情況下發生。Overdrawing occurs where more than one object is drawn in the same screen pixels. 請注意,在這個指導方針和想要最小化元素計數之間有時需要取捨。Note that there is sometimes a trade-off between this guidance and the desire to minimize element count.

使用 DebugSettings.IsOverdrawHeatMapEnabled 做為視覺診斷。Use DebugSettings.IsOverdrawHeatMapEnabled as a visual diagnostic. 您會發現原本未注意到的繪製物件出現在場景中。You might find objects being drawn that you didn't know were in the scene.

透明或隱藏的元素Transparent or hidden elements

如果元素因為是透明的或是隱藏在其他元素後面而看不見,而且它不會參與配置,則刪除它。If an element isn't visible because it's transparent or hidden behind other elements, and it's not contributing to layout, then delete it. 如果元素在初始視覺狀態看不見,但是在其他視覺狀態中可見,請使用 x:Load 來控制其狀態,或者在元素本身將 Visibility 設為 Collapsed,並且在適當狀態中將值變更為 VisibleIf the element is not visible in the initial visual state but it is visible in other visual states, then use x:Load to control its state or set Visibility to Collapsed on the element itself and change the value to Visible in the appropriate states. 這個啟發學習法有例外狀況:一般來說,屬性在大多數視覺狀態中的值最好是在本機對元素進行設定。There will be exceptions to this heuristic: in general, the value a property has in the majority of visual states is best set locally on the element.

複合元素Composite elements

使用複合元素,而不要分層放置多個元素來建立效果。Use a composite element instead of layering multiple elements to create an effect. 在這個範例中,結果是雙色調圖形,上半部是黑色 (來自 Grid 的背景),下半部是灰色 (從半透明白色的Rectangle alpha-blended 混合 Grid 的黑色背景)。In this example, the result is a two-toned shape where the top half is black (from the background of the Grid) and the bottom half is gray (from the semi-transparent white Rectangle alpha-blended over the black background of the Grid). 這裡需要 150% 的像素以達成填滿的結果。Here, 150% of the pixels necessary to achieve the result are being filled.

Inefficient。Inefficient.

<!-- 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>

Efficient。Efficient.

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

版面配置面板Layout panels

配置面板可以有兩個目的:為區域上色和配置子元素。A layout panel can have two purposes: to color an area, and to lay out child elements. 如果進一步以 z 順序排序的元素已為區域上色,則前方的配置面板不需要繪製該區域:而是可以只專注於配置其子系。If an element further back in z-order is already coloring an area then a layout panel in front does not need to paint that area: instead it can just focus on laying out its children. 以下是範例。Here's an example.

Inefficient。Inefficient.

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

Efficient。Efficient.

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

如果 Grid 可以進行點擊測試,則在其上設定透明背景值。If the Grid has to be hit-testable then set a background value of transparent on it.

框線Borders

使用 Border 元素以在物件周圍繪製框線。Use a Border element to draw a border around an object. 在這個範例中,Grid 是做為 TextBox 周圍的臨時框線。In this example, a Grid is used as a makeshift border around a TextBox. 但是會過度繪製中心儲存格中的所有像素。But all the pixels in the center cell are overdrawn.

Inefficient。Inefficient.

<!-- 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>

Efficient。Efficient.

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

邊界Margins

請注意邊界。Be aware of margins. 如果負數邊界延伸到彼此轉譯的界限內,並且導致過度繪製,則兩個鄰近的元素會重疊 (可能會意外發生)。Two neighboring elements will overlap (possibly accidentally) if negative margins extend into another’s render bounds and cause overdrawing.

快取靜態內容Cache static content

另一個過度繪製的來源是來自許多重疊元素的圖形。Another source of overdrawing is a shape made from many overlapping elements. 如果您在包含組合圖形的 UIElement 上,將 CacheMode 設為 BitmapCache,則平台會將元素轉譯為點陣圖一次,然後在每個框架使用該點陣圖,而不會過度繪製。If you set CacheMode to BitmapCache on the UIElement that contains the composite shape then the platform renders the element to a bitmap once and then uses that bitmap each frame instead of overdrawing.

Inefficient。Inefficient.

<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>

三個單色圓圈組成的文氏圖表

上面的影像是結果,但以下是過度繪製區域的地圖。The image above is the result, but here's a map of the overdrawn regions. 紅色越深代表過度繪製的次數越多。Darker red indicates higher amounts of overdraw.

顯示重疊區域的文氏圖表

Efficient。Efficient.

<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>

請注意使用 CacheModeNote the use of CacheMode. 如果有任何子圖形具有動畫效果,請勿使用這項技巧,因為每個框架可能需要重新產生點陣快取,而導致破壞原本的目的。Don't use this technique if any of the sub-shapes animate because the bitmap cache will likely need to be regenerated every frame, defeating the purpose.

使用 XBF2Use XBF2

XBF2 是 XAML 標記的二進位表示法,可避免在執行階段產生的所有文字剖析成本。XBF2 is a binary representation of XAML markup that avoids all text-parsing costs at runtime. 它也會將您的二進位檔針對載入和樹狀目錄建立進行最佳化,並且允許針對 XAML 類型使用「快速路徑」以改善堆積和物件建立成本,例如 VSM、ResourceDictionary、樣式等等。It also optimizes your binary for load and tree creation, and allows "fast-path" for XAML types to improve heap and object creation costs, for example VSM, ResourceDictionary, Styles, and so on. 它完全採用記憶體對應,因此沒有用來載入和讀取 XAML 頁面的堆積磁碟使用量。It is completely memory-mapped so there is no heap footprint for loading and reading a XAML Page. 此外,它也可以減少 appx 中儲存的 XAML 頁面的磁碟使用量。In addition, it reduces the disk footprint of stored XAML pages in an appx. XBF2 是一個較精簡的表示法,與 XAML/XBF1 檔案相比,最多可以減少 50% 的磁碟使用量。XBF2 is a more compact representation and it can reduce disk footprint of comparative XAML/XBF1 files by up to 50%. 例如,內建的「相片」應用程式在轉換成 XBF2 之後的縮減程度大約為 60%,從大約 ~1 mb 的 XBF1 資產降低成 ~400kb 的 XBF2 資產。For example, the built-in Photos app saw around a 60% reduction after conversion to XBF2 dropping from around ~1mb of XBF1 assets to ~400kb of XBF2 assets. 我們也看過應用程式的受益情況是在 CPU 方面的縮減程度大約為 15% 到 20%,而在 Win32 堆積方面為 10% 到 15%。We have also seen apps benefit anywhere from 15 to 20% in CPU and 10 to 15% in Win32 heap.

XAML 內建控制項和架構提供的字典已經完全啟用 XBF2。XAML built-in controls and dictionaries that the framework provides are already fully XBF2-enabled. 針對您自己的應用程式,請確定您專案檔宣告的是 TargetPlatformVersion 8.2 或更新版本。For your own app, ensure that your project file declares TargetPlatformVersion 8.2 or later.

若要檢查您是否有 XBF2,請在二進位編輯器中開啟您的應用程式;如果您有 XBF2,則第 12 和第 13 個位元組會是 00 02。To check whether you have XBF2, open your app in a binary editor; the 12th and 13th bytes are 00 02 if you have XBF2.