Пути улучшения скорости рендеринга интерфейса пользователя WPF

В случае, если экран приложения WPF содержит множество примитивных элементов управления, его рендеринг становится вялым. Каковы рекомендуемые способы повышения быстродействия приложения WPF в таком случае, кроме добавления меньшего количества элементов управления и использования более мощной видеокарты?

Есть ли способ как-то использовать закадровую буферизацию или что-то в этом роде?

4 ответа

Решение

Наша команда столкнулась с проблемами производительности рендеринга. В нашем случае у нас есть около 400 транспортных единиц, и мы должны визуализировать диаграмму каждой единицы с большим количеством деталей (текстовые метки, специальные метки, различные геометрии и т. Д.).

В первых наших реализациях мы разбили каждую диаграмму на примитивы и с помощью привязки скомпоновали всю диаграмму объекта. Это был очень грустный опыт. Реакция интерфейса была крайне медленной.

Поэтому мы решили создать по одному элементу пользовательского интерфейса на каждую единицу и визуализировать диаграмму с DrawingContext. Хотя это было намного лучше в плане производительности, мы потратили около месяца на улучшение рендеринга.

Несколько советов:

  1. Кэшируйте все. Кисти, цвета, геометрия, форматированные тексты, глифы. (Например, у нас есть два класса: RenderTools а также TextCache, Процесс рендеринга каждого модуля обращается к общему экземпляру обоих классов. Так что, если две диаграммы имеют одинаковый текст, его подготовка выполняется только один раз.)
  2. замерзать Freezable, если вы планируете использовать его в течение длительного времени. Особенно геометрии. Сложные незамерзающие геометрии выполняют HitTest крайне медленно.
  3. Выберите самые быстрые способы рендеринга каждого примитива. Например, существует около 6 способов рендеринга текста, но самый быстрый DrawingContext.DrawGlyphs,
  4. Используйте профилировщик, чтобы обнаружить горячие точки. Например, в нашем проекте мы имели кеш геометрии и отображали соответствующие по требованию. Казалось, что улучшения невозможны. Но однажды мы подумали, что если мы будем рендерить геометрию один раз и кэшировать готовые визуальные эффекты? В нашем случае такой подход оказался приемлемым. Диаграмма нашего подразделения имеет только несколько состояний. Когда данные диаграммы меняются, мы перестраиваем DrawingVisual для каждого состояния и помещаем их в кеш.

Конечно, этот путь требует некоторых вложений, это скучная и скучная работа, но результат потрясающий.

Кстати, когда мы включили опцию кэширования WPF (вы можете найти ссылку в ответах), наше приложение зависло.

У меня была такая же проблема перфорирования с сильно настроенной сеткой данных с одного года, и мой вывод:

в принципе вы ничего не можете сделать на своей стороне (не затрагивая ваше приложение, то есть: имея меньше элементов управления или используя только стили по умолчанию)

Ссылка, упомянутая Йенсом, великолепна, но бесполезна в вашем случае.

Ссылка "Оптимизация производительности приложений WPF", предоставленная NVM, практически одинаково бесполезна в моем опыте: она просто обращается к здравому смыслу, и я уверен, что вы не узнаете ничего экстраординарного и в чтении. Возможно, кроме одного: я должен сказать, что эта ссылка научила меня вкладывать столько, сколько я могу в ресурс моего приложения. Поскольку WPF не восстанавливает ничего, что вы помещаете в ресурс, он просто использует один и тот же ресурс снова и снова. Поэтому поместите туда столько, сколько сможете (стили, кисти, шаблоны, шрифты...)

В общем, в WPF просто нет возможности ускорить процесс, просто выбрав один вариант или отключив другой. Вы можете просто попросить MS переработать слой рендеринга в ближайшем будущем, чтобы оптимизировать его, а тем временем постараться уменьшить ваши потребности в эффектах, настраиваемых элементах управления и так далее...

Взгляните на новую (.NET 4.0) опцию кэширования. (Смотрите здесь.)

Я столкнулся с похожей проблемой и хочу поделиться своими мыслями и находками. Первоначальная проблема вызвана виртуализированным списком, в котором отображается около 25 сложных элементов управления (сетка с текстовым блоком и несколькими кнопками внутри, отображающими некоторые пути). Для исследования проблемы я использовал временную шкалу приложения VisualStudio, которая позволяет определить, сколько времени на это требуется. для визуализации каждого элемента управления и PerfView, чтобы узнать, что на самом деле WPF делает для визуализации каждого элемента управления. По умолчанию рендеринг каждого элемента занимал около 12 мсек. Это довольно долго, если вам нужно динамически обновлять список. Сложно использовать PerfView для анализа того, что происходит внутри, поскольку WPF отображает элемент в иерархии родитель-потомок, но я получил общее представление о внутренних процессах. WPF выполняет следующие действия для отображения каждого элемента в списке:

  1. Анализируйте шаблон с помощью средства чтения XAML. Насколько я понимаю, самая большая проблема - это синтаксический анализ XAML.
  2. Применить стили
  3. Применить привязки

Применение стилей и привязок не займет много времени.

Я сделал следующее, чтобы улучшить производительность:

  1. У каждой кнопки есть собственный шаблон, и на его рендеринг уходит много времени. Я заменил кнопки на границы. После этого на рендеринг каждого элемента уходит около 4-5 мсек.
  2. Перенести все настройки элементов в стили. Около 3мс.
  3. Создайте настраиваемый элемент управления с единой сеткой в ​​шаблоне. Я создаю все дочерние элементы в коде и применяю стили с помощью метода TryFindResources. В результате около 2 мс.

После всех этих изменений производительность выглядит нормально, но по-прежнему большая часть времени уходит на кодирование шаблона ListControl.Item и шаблона настраиваемого элемента управления. 4. Последний шаг: замените ListControl элементами управления Canvas и Scrollbar. Теперь все элементы создаются во время выполнения, а положение вычисляется вручную с помощью методов MeasureOverride и ArrangeOverride. Теперь для рендеринга каждого элемента требуется <1 мс, из которых 0,5 мс тратится на рендеринг TextBlock.

Я до сих пор использую стили и привязки, поскольку они не сильно влияют на производительность при изменении данных. Вы можете себе представить, что это не решение WPF. Но мне нравится несколько подобных списков в приложении, и можно вообще не использовать шаблоны.

Другие вопросы по тегам