Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Анализ приложений — это средство, которое предоставляет разработчикам уведомление о проблемах с производительностью. Анализ приложений проверяет код вашего приложения на соответствие набору рекомендаций и передовым практикам по производительности.
Анализ приложений выявляет проблемы из набора правил, включающего общие проблемы производительности, с которыми сталкиваются приложения. При необходимости анализ приложений будет указывать на инструмент таймлайна Visual Studio, сведения об источнике и документацию, чтобы дать вам возможность изучить.
Правила в анализе приложений представляют собой руководящие принципы или лучшие практики, по которым проверяется ваше приложение.
Размер декодированного изображения больше размера отрисовки
Изображения записываются с очень высоким разрешением, что может привести к приложениям, использующим больше ЦП при декодировании данных изображения и больше памяти после загрузки с диска. Нет смысла декодировать и сохранять в памяти изображение с высоким разрешением только для того, чтобы показывать его в размере меньше оригинального. Вместо этого создайте версию изображения с точным размером, который будет использоваться на экране, с помощью свойств DecodePixelWidth и DecodePixelHeight.
Воздействие
Отображение изображений в своих неродных размерах может негативно повлиять на время ЦП (из-за декодирования до правильного размера и времени загрузки) и памяти.
Причины и решения
Изображение не устанавливается асинхронно
Приложение использует SetSource() вместо SetSourceAsync(). Всегда следует избегать использования SetSource и вместо этого использовать SetSourceAsync при настройке потока для декодирования изображений асинхронно.
Изображение вызывается, если ImageSource не находится в динамическом дереве
BitmapImage подключается к динамическому дереву XAML после задания содержимого с помощью SetSourceAsync или UriSource. Перед настройкой источника всегда следует подключить BitmapImage к динамическому дереву. В любой момент, когда элемент изображения или кисть указан в разметке, это будет автоматически происходить. Ниже приведены примеры.
Примеры живых деревьев
Пример 1 (хорошо) — универсальный идентификатор ресурса (URI), указанный в разметке.
<Image x:Name="myImage" UriSource="Assets/cool-image.png"/>
Пример 2 разметки — URI, указанный в коде за кулисами.
<Image x:Name="myImage"/>
Пример 2 кода позади (хорошо) — подключение BitmapImage к дереву перед настройкой UriSource.
var bitmapImage = new BitmapImage();
myImage.Source = bitmapImage;
bitmapImage.UriSource = new URI("ms-appx:///Assets/cool-image.png", UriKind.RelativeOrAbsolute);
Пример 2 (плохо) — установка UriSource объекта BitmapImage перед подключением к дереву.
var bitmapImage = new BitmapImage();
bitmapImage.UriSource = new URI("ms-appx:///Assets/cool-image.png", UriKind.RelativeOrAbsolute);
myImage.Source = bitmapImage;
Кисть изображения не прямоугольная
Если изображение используется для непрямоугольной кисти, изображение будет использовать программный путь растеризации, который не будет масштабировать изображения совсем. Кроме того, он должен хранить копию образа как в программной, так и в аппаратной памяти. Например, если изображение используется в качестве кисти для эллипса, потенциально большое полное изображение будет храниться дважды внутренне. При использовании не прямоугольной кисти приложение должно предварительно масштабировать его изображения до приблизительного размера, в который они будут отображаться.
Кроме того, можно задать явный размер декодера, чтобы создать версию изображения с точным размером, который он будет нарисован на экране с помощью свойств DecodePixelWidth и DecodePixelHeight .
<Image>
<Image.Source>
<BitmapImage UriSource="ms-appx:///Assets/highresCar.jpg"
DecodePixelWidth="300" DecodePixelHeight="200"/>
</Image.Source>
</Image>
Единицы для DecodePixelWidth и DecodePixelHeight по умолчанию являются физическими пикселями. Свойство DecodePixelType можно использовать для изменения этого поведения: установка DecodePixelType в Logical приводит к тому, что размер декодирования автоматически учитывает текущий коэффициент масштабирования системы, аналогично другим элементам XAML. Поэтому, как правило, следует задать DecodePixelType в Logical, если, например, вы хотите, чтобы DecodePixelWidth и DecodePixelHeight соответствовали свойствам высоты и ширины элемента управления "Изображение", в котором будет отображаться изображение. При использовании физических пикселей по умолчанию необходимо самостоятельно учитывать текущий коэффициент масштабирования системы, и вы должны слушать уведомления об изменении масштаба, если пользователь изменяет свои настройки отображения.
В некоторых случаях, когда соответствующий размер декодирования не может быть определен заранее, следует воспользоваться автоматическим подбором размера XAML, который постарается декодировать изображение до нужного размера, если явные параметры DecodePixelWidth/DecodePixelHeight не указаны.
Вы должны задать явный размер декодировки, если вы знаете размер содержимого изображения заранее. Вы также должны совместно установить DecodePixelType в Logical, если указанный размер декодирования соотносится с другими размерами элементов XAML. Например, если вы явно задали размер содержимого с помощью Image.Width и Image.Height, можно задать для DecodePixelType значение DecodePixelType.Logical, чтобы использовать те же логические размеры пикселей, что и элемент управления "Изображение", а затем явно использовать BitmapImage.DecodePixelWidth и/или BitmapImage.DecodePixelHeight, чтобы управлять размером изображения для достижения потенциально большой экономии памяти.
Обратите внимание, что Image.Stretch следует учитывать при определении размера декодированного содержимого.
Изображения, используемые внутри BitmapIcons, декодируются обратно до естественного размера.
Задайте явный размер декодирования, чтобы создать версию изображения с точным размером, в котором оно будет отображаться на экране, используя свойства DecodePixelWidth и DecodePixelHeight.
Изображения, которые отображаются очень большими на экране, возвращаются к декодированию в естественный размер
Изображения, которые отображаются очень большими на экране, обратно декодируются до естественного размера. Задайте явный размер декодирования, чтобы создать версию изображения с точным размером, в котором оно будет отображаться на экране, используя свойства DecodePixelWidth и DecodePixelHeight.
Изображение скрыто
Изображение скрыто путем установки параметра Opacity в значение 0 или параметра Видимость в положение "Свернуто" на элементе узла изображения, кисти или любом родительском элементе. Изображения, не видимые на экране из-за обрезки или прозрачности, могут вернуться к декодированию до своего естественного размера.
Изображение использует свойство NineGrid
Если изображение используется для NineGrid, изображение будет использовать путь растеризации программного обеспечения, который не будет масштабировать изображения вообще. Кроме того, он должен хранить копию образа как в программной, так и в аппаратной памяти. При использовании NineGrid приложение должно предварительно масштабировать его изображения до приблизительного размера, в который они будут отображаться.
Изображения, использующие свойство NineGrid, возвращаются к декодированию в естественный размер. Рассмотрите возможность добавления эффекта ninegrid в исходное изображение.
DecodePixelWidth или DecodePixelHeight установлены в размере, который превышает отображаемый на экране размер изображения
Если параметрам DecodePixelWidth/Height явно заданы значения больше, чем размер изображения, которое будет отображаться на экране, приложение будет излишне потреблять дополнительную память из расчета до 4 байт на пиксель, что может быстро стать дорогостоящим при работе с большими изображениями. Изображение также будет уменьшено с помощью билинейного масштабирования, что может привести к его размытию при больших коэффициентах масштабирования.
Изображение декодируется как часть создания изображения для перетаскивания и сброса.
Задайте явный размер декодирования, чтобы создать версию изображения с точным размером, в котором оно будет отображаться на экране, используя свойства DecodePixelWidth и DecodePixelHeight.
Свёрнутые элементы при загрузке
Распространенный шаблон в приложениях — скрытие элементов в пользовательском интерфейсе и их отображение в дальнейшем. В большинстве случаев эти элементы следует отложить с помощью x:Load или x:DeferLoadStrategy, чтобы избежать оплаты затрат на создание элемента во время загрузки.
Это включает в себя случаи, когда логический преобразователь видимости используется для скрытия элементов до последующего времени.
Воздействие
Свернутые элементы загружаются вместе с другими элементами и способствуют увеличению времени загрузки.
Причина
Это правило было активировано, так как элемент был свернут во время загрузки. Сворачивание элемента или установка его непрозрачности в значение 0 не препятствует созданию элемента. Это правило может быть вызвано приложением, использующим логический преобразователь видимости, который по умолчанию имеет значение false.
Решение
С помощью атрибута x:Load или x:DeferLoadStrategyможно отложить загрузку части пользовательского интерфейса и загружать её по мере необходимости. Это хороший способ отложить обработку пользовательского интерфейса, который не отображается в первом кадре. При необходимости можно загрузить элемент или как часть набора отложенной логики. Чтобы активировать загрузку, вызовите findName в элементе, который требуется загрузить. x:Load расширяет возможности x:DeferLoadStrategy, позволяя выгрузить элементы и управлять состоянием загрузки с помощью x:Bind.
В некоторых случаях использование findName для отображения фрагмента пользовательского интерфейса может не быть ответом. Это верно, если вы ожидаете реализовать значительную часть пользовательского интерфейса по нажатию кнопки с очень низкой задержкой. В этом случае вам может потребоваться сократить задержку пользовательского интерфейса за счет использования дополнительной памяти. Если это так, вы должны использовать x:DeferLoadStrategy и установить для элемента, который требуется реализовать, значение свойства Видимость как Collapsed. После загрузки страницы и когда поток интерфейса пользователя свободен, вы можете вызвать findName, если необходимо загрузить элементы. Элементы не будут видны пользователю, пока вы не установите параметр "Видимость" в положение "Видимый".
ListView не виртуализирован
Виртуализация пользовательского интерфейса — это самое важное улучшение, что позволяет повысить производительность коллекции. Это означает, что элементы пользовательского интерфейса, представляющие элементы, создаются по запросу. Для элемента управления, привязанного к коллекции из 1000 элементов, это будет тратой ресурсов создавать пользовательские интерфейсы для всех элементов сразу, поскольку их нельзя отобразить все в одно и то же время. ListView и GridView (и другие стандартные элементы управления, производные от ItemsControl), выполняют виртуализацию пользовательского интерфейса. Когда элементы находятся близко к появлению на экране (несколько страниц впереди), фреймворк создает для них пользовательский интерфейс и кэширует их. Если маловероятно, что элементы будут отображаться снова, фреймворк освобождает память.
Виртуализация пользовательского интерфейса — это лишь один из нескольких ключевых факторов повышения производительности коллекции. Снижение сложности элементов сбора и виртуализации данных являются двумя другими важными аспектами повышения производительности коллекции. Дополнительные сведения о повышении производительности коллекции в ListView и GridView см. в статьях по оптимизации пользовательского интерфейса ListView и GridView и виртуализации данных ListView и GridView.
Воздействие
Не виртуализированный ItemsControl увеличит время загрузки и использование ресурсов, загрузив больше дочерних элементов, чем необходимо.
Причина
Концепция окна просмотра важна для виртуализации пользовательского интерфейса, так как платформа должна создавать элементы, которые, скорее всего, будут отображаться. Как правило, область просмотра ItemsControl является размером логической области элемента управления. Например, видовая область элемента ListView — это его ширина и высота. Некоторые панели предоставляют дочерним элементам неограниченное пространство, примером являются ScrollViewer и Grid с автоматическими по размеру строками или столбцами. Когда виртуализированный ItemsControl помещается на панель, например, требуется достаточно места для отображения всех его элементов, что приводит к поражению виртуализации.
Решение
Восстановите виртуализацию, задав ширину и высоту используемого элемента ItemsControl.
Поток пользовательского интерфейса заблокирован или бездействует во время загрузки
Блокировка потока пользовательского интерфейса относится к синхронным вызовам функций, выполняемых вне потока, которые блокируют поток пользовательского интерфейса.
Для полного списка рекомендаций по улучшению производительности запуска приложения см. Рекомендации по производительности запуска приложения и Поддержание отзывчивости потока пользовательского интерфейса.
Воздействие
Заблокированный или неактивный поток пользовательского интерфейса во время загрузки будет препятствовать макету и другим операциям пользовательского интерфейса, увеличивая время запуска.
Причина
Код платформы для пользовательского интерфейса и код приложения для пользовательского интерфейса выполняются в одном потоке пользовательского интерфейса. Только одна инструкция может выполняться в этом потоке одновременно, поэтому если код приложения занимает слишком много времени для обработки события, платформа не может запускать макет или создавать новые события, представляющие взаимодействие с пользователем. Скорость реагирования приложения связана с доступностью потока пользовательского интерфейса для обработки работы.
Решение
Ваше приложение может быть интерактивным, даже если есть части приложения, которые не являются полностью функциональными. Например, если приложение отображает данные, которые занимает некоторое время для извлечения, этот код можно выполнить независимо от кода запуска приложения, извлекая данные асинхронно. Когда данные доступны, заполните пользовательский интерфейс приложения данными. Чтобы обеспечить реагирование приложения, платформа предоставляет асинхронные версии многих его API. Асинхронный API гарантирует, что активный поток выполнения никогда не блокируется в течение значительного времени. При вызове API из потока пользовательского интерфейса используйте асинхронную версию, если она доступна.
{Binding} используется вместо {x:Bind}
Это правило запускается при использовании инструкции {Binding} в приложении. Чтобы повысить производительность приложений, приложения должны рассмотреть возможность использования {x:Bind}.
Воздействие
{Binding} требует больше времени и памяти, чем {x:Bind}.
Причина
Приложение использует {Binding} вместо {x:Bind}. {Binding} влечет за собой нетривиальный рабочий объем памяти и нагрузку на ЦП. Создание {Binding} приводит к серии выделений, а обновление целевого объекта привязки может привести к рефлексии и упаковке.
Решение
Используйте расширение разметки {x:Bind}, которое компилирует привязки во время сборки. Привязки {x:Bind} (часто называемые скомпилированные привязки) имеют большую производительность, обеспечивают проверку выражений привязки во время компиляции и поддерживают отладку, позволяя задавать точки останова в файлах кода, созданных как частичный класс для страницы.
Обратите внимание, что x:Bind не подходит во всех случаях, таких как сценарии с поздней привязкой. Полный список случаев, не охваченных {x:Bind}, см. в документации по {x:Bind}.
X:Name используется вместо x:Key
ResourceDictionaries обычно используется для хранения ресурсов на нескольких глобальных уровнях, то есть ресурсов, на которые приложение хочет ссылаться в нескольких местах; например, стили, кисти, шаблоны и т. д. Как правило, мы оптимизируем ResourceDictionaries, чтобы не создавать экземпляры ресурсов, если они не запрашиваются. Но есть несколько мест, где вам нужно быть немного осторожным.
Воздействие
Любой ресурс с x:Name будет создан сразу после создания ResourceDictionary. Это происходит из-за того, что x:Name сообщает платформе, что приложению требуется доступ к этому ресурсу, поэтому платформа должна создать ссылку на нее.
Причина
Приложение задает x:Name для ресурса.
Решение
Используйте x:Key вместо x:Name, если вы не ссылаетесь на ресурсы из программной части.
Элемент управления "Collection" использует не виртуализирующуюся панель.
Если вы предоставляете шаблон панели настраиваемых элементов (см. ItemsPanel), убедитесь, что вы используете панель виртуализации, например ItemsWrapGrid или ItemsStackPanel. Если вы используете VariableSizedWrapGrid, WrapGrid или StackPanel, вы не получите виртуализацию. Кроме того, следующие события ListView вызываются только при использовании ItemsWrapGrid или ItemsStackPanel: ChoosingGroupHeaderContainer, ChoosingItemContainer и ContainerContentChanging.
Виртуализация пользовательского интерфейса — это самое важное улучшение, что позволяет повысить производительность коллекции. Это означает, что элементы пользовательского интерфейса, представляющие элементы, создаются по запросу. Для элемента управления, привязанного к коллекции из 1000 элементов, это будет тратой ресурсов создавать пользовательские интерфейсы для всех элементов сразу, поскольку их нельзя отобразить все в одно и то же время. ListView и GridView (и другие стандартные элементы управления, производные от ItemsControl), выполняют виртуализацию пользовательского интерфейса. Когда элементы находятся близко к появлению на экране (несколько страниц впереди), фреймворк создает для них пользовательский интерфейс и кэширует их. Если маловероятно, что элементы будут отображаться снова, фреймворк освобождает память.
Виртуализация пользовательского интерфейса — это лишь один из нескольких ключевых факторов повышения производительности коллекции. Снижение сложности элементов сбора и виртуализации данных являются двумя другими важными аспектами повышения производительности коллекции. Дополнительные сведения о повышении производительности коллекции в ListView и GridView см. в статьях по оптимизации пользовательского интерфейса ListView и GridView и виртуализации данных ListView и GridView.
Воздействие
Не виртуализированный ItemsControl увеличит время загрузки и использование ресурсов, загрузив больше дочерних элементов, чем необходимо.
Причина
Вы используете панель, которая не поддерживает виртуализацию.
Решение
Используйте панель виртуализации, например ItemsWrapGrid или ItemsStackPanel.
Доступность: элементы UIA без имени
В XAML можно указать имя, задав AutomationProperties.Name. Многие одноранговые узлы автоматизации предоставляют имя по умолчанию для UIA, если AutomationProperties.Name не задано.
Воздействие
Если пользователь достигает элемента без имени, он часто не знает, к чему относится элемент.
Причина
Имя UIA элемента имеет значение NULL или пустое. Это правило проверяет, что видит UIA, а не значение AutomationProperties.Name.
Решение
Задайте для свойства AutomationProperties.Name в XAML элемента управления соответствующую локализованную строку.
Иногда правильным исправлением в приложении может быть не указание имени, а удаление элемента UIA из всех деревьев, кроме необработанных. Это можно сделать в XAML, задав для этого параметр AutomationProperties.AccessibilityView = "Raw".
Специальные возможности: элементы UIA с одинаковым типом управления не должны иметь одинаковое имя.
Два элемента UIA с одинаковым родительским элементом UIA не должны иметь одинаковое имя и тип управления. Это нормально иметь два элемента управления с одинаковым именем, если они имеют разные типы элементов управления.
Это правило не проверяет наличие повторяющихся имен с разными родителями. Однако в большинстве случаев не следует дублировать имена и типы управления в одном окне, даже с разными родителями. Случаи, когда повторяющиеся имена в окне допустимы, являются двумя списками с идентичными элементами. В этом случае элементы списка должны иметь идентичные имена и типы управления.
Воздействие
Если пользователь достигает элемента с тем же именем и ControlType, что и другой элемент с тем же родительским элементом UIA, пользователь может не различать разницу между элементами.
Причина
Элементы UIA с одним и тем же родительским элементом UIA имеют одинаковое имя и тип управления.
Решение
Задайте имя в XAML с помощью AutomationProperties.Name. В списках, где обычно это происходит, используйте привязку для привязки значения AutomationProperties.Name к источнику данных.