Nota
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
App Analysis es una herramienta que proporciona a los desarrolladores una notificación de problemas de rendimiento. App Analysis ejecuta el código de la aplicación en un conjunto de directrices de rendimiento y procedimientos recomendados.
App Analysis identifica problemas a partir de un conjunto de reglas sobre problemas comunes de rendimiento que enfrentan las aplicaciones. Cuando proceda, el análisis de aplicaciones apuntará a la herramienta de escala de tiempo, la información de origen y la documentación de Visual Studio para proporcionarle los medios para investigar.
Las reglas de Análisis de aplicaciones hacen referencia a una guía o procedimiento recomendado en el que se comprueba la aplicación.
Tamaño de imagen descodificado mayor que el tamaño de representación
Las imágenes se capturan en resoluciones muy altas, lo que puede provocar que las aplicaciones usen más CPU al descodificar los datos de imagen y más memoria después de cargarse desde el disco. Pero no hay sentido descodificar y guardar una imagen de alta resolución en la memoria solo para mostrarla más pequeña que su tamaño nativo. En su lugar, cree una versión de la imagen con el tamaño exacto que se dibujará en pantalla mediante las propiedades DecodePixelWidth y DecodePixelHeight.
Impacto
La visualización de imágenes en sus tamaños no nativos puede afectar negativamente al tiempo de CPU (debido a la descodificación del tamaño adecuado y el tiempo de descarga) y la memoria.
Causas y soluciones
La imagen no se establece de forma asincrónica
La aplicación usa SetSource() en lugar de SetSourceAsync(). Siempre debe evitar usar SetSource y, en su lugar, usar SetSourceAsync al establecer una secuencia para descodificar imágenes de forma asincrónica.
Se llama a image cuando ImageSource no está en el árbol activo
BitmapImage está conectado al árbol XAML activo después de establecer el contenido con SetSourceAsync o UriSource. Siempre debe adjuntar una imagen bitmap al árbol en vivo antes de establecer el origen. Cada vez que se especifique un elemento de imagen o pincel en el marcado, esto ocurrirá automáticamente. A continuación se proporcionan ejemplos.
Ejemplos de árboles vivos
Ejemplo 1 (correcto): identificador uniforme de recursos (URI) especificado en el marcado.
<Image x:Name="myImage" UriSource="Assets/cool-image.png"/>
Ejemplo 2 de marcado: URI especificado en código subyacente.
<Image x:Name="myImage"/>
Ejemplo 2 de buen código subyacente: vincular BitmapImage al árbol antes de establecer su UriSource.
var bitmapImage = new BitmapImage();
myImage.Source = bitmapImage;
bitmapImage.UriSource = new URI("ms-appx:///Assets/cool-image.png", UriKind.RelativeOrAbsolute);
Ejemplo 2 de código subyacente (incorrecto): establezca el UriSource de BitmapImage antes de conectarlo al árbol.
var bitmapImage = new BitmapImage();
bitmapImage.UriSource = new URI("ms-appx:///Assets/cool-image.png", UriKind.RelativeOrAbsolute);
myImage.Source = bitmapImage;
El pincel de imagen no es rectangular
Cuando se utiliza una imagen para un pincel no rectangular, la imagen seguirá una ruta de rasterización por software, que no escalará las imágenes en absoluto. Además, debe almacenar una copia de la imagen en la memoria de software y hardware. Por ejemplo, si una imagen se usa como pincel para una elipse, la potencialmente gran imagen completa se almacenará dos veces internamente. Al usar un pincel no rectangular, la aplicación debe escalar previamente sus imágenes a aproximadamente el tamaño en el que se representarán.
Como alternativa, puede establecer un tamaño de descodificación explícito para crear una versión de la imagen en el tamaño exacto en el que se dibujará en pantalla mediante las propiedades de DecodePixelWidth y DecodePixelHeight.
<Image>
<Image.Source>
<BitmapImage UriSource="ms-appx:///Assets/highresCar.jpg"
DecodePixelWidth="300" DecodePixelHeight="200"/>
</Image.Source>
</Image>
Las unidades de DecodePixelWidth y DecodePixelHeight son de forma predeterminada píxeles físicos. La propiedad DecodePixelType puede usarse para cambiar este comportamiento: establecer DecodePixelType en Logical da como resultado que el tamaño de descodificación tenga en cuenta automáticamente el factor de escala actual del sistema, similar a otros contenidos XAML. Por lo tanto, sería generalmente apropiado establecer DecodePixelType en Lógico si, por ejemplo, desea que DecodePixelWidth y DecodePixelHeight coincidan con las propiedades Height y Width del control Image en el que se mostrará la imagen. Con el comportamiento predeterminado de usar píxeles físicos, deberá tener en cuenta el factor de escala actual del sistema, y deberá escuchar las notificaciones sobre cambios de escala en caso de que el usuario cambie sus preferencias de visualización.
En algunos casos en los que no se puede determinar un tamaño de descodificación adecuado con antelación, debes aplazar la descodificación automática del tamaño correcto de XAML, lo que hará un mejor esfuerzo para descodificar la imagen con el tamaño adecuado si no se especifica un DecodePixelWidth/DecodePixelHeight explícito.
Debe establecer un tamaño de descodificación explícito si conoce el tamaño del contenido de la imagen con antelación. También debes en conjunto establecer DecodePixelType en Lógico si el tamaño de descodificación proporcionado es relativo a otros tamaños de elemento XAML. Por ejemplo, si establece explícitamente el tamaño de contenido con Image.Width e Image.Height, podría establecer DecodePixelType en DecodePixelType.Logical para usar las mismas dimensiones de píxeles lógicas que un control Image y, a continuación, usar explícitamente BitmapImage.DecodePixelWidth o BitmapImage.DecodePixelHeight para controlar el tamaño de la imagen para lograr ahorros de memoria potencialmente grandes.
Tenga en cuenta que Image.Stretch debe tenerse en cuenta al determinar el tamaño del contenido descodificado.
Las imágenes utilizadas dentro de las BitmapIcons se decodifican a su tamaño natural
Establezca un tamaño de descodificación explícito para crear una versión de la imagen con el tamaño exacto que se mostrará en pantalla mediante las propiedades DecodePixelWidth y DecodePixelHeight.
Las imágenes que aparecen extremadamente grandes en la pantalla vuelven a descodificarse al tamaño natural
Las imágenes que aparecen extremadamente grandes en la pantalla se redimensionan a su tamaño natural. Establezca un tamaño de descodificación explícito para crear una versión de la imagen con el tamaño exacto que se mostrará en pantalla mediante las propiedades DecodePixelWidth y DecodePixelHeight.
La imagen está oculta
La imagen se oculta configurando la opacidad a 0 o la visibilidad a Oculto en el elemento de imagen anfitrión, el pincel o cualquier elemento primario. Las imágenes no visibles en la pantalla debido al recorte o la transparencia pueden volver a descodificarse a su tamaño natural.
La imagen usa la propiedad NineGrid
Cuando se usa una imagen para una NineGrid, la imagen usará una ruta de rasterización por software, que no redimensionará imágenes en absoluto. Además, debe almacenar una copia de la imagen en la memoria de software y hardware. Al usar NineGrid, la aplicación debe escalar previamente sus imágenes a aproximadamente el tamaño en el que se representarán.
Las imágenes que usan la propiedad NineGrid vuelven a descodificarse en tamaño natural. Considere la posibilidad de agregar el efecto ninegrid a la imagen original.
DecodePixelWidth o DecodePixelHeight se establecen en un tamaño mayor que la imagen aparecerá en la pantalla.
Si DecodePixelWidth/Height se establecen explícitamente más grandes que la imagen que se mostrará en pantalla, la aplicación usará innecesariamente memoria adicional, hasta 4 bytes por píxel, lo que se vuelve costoso para imágenes grandes. La imagen también se reducirá mediante el escalado bilineal, lo que podría causar que se vea borrosa con factores de escala grandes.
La imagen se descodifica como parte de la generación de una imagen de arrastrar y colocar
Establezca un tamaño de descodificación explícito para crear una versión de la imagen con el tamaño exacto que se mostrará en pantalla mediante las propiedades DecodePixelWidth y DecodePixelHeight.
Elementos contraídos en tiempo de carga
Un patrón común en las aplicaciones es ocultar elementos en la interfaz de usuario inicialmente y mostrarlos más adelante. En la mayoría de los casos, estos elementos deben aplazarse mediante x:Load o x:DeferLoadStrategy para evitar pagar el costo de crear el elemento en tiempo de carga.
Esto incluye los casos en los que se usa un convertidor booleano a la visibilidad para ocultar elementos hasta un momento posterior.
Impacto
Los elementos colapsados se cargan junto con otros elementos y contribuyen a aumentar el tiempo de carga.
Causa
Esta regla se desencadenó porque un elemento se contraía en tiempo de carga. Contraer un elemento o establecer su opacidad en 0 no impide la creación del elemento. Esta regla podría deberse a una aplicación que usa un convertidor de visibilidad booleano que tiene como valor predeterminado false.
Solución
Utilizando el atributo x:Load o x:DeferLoadStrategy, puede demorar la carga de un elemento de la interfaz de usuario y cargarlo cuando sea necesario. Esta es una buena manera de retrasar el procesamiento de la interfaz de usuario que no está visible en el primer fotograma. Puede optar por cargar el elemento cuando sea necesario o como parte de un conjunto de lógica retrasada. Para desencadenar la carga, llame a findName en el elemento que desea cargar. x:Load amplía las capacidades de x:DeferLoadStrategy, que permite desactivar los elementos y controlar el estado de carga a través de x:Bind.
En algunos casos, es posible que el uso de findName para mostrar una parte de la interfaz de usuario no sea la respuesta. Esto es cierto si espera obtener una parte significativa de la interfaz de usuario en el clic de un botón con una latencia muy baja. En este caso, es posible que prefieras incrementar la latencia de la interfaz de usuario a costa de memoria adicional; si es así, debes usar x:DeferLoadStrategy y establecer Visibility en Collapsed en el elemento que deseas cargar. Una vez cargada la página y el subproceso de la interfaz de usuario está libre, puede llamar a findName cuando sea necesario para cargar los elementos. Los elementos no serán visibles para el usuario hasta que establezca la visibilidad del elemento en Visible.
ListView no está virtualizado
La virtualización de la interfaz de usuario es la mejora más importante que puede realizar para mejorar el rendimiento de la recopilación. Esto significa que los elementos de la interfaz de usuario que representan los elementos se crean a petición. Para un control de elementos enlazado a una colección de 1000 elementos, sería un desperdicio de recursos para crear la interfaz de usuario para todos los elementos al mismo tiempo porque no se pueden mostrar todos al mismo tiempo. ListView y GridView (y otros controles estándar derivados de ItemsControl) realizan la virtualización de la interfaz de usuario automáticamente. Cuando los elementos están a punto de desplazarse para ser visibles (a unas pocas páginas de distancia), la estructura genera la interfaz de usuario para los elementos y los almacena en caché. Cuando es poco probable que se vuelvan a mostrar los elementos, el marco vuelve a reclamar la memoria.
La virtualización de la interfaz de usuario es solo uno de los factores clave para mejorar el rendimiento de la recopilación. Reducir la complejidad de los elementos de recopilación y la virtualización de datos son otros dos aspectos importantes para mejorar el rendimiento de la recopilación. Para obtener más información sobre cómo mejorar el rendimiento de la colección en ListViews y GridViews, consulte los artículos sobre la optimización de la interfaz de usuario de ListView y GridView y la virtualización de datos de ListView y Gridview.
Impacto
Un itemsControl no virtualizado aumentará el tiempo de carga y el uso de recursos cargando más de sus elementos secundarios de los necesarios.
Causa
El concepto de una ventanilla es fundamental para la virtualización de la interfaz de usuario, ya que el marco debe crear los elementos que probablemente se muestren. En general, el viewport de un ItemsControl es la extensión del control lógico. Por ejemplo, el área de visualización de un control ListView es la anchura y la altura del elemento ListView. Algunos paneles permiten espacios ilimitados de elementos secundarios, ejemplos como ScrollViewer y Grid, con filas o columnas de tamaño automático. Cuando un ItemsControl virtualizado se coloca en un panel como ese, toma suficiente espacio para mostrar todos sus elementos, lo que derrota la virtualización.
Solución
Restaure la virtualización estableciendo un ancho y alto en el ItemsControl que está utilizando.
Subproceso de interfaz de usuario bloqueado o inactivo durante la carga
El bloqueo de subprocesos de la interfaz de usuario hace referencia a llamadas sincrónicas a funciones que ejecutan fuera del subproceso que bloquean el subproceso de la interfaz de usuario.
Para obtener una lista completa de los procedimientos recomendados para mejorar el rendimiento de inicio de la aplicación, consulta Procedimientos recomendados para el rendimiento de inicio de la aplicación y Mantener la capacidad de respuesta del subproceso de interfaz de usuario.
Impacto
Un subproceso de interfaz de usuario bloqueado o inactivo durante el tiempo de carga impedirá el diseño y otras operaciones de interfaz de usuario, lo que aumentará el tiempo de inicio.
Causa
El código de la plataforma para la interfaz de usuario y el código de la aplicación para la interfaz de usuario se ejecutan en el mismo subproceso de interfaz de usuario. Solo se puede ejecutar una instrucción en ese subproceso a la vez, por lo que si el código de la aplicación tarda demasiado tiempo en procesar un evento, el marco no puede ejecutar el diseño ni generar nuevos eventos que representen la interacción del usuario. La capacidad de respuesta de la aplicación está relacionada con la disponibilidad del hilo de UI para procesar trabajo.
Solución
La aplicación puede ser interactiva aunque haya partes de la aplicación que no sean totalmente funcionales. Por ejemplo, si la aplicación muestra datos que tardan un tiempo en recuperarse, puede hacer que ese código se ejecute independientemente del código de inicio de la aplicación recuperando los datos de forma asincrónica. Cuando los datos estén disponibles, rellene la interfaz de usuario de la aplicación con los datos. Para ayudar a mantener la capacidad de respuesta de la aplicación, la plataforma proporciona versiones asincrónicas de muchas de sus API. Una API asincrónica garantiza que el subproceso de ejecución activo nunca se bloquee durante un período de tiempo significativo. Al llamar a una API desde el subproceso de interfaz de usuario, use la versión asincrónica si está disponible.
{Binding} se usa en lugar de {x:Bind}
Esta regla se desencadena cuando tu aplicación utiliza una declaración {Binding}. Para mejorar el rendimiento de la aplicación, las aplicaciones deben considerar el uso de {x:Bind}.
Impacto
{Binding} se ejecuta en más tiempo y más memoria que {x:Bind}.
Causa
La aplicación usa {Binding} en lugar de {x:Bind}. {Binding} aporta un conjunto de trabajo no trivial y una sobrecarga de CPU. La creación de un {Binding} provoca una serie de asignaciones y la actualización de un objetivo de enlace puede causar reflexión y "boxing".
Solución
Utiliza la extensión de marcado {x:Bind}, que compila vinculaciones en tiempo de compilación. Los enlaces {x:Bind} (a menudo denominados enlaces compilados) tienen un gran rendimiento, proporcionan una validación en tiempo de compilación de las expresiones de enlace y admiten la depuración al permitirle establecer puntos de interrupción en los archivos de código que se generan como la clase parcial de la página.
Tenga en cuenta que x:Bind no es adecuado en todos los casos, como en escenarios vinculados tardíamente. Para obtener una lista completa de los casos no cubiertos por {x:Bind}, consulte la documentación de {x:Bind}.
x:Name se usa en lugar de x:Key
Los resourceDictionaries se usan generalmente para almacenar los recursos en un nivel algo global, es decir, los recursos a los que la aplicación quiere hacer referencia en varios lugares; por ejemplo, estilos, pinceles, plantillas, etc. En general, hemos optimizado ResourceDictionaries para no crear instancias de recursos a menos que se les solicite. Pero hay pocos lugares en los que necesitas tener un poco de cuidado.
Impacto
Se creará una instancia de cualquier recurso con x:Name en cuanto se cree ResourceDictionary. Esto sucede porque x:Name indica a la plataforma que la aplicación necesita acceso de campo a este recurso, por lo que la plataforma debe crear algo para crear una referencia.
Causa
La aplicación está estableciendo x:Name en un recurso.
Solución
Use x:Key en lugar de x:Name cuando no haga referencia a recursos desde código subyacente.
El control de colecciones usa un panel sin virtualización
Si proporciona una plantilla de panel de elementos personalizados (vea ItemsPanel), asegúrese de usar un panel de virtualización como ItemsWrapGrid o ItemsStackPanel. Si usa VariableSizedWrapGrid, WrapGrid o StackPanel, no obtendrá la virtualización. Además, los siguientes eventos de ListView solo se generan cuando se usa el ItemsWrapGrid o el ItemsStackPanel: ChoosingGroupHeaderContainer, ChoosingItemContainer y ContainerContentChanging.
La virtualización de la interfaz de usuario es la mejora más importante que puede realizar para mejorar el rendimiento de la recopilación. Esto significa que los elementos de la interfaz de usuario que representan los elementos se crean a petición. Para un control de elementos enlazado a una colección de 1000 elementos, sería un desperdicio de recursos para crear la interfaz de usuario para todos los elementos al mismo tiempo porque no se pueden mostrar todos al mismo tiempo. ListView y GridView (y otros controles estándar derivados de ItemsControl) realizan la virtualización de la interfaz de usuario automáticamente. Cuando los elementos están a punto de desplazarse para ser visibles (a unas pocas páginas de distancia), la estructura genera la interfaz de usuario para los elementos y los almacena en caché. Cuando es poco probable que se vuelvan a mostrar los elementos, el marco vuelve a reclamar la memoria.
La virtualización de la interfaz de usuario es solo uno de los factores clave para mejorar el rendimiento de la recopilación. Reducir la complejidad de los elementos de recopilación y la virtualización de datos son otros dos aspectos importantes para mejorar el rendimiento de la recopilación. Para obtener más información sobre cómo mejorar el rendimiento de la colección en ListViews y GridViews, consulte los artículos sobre la optimización de la interfaz de usuario de ListView y GridView y la virtualización de datos de ListView y Gridview.
Impacto
Un itemsControl no virtualizado aumentará el tiempo de carga y el uso de recursos cargando más de sus elementos secundarios de los necesarios.
Causa
Está usando un panel que no admite la virtualización.
Solución
Use un panel de virtualización como ItemsWrapGrid o ItemsStackPanel.
Accesibilidad: elementos UIA sin nombre
En XAML, puedes proporcionar un nombre estableciendo AutomationProperties.Name. Muchos sistemas del mismo nivel de automatización proporcionan un nombre predeterminado a UIA si AutomationProperties.Name está sin establecer.
Impacto
Si un usuario llega a un elemento sin nombre, a menudo no tendrá forma de saber a qué se relaciona el elemento.
Causa
El nombre UIA del elemento es nulo o está vacío. Esta regla comprueba qué ve UIA, no el valor del AutomationProperties.Name.
Solución
Establezca la propiedad AutomationProperties.Name en el XAML del control a una cadena localizada apropiada.
A veces, la solución adecuada para la aplicación no es proporcionar un nombre, sino quitar el elemento UIA de todos los árboles excepto los sin procesar. Puedes hacerlo en XAML estableciendo AutomationProperties.AccessibilityView = "Raw"
.
Accesibilidad: los elementos UIA con el mismo Controltype no deben tener el mismo nombre
Dos elementos UIA con el mismo elemento primario UIA no deben tener el mismo Nombre y ControlType. Está bien tener dos controles con el mismo nombre si tienen diferentes ControlTypes.
Esta regla no comprueba si hay nombres duplicados con distintos padres. Sin embargo, en la mayoría de los casos, no se deben duplicar Nombres y Tipos de Control en toda una ventana, incluso con diferentes padres. Los casos en los que los nombres duplicados dentro de una ventana son aceptables son dos listas con elementos idénticos. En este caso, se espera que los elementos de lista tengan Nombres idénticos y Tipos de Control.
Impacto
Si un usuario llega a un elemento con el mismo Nombre y ControlType que otro elemento con el mismo elemento primario UIA, es posible que el usuario no pueda distinguir la diferencia entre los elementos.
Causa
Los elementos UIA con el mismo elemento primario UIA tienen el mismo Nombre y ControlType.
Solución
Establezca un nombre en XAML mediante AutomationProperties.Name. En las listas en las que suele producirse esto, use el enlace para enlazar el valor del AutomationProperties.Name a un origen de datos.