Nota
O acesso a esta página requer autorização. Pode tentar iniciar sessão ou alterar os diretórios.
O acesso a esta página requer autorização. Pode tentar alterar os diretórios.
A Análise de Aplicativos é uma ferramenta que fornece aos desenvolvedores uma notificação prévia de problemas de desempenho. A Análise de Aplicativo executa o código do seu aplicativo em relação a um conjunto de diretrizes de desempenho e práticas recomendadas.
A Análise de Aplicativos identifica problemas a partir de um conjunto de regras de problemas comuns de desempenho com os quais os aplicativos se deparam. Quando apropriado, a análise da aplicação apontará para a ferramenta de linha do tempo, as informações de origem e a documentação do Visual Studio para fornecer as ferramentas necessárias para investigar.
As regras na Análise de Aplicativos referem-se a uma diretriz ou prática recomendada contra a qual seu aplicativo está sendo verificado.
Tamanho da imagem decodificada maior que o tamanho da renderização
As imagens são capturadas em resoluções muito altas, o que pode levar os aplicativos a usar mais CPU ao decodificar os dados da imagem e mais memória depois que ela é carregada do disco. Mas não faz sentido decodificar e salvar uma imagem de alta resolução na memória apenas para exibi-la menor do que seu tamanho nativo. Em vez disso, crie uma versão da imagem no tamanho exato em que ela será desenhada na tela usando as propriedades DecodePixelWidth e DecodePixelHeight.
Impacto
A exibição de imagens em seus tamanhos não nativos pode afetar negativamente o tempo da CPU (devido à decodificação para o tamanho e o tempo de download adequados) e a memória.
Causas e soluções
A imagem não está sendo definida de forma assíncrona
O aplicativo está usando SetSource() em vez de SetSourceAsync(). Você deve sempre evitar usar SetSource e, em vez disso, usar SetSourceAsync ao definir um fluxo para decodificar imagens de forma assíncrona.
A imagem está sendo chamada quando o ImageSource não está na árvore ativa
BitmapImage é conectado à árvore XAML ativa depois de definir o conteúdo com SetSourceAsync ou UriSource. Você sempre deve anexar um BitmapImage à árvore ativa antes de definir a origem. Sempre que um elemento de imagem ou pincel for especificado na marcação, esse será automaticamente o caso. Seguem-se alguns exemplos.
Exemplos de árvores vivas
Exemplo 1 (bom) — URI (Uniform Resource Identifier) especificado na marcação.
<Image x:Name="myImage" UriSource="Assets/cool-image.png"/>
Exemplo de marcação 2 — URI especificada em code-behind.
<Image x:Name="myImage"/>
Exemplo 2 de code-behind (bom) — ligando o BitmapImage à árvore de elementos antes de definir o seu UriSource.
var bitmapImage = new BitmapImage();
myImage.Source = bitmapImage;
bitmapImage.UriSource = new URI("ms-appx:///Assets/cool-image.png", UriKind.RelativeOrAbsolute);
Exemplo 2 código subjacente (inadequado) — ao definir o UriSource da BitmapImage antes de conectá-lo à árvore.
var bitmapImage = new BitmapImage();
bitmapImage.UriSource = new URI("ms-appx:///Assets/cool-image.png", UriKind.RelativeOrAbsolute);
myImage.Source = bitmapImage;
O pincel de imagem não é retangular
Quando uma imagem é usada para um pincel não retangular, a imagem seguirá um caminho de rasterização por software, que não escalará as imagens. Além disso, ele deve armazenar uma cópia da imagem na memória de software e hardware. Por exemplo, se uma imagem for usada como pincel para uma elipse, a imagem potencialmente grande e completa será armazenada duas vezes internamente. Ao usar um pincel não retangular, seu aplicativo deve pré-dimensionar suas imagens para aproximadamente o tamanho em que serão renderizadas.
Como alternativa, você pode definir um tamanho de decodificação explícito para criar uma versão da imagem no tamanho exato em que ela será desenhada na tela usando as propriedades DecodePixelWidth e DecodePixelHeight.
<Image>
<Image.Source>
<BitmapImage UriSource="ms-appx:///Assets/highresCar.jpg"
DecodePixelWidth="300" DecodePixelHeight="200"/>
</Image.Source>
</Image>
As unidades para DecodePixelWidth e DecodePixelHeight são, por padrão, pixels físicos. A propriedade DecodePixelType pode ser usada para alterar esse comportamento: definir DecodePixelType como Logical resulta no tamanho da decodificação contabilizando automaticamente o fator de escala atual do sistema, semelhante a outro conteúdo XAML. Portanto, seria geralmente apropriado definir DecodePixelType como Logical se, por exemplo, pretenderes que DecodePixelWidth e DecodePixelHeight correspondam às propriedades de altura e largura do controlo de Imagem no qual a imagem será exibida. Com o comportamento padrão de usar pixels físicos, você mesmo deve levar em conta o fator de escala atual do sistema e ouvir as notificações de alteração de escala caso o usuário altere suas preferências de exibição.
Em alguns casos em que um tamanho de decodificação apropriado não pode ser determinado com antecedência, deve-se recorrer à decodificação automática de tamanho adequado do XAML, que fará um esforço para decodificar a imagem no tamanho apropriado se não for especificado um DecodePixelWidth/DecodePixelHeight explícito.
Você deve definir um tamanho de decodificação explícito se souber o tamanho do conteúdo da imagem com antecedência. Você deve também definir em conjunto DecodePixelType como Logical se o tamanho de decodificação fornecido for relativo a outros tamanhos de elemento XAML. Por exemplo, se você definir explicitamente o tamanho do conteúdo com Image.Width e Image.Height, poderá definir DecodePixelType como DecodePixelType.Logical para usar as mesmas dimensões lógicas de pixel de um controle Image e, em seguida, usar explicitamente BitmapImage.DecodePixelWidth e/ou BitmapImage.DecodePixelHeight para controlar o tamanho da imagem para obter economias de memória potencialmente grandes.
Observe que Image.Stretch deve ser considerado ao determinar o tamanho do conteúdo decodificado.
As imagens usadas dentro de BitmapIcons são decodificadas para o tamanho natural.
Defina um tamanho de decodificação explícito para criar uma versão da imagem no tamanho exato em que ela será desenhada na tela, usando as propriedades DecodePixelWidth e DecodePixelHeight com e .
As imagens que aparecem extremamente grandes no ecrã são decodificadas para o tamanho natural
As imagens que aparecem extremamente grandes no ecrã são redimensionadas para o tamanho natural. Defina um tamanho de decodificação explícito para criar uma versão da imagem no tamanho exato em que ela será desenhada na tela, usando as propriedades DecodePixelWidth e DecodePixelHeight com e .
A imagem está oculta
A imagem fica oculta definindo Opacidade como 0 ou Visibilidade como Recolhida no elemento ou pincel da imagem do host ou em qualquer elemento pai. Imagens não visíveis no ecrã devido a recorte ou transparência podem ser redimensionadas para o tamanho natural.
A imagem está usando a propriedade NineGrid
Quando uma imagem é usada para um NineGrid, a imagem usará um caminho de rasterização de software, que não redimensionará as imagens. Além disso, ele deve armazenar uma cópia da imagem na memória de software e hardware. Ao usar o NineGrid, seu aplicativo deve pré-dimensionar suas imagens para aproximadamente o tamanho em que serão renderizadas.
As imagens que usam a propriedade NineGrid voltam à decodificação para tamanho natural. Considere adicionar o efeito ninegrid à imagem original.
DecodePixelWidth ou DecodePixelHeight são definidos para um tamanho maior do que a imagem aparecerá na tela
Se DecodePixelWidth/Height forem explicitamente definidos maiores do que a imagem que será exibida no ecrã, a aplicação usará desnecessariamente memória extra, até cerca de 4 bytes por pixel, o que rapidamente pode tornar-se dispendioso para imagens grandes. A imagem também será reduzida usando escala bilinear, o que pode fazer com que pareça desfocada para fatores de grande escala.
A imagem é decodificada como parte da produção de uma imagem de arrastar e soltar
Defina um tamanho de decodificação explícito para criar uma versão da imagem no tamanho exato em que ela será desenhada na tela, usando as propriedades DecodePixelWidth e DecodePixelHeight com e .
Elementos recolhidos ao carregar
Um padrão comum em aplicativos é ocultar elementos na interface do usuário inicialmente e mostrá-los posteriormente. Na maioria dos casos, esses elementos devem ser adiados usando x:Load ou x:DeferLoadStrategy para evitar pagar o custo de criação do elemento no tempo de carregamento.
Isso inclui casos em que um conversor booleano para visibilidade é usado para ocultar itens até um momento posterior.
Impacto
Os elementos recolhidos são carregados juntamente com outros elementos e contribuem para um aumento no tempo de carregamento.
Motivo
Esta regra foi acionada porque um elemento foi recolhido durante o carregamento. Recolher um elemento, ou definir a sua opacidade como 0, não impede que o elemento seja criado. Esta regra pode ocorrer devido a um aplicativo que usa um conversor de Booleano para visibilidade, que por padrão é 'false'.
Solução
Usando o atributo x:Load ou x:DeferLoadStrategy, pode-se atrasar o carregamento de uma parte da interface de utilizador e carregá-la quando necessário. Essa é uma boa maneira de atrasar o processamento da interface que não é visível no primeiro fotograma. Você pode optar por carregar o elemento quando necessário ou como parte de um conjunto de lógica atrasada. Para acionar o carregamento, chame findName no elemento que você deseja carregar. x:Load estende os recursos de x:DeferLoadStrategy permitindo que os elementos sejam descarregados e que o estado de carregamento seja controlado via x:Bind.
Em alguns casos, usar findName para mostrar uma parte da interface do usuário pode não ser a resposta. Isso é verdade se você estiver esperando conseguir realizar uma parte significativa da interface do utilizador ao clicar num botão com latência muito baixa. Nesse caso, você pode querer trocar a latência mais rápida da interface do usuário ao custo de memória adicional, se assim for, você deve usar x:DeferLoadStrategy e definir Visibility como Collapsed no elemento que deseja realizar. Depois que a página for carregada e o thread da interface do usuário estiver livre, você poderá chamar findName quando necessário para carregar os elementos. Os elementos não ficarão visíveis para o usuário até que você defina a Visibilidade do elemento como Visível.
ListView não está virtualizado
A virtualização da interface do usuário é a melhoria mais importante que você pode fazer para melhorar o desempenho da coleção. Isso significa que os elementos da interface do usuário que representam os itens são criados sob demanda. Para um controle de itens vinculado a uma coleção de 1000 itens, seria um desperdício de recursos criar a interface do usuário para todos os itens ao mesmo tempo, porque eles não podem ser exibidos todos ao mesmo tempo. ListView e GridView (e outros controles padrão derivados de ItemsControl) executam a virtualização da interface do usuário para você. Quando os itens estão perto de serem rolados para a exibição (a algumas páginas de distância), a estrutura gera a interface do usuário para os itens e os armazena em cache. Quando é improvável que os itens sejam mostrados novamente, a estrutura recupera a memória.
A virtualização da interface do usuário é apenas um dos vários fatores-chave para melhorar o desempenho da coleção. A redução da complexidade dos itens de coleta e a virtualização de dados são dois outros aspetos importantes para melhorar o desempenho da coleção. Para obter mais informações sobre como melhorar o desempenho da coleção em ListView e GridView, consulte os artigos sobre otimização da interface do utilizador de ListView e GridView e sobre virtualização de dados de ListView e GridView .
Impacto
Um ItemsControl não virtualizado aumentará o tempo de carregamento e o uso de recursos carregando mais itens filhos do que o necessário.
Motivo
O conceito de um visor é crítico para a virtualização da interface do usuário porque a estrutura deve criar os elementos que provavelmente serão mostrados. Em geral, a janela de visualização de um ItemsControl é a extensão do controlo lógico. Por exemplo, a área de visualização de um ListView é a largura e a altura do elemento ListView. Alguns painéis permitem aos elementos filho espaço ilimitado, sendo exemplos o ScrollViewer e um Grid, com linhas ou colunas de tamanho automático. Quando um ItemsControl virtualizado é colocado em um painel como esse, ele ocupa espaço suficiente para exibir todos os seus itens, o que derrota a virtualização.
Solução
Restaure a virtualização definindo uma largura e altura no ItemsControl que você está usando.
Thread da interface do usuário bloqueado ou ocioso durante o carregamento
O bloqueio de thread da interface do usuário refere-se a chamadas síncronas para funções executadas fora do thread que bloqueiam o thread da interface do usuário.
Para obter uma lista completa das melhores práticas para melhorar o desempenho de inicialização da sua aplicação, consulte Práticas recomendadas para o desempenho de inicialização da sua aplicação e Manter o thread da interface do utilizador responsivo.
Impacto
Um thread de interface do usuário bloqueado ou ocioso durante o tempo de carregamento impedirá o layout e outras operações da interface do usuário, aumentando o tempo de inicialização.
Motivo
O código da plataforma para a interface do usuário e o código do seu aplicativo para a interface do usuário são executados no mesmo thread da interface do usuário. Apenas uma instrução pode ser executada nesse thread de cada vez, portanto, se o código do seu aplicativo demorar muito para processar um evento, a estrutura não poderá executar layout ou gerar novos eventos que representem a interação do usuário. A capacidade de resposta do seu aplicativo está relacionada à disponibilidade do thread da interface do usuário para processar o trabalho.
Solução
Seu aplicativo pode ser interativo mesmo que haja partes do aplicativo que não são totalmente funcionais. Por exemplo, se seu aplicativo exibir dados que levam um tempo para serem recuperados, você poderá fazer com que esse código seja executado independentemente do código de inicialização do aplicativo recuperando os dados de forma assíncrona. Quando os dados estiverem disponíveis, preencha a interface do usuário do aplicativo com os dados. Para ajudar a manter seu aplicativo responsivo, a plataforma fornece versões assíncronas de muitas de suas APIs. Uma API assíncrona garante que seu thread de execução ativo nunca seja bloqueado por um período significativo de tempo. Quando você chamar uma API a partir do thread da interface do usuário, use a versão assíncrona, se estiver disponível.
{Binding} está sendo usado em vez de {x:Bind}
Esta regra é disparada quando a sua aplicação utiliza uma instrução {Binding}. Para melhorar o desempenho do aplicativo, os aplicativos devem considerar o uso de {x:Bind}.
Impacto
{Binding} é executado em mais tempo e mais memória do que {x:Bind}.
Motivo
O aplicativo está usando {Binding} em vez de {x:Bind}. {Binding} traz consigo um conjunto de trabalho não trivial e sobrecarga de CPU. Criar um {Binding} causa uma série de alocações, e atualizar um destino de vinculação pode causar reflexão e encaixotamento.
Solução
Use a extensão de marcação {x:Bind}, que compila associações em tempo de compilação. As ligações {x:Bind} (muitas vezes referidas como ligações compiladas) têm um ótimo desempenho, fornecem validação em tempo de compilação de suas expressões de vinculação e suportam depuração, permitindo que você defina pontos de interrupção nos arquivos de código que são gerados como a classe parcial para sua página.
Observe que x:Bind não é adequado em todos os casos, como cenários de ligação tardia. Para obter uma lista completa de casos não cobertos por {x:Bind}, consulte a documentação {x:Bind}.
x:Name está sendo usado em vez de x:Key
Os Dicionários de Recursos geralmente são usados para armazenar seus recursos em um nível um pouco global, ou seja, recursos que seu aplicativo deseja referenciar em vários locais; por exemplo, estilos, pincéis, modelos e assim por diante. Em geral, otimizamos o ResourceDictionaries para não instanciar recursos, a menos que sejam solicitados. Mas há poucos lugares onde você precisa ter um pouco de cuidado.
Impacto
Qualquer recurso com x:Name será instanciado assim que o ResourceDictionary for 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.
Motivo
Seu aplicativo está definindo x:Name em um recurso.
Solução
Use x:Key em vez de x:Name quando não estiver fazendo referência a recursos do code-behind.
O controle de coleções está usando um painel não virtualizador
Se você fornecer um modelo de painel de itens personalizado (consulte ItemsPanel), certifique-se de usar um painel de virtualização, como ItemsWrapGrid ou ItemsStackPanel. Se você usar VariableSizedWrapGrid, WrapGrid ou StackPanel, não obterá virtualização. Além disso, os seguintes eventos ListView são gerados somente ao usar um ItemsWrapGrid ou um ItemsStackPanel: ChoosingGroupHeaderContainer, ChoosingItemContainer e ContainerContentChanging.
A virtualização da interface do usuário é a melhoria mais importante que você pode fazer para melhorar o desempenho da coleção. Isso significa que os elementos da interface do usuário que representam os itens são criados sob demanda. Para um controle de itens vinculado a uma coleção de 1000 itens, seria um desperdício de recursos criar a interface do usuário para todos os itens ao mesmo tempo, porque eles não podem ser exibidos todos ao mesmo tempo. ListView e GridView (e outros controles padrão derivados de ItemsControl) executam a virtualização da interface do usuário para você. Quando os itens estão perto de serem rolados para a exibição (a algumas páginas de distância), a estrutura gera a interface do usuário para os itens e os armazena em cache. Quando é improvável que os itens sejam mostrados novamente, a estrutura recupera a memória.
A virtualização da interface do usuário é apenas um dos vários fatores-chave para melhorar o desempenho da coleção. A redução da complexidade dos itens de coleta e a virtualização de dados são dois outros aspetos importantes para melhorar o desempenho da coleção. Para obter mais informações sobre como melhorar o desempenho da coleção em ListView e GridView, consulte os artigos sobre otimização da interface do utilizador de ListView e GridView e sobre virtualização de dados de ListView e GridView .
Impacto
Um ItemsControl não virtualizado aumentará o tempo de carregamento e o uso de recursos carregando mais itens filhos do que o necessário.
Motivo
Você está usando um painel que não oferece suporte à virtualização.
Solução
Use um painel de virtualização, como ItemsWrapGrid ou ItemsStackPanel.
Acessibilidade: elementos UIA sem nome
Em XAML, você pode fornecer um nome definindo AutomationProperties.Name. Muitos pares de automação fornecem um nome padrão para UIA se AutomationProperties.Name não estiver definido.
Impacto
Se um usuário chegar a um elemento sem nome, muitas vezes não terá como saber com o que o elemento se relaciona.
Motivo
O nome da UIA do elemento é nulo ou vazio. Esta regra verifica o que a UIA vê, não o valor do AutomationProperties.Name.
Solução
Defina a propriedade AutomationProperties.Name no XAML do controle como uma cadeia de caracteres localizada apropriada.
Às vezes, a correção correta do aplicativo não é fornecer um nome, é remover o elemento UIA de todos, exceto das árvores brutas. Você pode fazer isso em XAML definindo AutomationProperties.AccessibilityView = "Raw".
Acessibilidade: elementos UIA com o mesmo Controltype não devem ter o mesmo nome
Dois elementos da UIA com o mesmo pai da UIA não devem ter o mesmo Name e ControlType. Não há problema em ter dois controles com o mesmo Nome se eles tiverem ControlTypes diferentes.
Esta regra não verifica a existência de nomes duplicados com pais diferentes. No entanto, na maioria dos casos, você não deve duplicar Names e ControlTypes dentro de uma janela inteira, mesmo com pais diferentes. Os casos em que nomes duplicados dentro de uma janela são aceitáveis são duas listas com itens idênticos. Nesse caso, espera-se que os itens da lista tenham Names e ControlTypes idênticos.
Impacto
Se um utilizador atingir um elemento com o mesmo nome e tipo de controlo que outro elemento com o mesmo pai na interface de utilizador, o utilizador pode ter dificuldade para distinguir entre os elementos.
Motivo
Os elementos da UIA que têm o mesmo pai de UIA têm o mesmo "Name" e "ControlType".
Solução
Defina um nome em XAML usando AutomationProperties.Name. Em listas onde isso geralmente ocorre, use a associação para vincular o valor do AutomationProperties.Name a uma fonte de dados.