Otimize o carregamento de XAML

Otimizar o carregamento XAML (XAML)

[ Este artigo destina-se aos desenvolvedores do Windows 8.x e do Windows Phone 8.x que escrevem aplicativos do Windows Runtime. Se você estiver desenvolvendo para o Windows 10, consulte documentação mais recente]

Analisar XAML e criar os objetos correspondentes na memória pode ser demorado para uma interface do usuário complexa. Veja algumas coisas que você pode fazer para que seu aplicativo carregue XAML mais rapidamente ao desenvolver um aplicativo da Windows Store em C++, C# ou Visual Basic para Windows 8.

Recomendamos que você carregue somente o XAML necessário para passar o processo de inicialização, por exemplo, carregar as páginas necessárias para exibir a interface do usuário inicial. Examine com cuidado o XAML de sua primeira página para garantir que ela contenha tudo o que for necessário. Se a sua primeira página fizer referência a um controle ou estilo definido em um arquivo diferente, a estrutura analisará esse arquivo também.

Considere este exemplo. Ele mostra a primeira página que um aplicativo exibe e uma parte de AppStyles.Xaml. A página usa o recurso TextColor, que está definido em AppStyles.xaml. Isso significa que AppStyles.xaml deve ser analisado quando essa página for carregada. Como AppStyles.xaml contém vários recursos de aplicativo usados no aplicativo, a análise de todos os recursos que não são necessários para iniciar o aplicativo irá demorar.

Conteúdo da página principal.


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


Conteúdo de AppStyles.xaml.


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

    <!--This ResourceDictionary contains many other resources that
    used in the app, but they aren't used during startup.-->
</ResourceDictionary>


Cortar dicionários de recursos. Se você usa um recurso em um aplicativo, armazene-o no objeto Application para evitar duplicação. Mas se você usar um recurso em uma única página que não seja a inicial, coloque o recurso no dicionário de recursos dessa página. Isso reduzirá a quantidade de XAML analisado pela estruutra quando o aplicativo for iniciado. A estrutura só analisará o resto do XAML quando um usuário navegar até a página específica.

Veja um exemplo de uma prática ruim. Não inclua XAML específico de uma página no dicionário de recursos do aplicativo. O aplicativo incorre no custo de analisar recursos que não sejam imediatamente necessários na inicialização em vez de fazer isso sob demanda.



<Application ...> <!-- BAD CODE DO NOT USE.-->
     <Application.Resources>  <!-- BAD CODE DO NOT USE.-->
        <SolidColorBrush x:Key="DefaultAppTextColor" Color="#FF3F42CC"/> <!-- BAD CODE DO NOT USE.-->
        <SolidColorBrush x:Key="HomePageTextColor" Color="#FF3F42CC"/> <!-- BAD CODE DO NOT USE.-->
        <SolidColorBrush x:Key="SecondPageTextColor" Color="#FF3F42CC"/> <!-- BAD CODE DO NOT USE.-->
        <SolidColorBrush x:Key="ThirdPageTextColor" Color="#FF3F42CC"/> <!-- BAD CODE DO NOT USE.-->
    </Application.Resources> <!-- BAD CODE DO NOT USE.-->
</Application> <!-- BAD CODE DO NOT USE.-->


XAML para a primeira página do aplicativo.


<Page ...>  <!-- BAD CODE DO NOT USE.-->   
    <StackPanel>  <!-- BAD CODE DO NOT USE.-->
        <TextBox Foreground="{StaticResource HomePageTextColor}"/> <!-- BAD CODE DO NOT USE.-->
    </StackPanel> <!-- BAD CODE DO NOT USE.-->
</Page> <!-- BAD CODE DO NOT USE.-->
	

XAML para a segunda página do aplicativo.


<Page ...>  <!-- BAD CODE DO NOT USE.-->
    <StackPanel> <!-- BAD CODE DO NOT USE.-->
        <Button Content="Submit" Foreground="{StaticResource SecondPageColor}" /> <!-- BAD CODE DO NOT USE.-->
    </StackPanel> <!-- BAD CODE DO NOT USE.-->
</Page> <!-- BAD CODE DO NOT USE.-->


Mova os recursos específicos da página para o dicionário de recursos dessa página. Este exemplo define o recurso SecondPageTextColor na mesma página que o usa. Ele mantém o recurso, HomePageTextColor, em app.xaml porque ele deve ser analisado na inicialização de qualquer maneira. Você também pode mover o recurso para o dicionário de recursos da primeira página.


<Application ...>
    <Application.Resources>
        <SolidColorBrush x:Key="DefaultAppTextColor" Color="#FF3F42CC"/>
        <SolidColorBrush x:Key="HomePageTextColor" Color="#FF3F42CC"/>
    </Application.Resources>
</Application>


XAML para a segunda página do aplicativo.


<Page ...>    
    <StackPanel>
        <TextBox Foreground="{StaticResource HomePageTextColor}" />
    </StackPanel>
</Page>


XAML para a primeira página do aplicativo.


<Page ...>
    <Page.Resources>
        <SolidColorBrush x:Key="SecondPageTextColor" Color="#FF3F42CC"/>
    </Page.Resources>
    
    <StackPanel>
        <Button Content="Submit" Foreground="{StaticResource SecondPageTextColor}" />
    </StackPanel>
</Page>


Otimizar a contagem de elementos

A estrutura XAML pode exibir milhares de objetos e você pode fazer com que seu aplicativo crie o layout de cenas e as renderize com mais rapidez ao reduzir o número de elementos em uma página. Veja alguns truques que você pode usar para reduzir a contagem de elementos de uma cena mantendo o mesmo nível de complexidade visual.

  • Evite elementos desnecessários. Por exemplo, defina a propriedade Background em painéis para fornecer uma cor da tela de fundo em vez de colocar um Rectangle colorido por trás dos elementos desse painel.

    Não faça isso.

    
    <Grid> <!-- BAD CODE DO NOT USE.-->
        <Rectangle Fill="Black"/> <!-- BAD CODE DO NOT USE.-->
    </Grid> <!-- BAD CODE DO NOT USE.-->
    
    
    

    Em vez disso, faça isto.

    
    <Grid Background="Black" />
    
    
  • Se os elementos não estiverem visíveis porque são transparentes ou estão ocultos atrás de outros elementos, remova-os e defina a propriedade Visibility como Collapsed se outros estados visuais os usarem.
  • Se você reutilizar o mesmo elemento baseado em vetor várias vezes, transforme-o em uma imagem. Os elementos baseados em vetor são potencialmente mais caros porque a CPU deve criar cada elemento individual separadamente, mas a imagem precisa ser decodificada somente uma vez.

Reutilizar pincéis idênticos

A estrutura XAML tenta armazenar objetos comumente usados em cache de forma que eles possam ser reutilizados com mais frequência possível. Mas o XAML não pode dizer com facilidade se um pincel declarado em um modelo é o mesmo pincel declarado em um modelo diferente. Crie pincéis comumente usados como elementos ResourceDictionary raiz e então faça referência a esse objeto em modelos como necessário. O XAML será capaz de usar o mesmo objeto em modelos diferentes e o consumo de memória será reduzido. Esse truque é especialmente importante para objetos GradientBrush, que são mais caros do que objetos SolidColorBrush.

Evite a definição do mesmo pincel em vários controles como este.


 <!-- BAD CODE DO NOT USE.-->
<Page ...>  <!-- BAD CODE DO NOT USE.-->
    <StackPanel>  <!-- BAD CODE DO NOT USE.-->
        <TextBox>  <!-- BAD CODE DO NOT USE.-->
            <TextBox.Foreground>  <!-- BAD CODE DO NOT USE.-->
                <SolidColorBrush Color="#FF3F42CC"/> <!-- BAD CODE DO NOT USE.-->
            </TextBox.Foreground> <!-- BAD CODE DO NOT USE.-->
        </TextBox> <!-- BAD CODE DO NOT USE.-->
        <Button Content="Submit"> <!-- BAD CODE DO NOT USE.-->
            <Button.Foreground> <!-- BAD CODE DO NOT USE.-->
                <SolidColorBrush Color="#FF3F42CC"/> <!-- BAD CODE DO NOT USE.-->
            </Button.Foreground> <!-- BAD CODE DO NOT USE.-->
        </Button> <!-- BAD CODE DO NOT USE.-->
    </StackPanel> <!-- BAD CODE DO NOT USE.-->
</Page> <!-- BAD CODE DO NOT USE.-->


Em vez disso, defina o pincel comum e faça referência a ele como necessário, desta maneira. Se os controles em outras páginas usarem o mesmo pincel, mova-o para o app.xaml de forma que o aplicativo não o duplique.


<Page ...>
    <Page.Resources>
        <SolidColorBrush x:Key="TextColor" Color="#FF3F42CC"/>
    </Page.Resources>
    
    <StackPanel>
        <TextBox Foreground="{StaticResource TextColor}" />
        <Button Content="Submit" Foreground="{StaticResource TextColor}" />
    </StackPanel>
</Page>


Minimizar o redesenho para o mesmo local na tela

É muito mais rápido permitir que o hardware gráfico desenhe cada forma no buffer da tela do que selecionar partes de objetos obscuras. Como cada objeto é desenhado, a quantidade total de trabalho feito pelo hardware gráfico pode ser reduzida se os elementos completamente obscuros não forem desenhados. É claro que não se espera que você controle a visibilidade de todos os objetos, mas é possível fazer algumas coisas fáceis para impedir que o mesmo pixel seja desenhado várias vezes desnecessariamente.

  • Recolha elementos que estejam totalmente obscurecidos por outros em primeiro plano.

  • Crie um elemento composto em vez de mostrar os objetos em camadas para criar um efeito. Este exemplo de um XAML não otimizado cria uma tela de fundo de dois tons para o elemento Grid. A metade superior é preta e a metade inferior é cinza. O exemplo posiciona um Rectangle branco semitransparente na metade inferior da grade e permite que o fundo preto Grid se misture com Rectangle. Esse design faz com que a placa gráfica escreva todos os pixels na tela preta quando desenha Grid e enetão escreve todos os pixels do Retângulo branco (metade do tamanho da tela). O número total de pixels preenchidos é de 1,5 vez a resolução da tela.

    
    <Grid Background="Black"> <!-- BAD CODE DO NOT USE.-->
        <Grid.RowDefinitions> <!-- BAD CODE DO NOT USE.-->
            <RowDefinition Height="*"/> <!-- BAD CODE DO NOT USE.-->
            <RowDefinition Height="*"/> <!-- BAD CODE DO NOT USE.-->
        </Grid.RowDefinitions> <!-- BAD CODE DO NOT USE.-->
        <Rectangle Grid.Row="1" Fill="White" Opacity=".5"/> <!-- BAD CODE DO NOT USE.-->
    </Grid> <!-- BAD CODE DO NOT USE.-->
    
    
    

    Este exemplo de XAML otimizado cria a mesma tela de fundo de dois tons para o elemento Grid, mas com 33% menos preenchimentos de pixel. As únicas coisas desenhadas são o Rectangle superior (metade da tela) e o Rectangle inferior (metade da tela). O número total de pixels preenchidos é igual à resolução da tela. A tela de fundo da grade nunca é desenhada porque é transparente

    
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="*"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        <Rectangle Grid.Row="0" Fill="Black"/>
        <Rectangle Grid.Row="1" Fill="#FF7F7F7F"/>
    </Grid>
    
    
    
  • Não use a mesma cor para elementos de primeiro e segundo planos. Em vez disso, não defina a cor de elementos de primeiro plano e permita que a cor da tela de fundo sangre.

    Este XAML cria um GridView com um segundo plano azul e define o segundo plano de DataTemplate para cada item como azul também. A definição do segundo plano (como qualquer coisa, exceto Transparente) em DataTemplate faz com que os pixels sejam preenchidos para o segundo plano de cada item. Nesse caso, isso é desnecessário porque o segundo plano de GridView e o segundo plano dos itens têm a mesma cor.

    Não faça isso.

    
    <!-- BAD CODE DO NOT USE.-->
    <GridView Background="Blue">  <!-- BAD CODE DO NOT USE.-->
        <GridView.ItemTemplate> <!-- BAD CODE DO NOT USE.-->
            <DataTemplate> <!-- BAD CODE DO NOT USE.-->
                <!--This background is unnecessary and can be removed-->
                <Grid Background="Blue"/> <!-- BAD CODE DO NOT USE.-->
            </DataTemplate> <!-- BAD CODE DO NOT USE.-->
        </GridView.ItemTemplate> <!-- BAD CODE DO NOT USE.-->
    </GridView> <!-- BAD CODE DO NOT USE.-->
    
    
    

    Em vez disso, faça isto.

    
    <GridView Background="Blue">  
        <GridView.ItemTemplate> 
            <DataTemplate> 
                <Grid/> 
            </DataTemplate>
        </GridView.ItemTemplate>
    </GridView> 
    
    
    
  • Prefira que um elemento Border desenhe uma borda em torno de um objeto em vez de usar outros objetos para representar uma borda. Neste exemplo, Grid e TextBox usam muitos dos mesmos pixels. Onde ocorre a sobreposição, os pixels são preenchidos duas vezes.

    
    <!-- BAD CODE DO NOT USE.-->
    <Grid Background="Blue" Width="300" Height="45"> <!-- BAD CODE DO NOT USE.-->
        <Grid.RowDefinitions> <!-- BAD CODE DO NOT USE.-->
            <RowDefinition Height="5"/> <!-- BAD CODE DO NOT USE.-->
            <RowDefinition/> <!-- BAD CODE DO NOT USE.-->
            <RowDefinition Height="5"/> <!-- BAD CODE DO NOT USE.-->
        </Grid.RowDefinitions> <!-- BAD CODE DO NOT USE.-->
        <Grid.ColumnDefinitions> <!-- BAD CODE DO NOT USE.-->
            <ColumnDefinition Width="5"/> <!-- BAD CODE DO NOT USE.-->
            <ColumnDefinition/> <!-- BAD CODE DO NOT USE.-->
            <ColumnDefinition Width="5"/> <!-- BAD CODE DO NOT USE.-->
        </Grid.ColumnDefinitions> <!-- BAD CODE DO NOT USE.-->
        <TextBox Grid.Row="1" Grid.Column="1"></TextBox> <!-- BAD CODE DO NOT USE.-->
    </Grid> <!-- BAD CODE DO NOT USE.-->
    
    
    

    Mas este exemplo desenha uma borda em torno de TextBox sem a criação de áreas sobrepostas de pixels a serem preenchidos.

    
    <Border BorderBrush="Blue" BorderThickness="5" Width="300" Height="45">
        <TextBox/>
    </Border>
    
    
    
  • Cuidado com seus tamanhos de margem. Dois elementos vizinhos podem se sobrepor acidentalmente caso suas margens se estendam pelos limites um do outro, o que fará com que os pixels sejam preenchidos duas vezes.

A propriedade DebugSettings.IsOverdrawHeatMapEnabled ajuda você a determinar onde e quando um aplicativo desenha objetos em cima uns dos outros. Não é incomum localizar objetos sendo desenhados e que talvez você nem soubesse que eles estavam na cena

Armazenar conteúdo estático em cache

Você pode criar um elemento conceitualmente discreto usando várias subformas sobrepostas. A estrutura redesenha cada local em que os elementos se sobrepõem. É possível eliminar isso definindo CacheMode como BitmapCache no UIElement que contém o elemento conceitual inteiro. Fazer isso permite que a estrutura renderize o elemento para um bitmap uma vez e então use esse bitmap em vez de renderizar novamente os sub-objetos a cada quadro.

Suponha que você tenha criado um logotipo que se pareça com um diagrama de Venn de três círculos. É possível criar esse objeto rapidamente com um XAML simples.


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


Diagrama de Venn com três círculos sólidos

Fica claro que os sub-elementos do logotipo se sobrepõem. Sempre que o hardware gráfico desenhar isso, levará tempo preenchendo os pixels de cada círculo. A imagem a seguir mostra as áreas desenhadas em sobreposição. O vermelho mais escuro indica maiores quantidades de desenho em sobreposição.

Diagrama de Venn que mostra áreas sobrepostas

Como o logotipo é um objeto completo que sempre tem a mesma aparência, você pode eliminar o desenho sobreposto definindo a propriedade CacheMode no UIElement pai. Nestse exemplo, o aplicativo cria o elemento uma vez, o armazena em cache e então usa a versão em cache em vez de desenhar cada círculo sempre que redesenhar o logotipo.


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


Não use essa técnica se qualquer uma das subformas for animada, porque sempre que um desses elementos for alterado, o cache de bitmap precisará ser regenerado.

 

 

Mostrar:
© 2017 Microsoft