Nota
O acesso a esta página requer autorização. Podes tentar iniciar sessão ou mudar de diretório.
O acesso a esta página requer autorização. Podes tentar mudar de diretório.
Analisar a marcação XAML para construir objetos na memória é demorado para uma interface do usuário complexa. Aqui estão algumas coisas que você pode fazer para melhorar o tempo de análise e carregamento de sua marcação XAML e a eficiência de memória de seu aplicativo.
Na inicialização do aplicativo, limite a marcação XAML carregada apenas ao que você precisa para sua interface do usuário inicial. Examine a marcação na página inicial (incluindo recursos da página) e confirme se você não está carregando elementos extras que não são necessários imediatamente. Esses elementos podem vir de uma variedade de fontes, como dicionários de recursos, elementos que são inicialmente recolhidos e elementos sobrepostos a outros elementos.
Otimizar seu XAML para eficiência requer fazer compensações; Nem sempre há uma única solução para cada situação. Aqui, analisamos alguns problemas comuns e fornecemos diretrizes que você pode usar para fazer as compensações certas para seu aplicativo.
Minimizar a contagem de elementos
Embora a plataforma XAML seja capaz de exibir um grande número de elementos, você pode fazer com que seu aplicativo disponha e renderize mais rapidamente usando o menor número de elementos para obter os elementos visuais desejados.
As escolhas que você fizer na forma como dispõe seus controles de interface do usuário afetarão o número de elementos da interface do usuário que são criados quando seu aplicativo é iniciado. Para obter informações mais detalhadas sobre como otimizar o layout, consulte Otimizar seu layout XAML.
A contagem de elementos é extremamente importante em modelos de dados porque cada elemento é criado novamente para cada item de dados. Para obter informações sobre como reduzir a contagem de elementos numa lista ou grelha, consulte Redução de Elementos por Item no artigo Otimização da Interface do Utilizador do ListView e GridView.
Aqui, analisamos algumas outras maneiras de reduzir o número de elementos que seu aplicativo precisa carregar na inicialização.
Adiar a criação de itens
Se sua marcação XAML contiver elementos que você não mostra imediatamente, você pode adiar o carregamento desses elementos até que eles sejam mostrados. Por exemplo, você pode atrasar a criação de conteúdo não visível, como uma guia secundária em uma interface do usuário semelhante a uma guia. Ou, tu podes mostrar itens num modo de visualização em grelha por predefinição, mas dar a hipótese ao utilizador de ver os dados numa lista. Você pode atrasar o carregamento da lista até que seja necessário.
Use o atributo x:Load em vez da propriedade Visibility para controlar quando um elemento é mostrado. Quando a visibilidade de um elemento é definida como Recolhido, ele é ignorado durante o passo de renderização, mas você ainda paga os custos da instância do objeto na memória. Quando você usa x:Load em vez disso, a estrutura não cria a instância do objeto até que ela seja necessária, portanto, os custos de memória são ainda menores. A desvantagem é que você paga uma pequena sobrecarga de memória (aproximadamente 600 bytes) quando a interface do usuário não é carregada.
Observação
Você pode atrasar o carregamento de elementos usando o atributo x:Load ou o atributo x:DeferLoadStrategy. O atributo x:Load está disponível a partir do Windows 10 Creators Update (versão 1703, compilação 15063 do SDK). A versão mínima direcionada pelo seu projeto do Visual Studio deve ser Windows 10 Creators Update (10.0, Build 15063) para poder usar x:Load. Para direcionar versões anteriores, use x:DeferLoadStrategy.
Os exemplos a seguir mostram a diferença na contagem de elementos e no uso de memória quando diferentes técnicas são usadas para ocultar elementos da interface do usuário. Um ListView e um GridView contendo itens idênticos são colocados na grelha principal de uma página. O ListView não está visível, mas o GridView é mostrado. O XAML em cada um desses exemplos produz a mesma interface do usuário na tela. Usamos as ferramentas do Visual Studio para análise e otimização de desempenho de modo a verificar o uso de memória e a contagem de elementos.
Opção 1 - Ineficiente
Aqui, o ListView é carregado, mas não é visível porque é Width é 0. O ListView e cada um de seus elementos filho são criados na árvore visual e carregados na memória.
<!-- 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>
Árvore visual ao vivo com o ListView carregado. A contagem total de elementos para a página é 89.
ListView e seus elementos são carregados na memória.
Opção 2 - Melhor
Aqui, a Visibilidade do ListView é definida como colapsada (o outro XAML é idêntico ao original). O ListView está criado na árvore visual, mas os seus elementos filhos não estão. No entanto, eles são carregados na memória, portanto, o uso da memória é idêntico ao exemplo anterior.
<ListView x:Name="List1" Visibility="Collapsed">
Árvore visual em tempo real com o ListView recolhido. A contagem total de elementos para a página é 46.
ListView e seus elementos são carregados na memória.
Opção 3 - Mais eficiente
Aqui, o ListView tem o atributo x:Load definido como False (o outro XAML é idêntico ao original). O ListView não é criado na árvore visual ou carregado na memória na inicialização.
<ListView x:Name="List1" Visibility="Collapsed" x:Load="False">
Árvore visual em tempo real com ListView não carregada. A contagem total de elementos para a página é 45.
ListView e suas entidades filhas não são carregadas na memória.
Observação
As contagens de elementos e o uso de memória nesses exemplos são muito pequenos e são mostrados apenas para demonstrar o conceito. Nesses exemplos, a sobrecarga de usar x:Load é maior do que a economia de memória, portanto, o aplicativo não se beneficiaria. Você deve usar as ferramentas de criação de perfil em seu aplicativo para determinar se seu aplicativo se beneficiará ou não do carregamento adiado.
Usar propriedades do painel de layout
Os painéis de layout têm uma propriedade Background, portanto, não há necessidade de colocar um Retângulo em frente a um Painel apenas para colori-lo.
ineficiente
<!-- NOTE: EXAMPLE OF INEFFICIENT CODE; DO NOT COPY-PASTE. -->
<Grid>
<Rectangle Fill="Black"/>
</Grid>
Eficiente
<Grid Background="Black"/>
Os painéis de layout também têm propriedades de borda integradas, portanto, não tem de colocar um elemento Border ao redor de um painel de layout. Consulte Otimizar seu layout XAML para obter mais informações e exemplos.
Use imagens no lugar de elementos baseados em vetores
Se você reutilizar o mesmo elemento baseado em vetor vezes suficientes, torna-se mais eficiente usar um elemento Image em vez disso. Os elementos baseados em vetores podem ser mais caros porque a CPU deve criar cada elemento individual separadamente. O arquivo de imagem precisa ser decodificado apenas uma vez.
Otimizar recursos e dicionários de recursos
Normalmente, você usa dicionários de recursos para armazenar, em um nível um pouco global, recursos que deseja referenciar em vários locais em seu aplicativo. Por exemplo, estilos, pincéis, modelos e assim por diante.
Em geral, otimizámos ResourceDictionary para não instanciar recursos, exceto quando solicitados. Mas há situações que você deve evitar para que os recursos não sejam instanciados desnecessariamente.
Recursos com x:Name
Use o atributo x:Key para fazer referência aos seus recursos. Qualquer recurso com o atributo x:Name não se beneficiará da otimização da plataforma; em vez disso, ele é instanciado assim que o ResourceDictionary é criado. Isso acontece porque x:Name informa à plataforma que seu aplicativo precisa de acesso de campo a esse recurso, então a plataforma precisa criar algo para criar uma referência.
ResourceDictionary em um UserControl
Um ResourceDictionary definido dentro de um UserControl implica uma penalidade. A plataforma cria uma cópia de tal ResourceDictionary para cada instância do UserControl. Se você tiver um UserControl que é muito usado, mova o ResourceDictionary para fora do UserControl e coloque-o no nível da página.
Escopo dos Recursos e do ResourceDictionary
Se uma página fizer referência a um controle de usuário ou a um recurso definido em um arquivo diferente, a estrutura também analisará esse arquivo.
Aqui, uma vez que InitialPage.xaml usa um recurso de ExampleResourceDictionary.xaml , o exemplo completo de ExampleResourceDictionary.xaml deve ser analisado durante a inicialização.
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>
ExemploResourceDictionary.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>
Se você usar um recurso em muitas páginas em todo o aplicativo, armazená-lo em App.xaml é uma boa prática e evita a duplicação. Mas App.xaml é analisado na inicialização do aplicativo, portanto, qualquer recurso usado em apenas uma página (a menos que essa página seja a página inicial) deve ser colocado nos recursos locais da página. Este exemplo mostra App.xaml que contém recursos que são usados por apenas uma página (que não é a página inicial). Isso aumenta desnecessariamente o tempo de inicialização do aplicativo.
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>
Para tornar este exemplo mais eficiente, mova SecondPageTextBrush para SecondPage.xaml e mova ThirdPageTextBrush para ThirdPage.xaml.
InitialPageTextBrush pode permanecer em App.xaml porque os recursos do aplicativo devem ser analisados na inicialização do aplicativo em qualquer caso.
Consolide vários pincéis com a mesma aparência em um único recurso
A plataforma XAML tenta armazenar em cache objetos comumente usados para que eles possam ser reutilizados com a maior frequência possível. Mas o XAML não consegue facilmente dizer se um pincel declarado num conjunto de marcação é o mesmo que um pincel declarado noutro. O exemplo aqui usa SolidColorBrush para demonstrar, mas o caso é mais provável e mais importante com GradientBrush. Verifique também se há pincéis que usam cores predefinidas; Por exemplo, "Orange" e "#FFFFA500" são da mesma cor.
Ineficiente.
<!-- 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>
Para corrigir a duplicação, defina o pincel como um recurso. Se os controles em outras páginas usarem o mesmo pincel, mova-o para App.xaml.
Eficiente.
<Page ... >
<Page.Resources>
<SolidColorBrush x:Key="BrandBrush" Color="#FFFFA500"/>
</Page.Resources>
<StackPanel>
<TextBlock Foreground="{StaticResource BrandBrush}" />
<Button Content="Submit" Foreground="{StaticResource BrandBrush}" />
</StackPanel>
</Page>
Minimizar o sobredesenho
O sobredesenho ocorre quando mais de um objeto é desenhado nos mesmos pixels da tela. Observe que às vezes há um trade-off entre essa orientação e o desejo de minimizar a contagem de elementos.
Use DebugSettings.IsOverdrawHeatMapEnabled como um diagnóstico visual. Você pode encontrar objetos sendo desenhados que você não sabia que estavam na cena.
Elementos transparentes ou ocultos
Se um elemento não estiver visível porque é transparente ou oculto atrás de outros elementos e não estiver contribuindo para o layout, exclua-o. Se o elemento não estiver visível no estado visual inicial, mas for visível em outros estados visuais, use x:Load para controlar o seu estado ou defina a Visibilidade para Recolhido no próprio elemento e mude o valor para Visível nos estados apropriados. Haverá exceções a essa heurística: em geral, o valor que uma propriedade tem na maioria dos estados visuais é melhor definido localmente no elemento.
Elementos compostos
Use um elemento composto em vez de colocar vários elementos em camadas para criar um efeito. ** Neste exemplo, o resultado é uma forma de dois tons onde a metade superior é preta (proveniente do fundo da Grelha ) e a metade inferior é cinza (devido ao Retângulo branco semitransparente misturado de forma alfa sobre o fundo preto da Grelha ). Aqui, 150% dos pixels necessários para alcançar o resultado estão sendo preenchidos.
Ineficiente.
<!-- 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>
Eficiente.
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Rectangle Fill="Black"/>
<Rectangle Grid.Row="1" Fill="#FF7F7F7F"/>
</Grid>
Painéis de layout
Um painel de layout pode ter duas finalidades: colorir uma área e dispor elementos filho. Se um elemento mais atrás na ordem z já está colorindo uma área, então um painel de layout na frente não precisa pintar essa área: em vez disso, ele pode apenas se concentrar em colocar seus filhos. Eis um exemplo.
Ineficiente.
<!-- NOTE: EXAMPLE OF INEFFICIENT CODE; DO NOT COPY-PASTE. -->
<GridView Background="Blue">
<GridView.ItemTemplate>
<DataTemplate>
<Grid Background="Blue"/>
</DataTemplate>
</GridView.ItemTemplate>
</GridView>
Eficiente.
<GridView Background="Blue">
<GridView.ItemTemplate>
<DataTemplate>
<Grid/>
</DataTemplate>
</GridView.ItemTemplate>
</GridView>
Se o Grid tiver que ser interativo a testes de toque, então defina um valor de fundo transparente para ele.
Fronteiras
Use um elemento Border para desenhar uma borda ao redor de um objeto. Neste exemplo, um de grade de
Ineficiente.
<!-- 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>
Eficiente.
<Border BorderBrush="Blue" BorderThickness="5" Width="300" Height="45">
<TextBox/>
</Border>
Margens
Esteja atento às margens. Dois elementos vizinhos se sobreporão (possivelmente acidentalmente) se as margens negativas se estenderem para os limites de renderização de outro e causarem sobredesenho.
Armazenar conteúdo estático em cache
Outra fonte de sobrecarga é uma forma feita de muitos elementos sobrepostos. Se você definir CacheMode para BitmapCache no UIElement que contém a forma composta, a plataforma renderizará o elemento para um bitmap uma vez e, em seguida, usará esse bitmap cada quadro em vez de sobredesenhar.
Ineficiente.
<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>
A imagem acima é o resultado, mas aqui está um mapa das regiões sobredesenhadas. O vermelho mais escuro indica maiores quantidades de sobrecarga.
Eficiente.
<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>
Observe o uso de CacheMode. Não use essa técnica se alguma das subformas for animada porque o cache de bitmap provavelmente precisará ser regenerado a cada quadro, anulando a finalidade.
Usar XBF2
XBF2 é uma representação binária da marcação XAML que evita todos os custos de análise de texto em tempo de execução. Ele também otimiza seu binário para criação de carga e árvore e permite "caminho rápido" para tipos XAML para melhorar os custos de criação de heap e objeto, por exemplo, VSM, ResourceDictionary, Styles e assim por diante. Está completamente mapeado na memória, portanto, não há consumo de heap para carregar e ler uma página XAML. Além disso, reduz o espaço ocupado pelo disco das páginas XAML armazenadas em um appx. XBF2 é uma representação mais compacta e pode reduzir o espaço ocupado pelo disco de arquivos XAML/XBF1 comparativos em até 50%. Por exemplo, o aplicativo Fotos integrado viu uma redução de cerca de 60% após a conversão para XBF2, caindo de cerca de ~1mb de ativos XBF1 para ~400kb de ativos XBF2. Também vimos aplicativos se beneficiarem de 15 a 20% na CPU e 10 a 15% na pilha Win32.
Os controles e dicionários internos XAML que a estrutura fornece já são totalmente habilitados para XBF2. Para seu próprio aplicativo, certifique-se de que seu arquivo de projeto declare TargetPlatformVersion 8.2 ou posterior.
Para verificar se você tem XBF2, abra seu aplicativo em um editor binário; o 12º e o 13º bytes são 00 02 se você tiver XBF2.