ElementName или RelativeResource?

Какая из следующих привязок TextBlocks стоит больше производительности:

<Window  
  x:Name="Me"
  x:Class="MainWindow"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
  xmlns:src="clr-namespace:WpfApplication1" 
  Title="MainWindow">
  <StackPanel>
    <TextBlock Text="{Binding Title, ElementName=Me}"/>
    <TextBlock Text="{Binding Title, RelativeSource={RelativeSource AncestorType={x:Type src:MainWindow}}}"/>
  </StackPanel>    
</Window>

Я уверен, что мой вопрос может быть другим, когда TextBlocks находятся на высоком уровне вложенности, имея много братьев и сестер и предков.

Соображения

(основываясь только на личных мыслях, я могу ошибаться в каждом конкретном случае!)

  • ElementName:

    • Можно поискать и сравнить текущий элемент, чтобы лучше контролировать всех его детей, братьев и сестер, дядей и великих дядей, включая предков (может быть, существует HashTable всех зарегистрированных имен?)
    • Получение Name свойство элемента управления должно стоить меньше производительности, чем вызов GetType,
    • Сравнение строки дешевле, чем сравнение типов, особенно если вы знаете, что большинство элементов управления даже не имеют своих Name задавать.
  • FindAncestor:

    • Будет повторяться только через предков, а не братьев и сестер, братьев и сестер и т.д.
    • Скорее всего использует GetType определить тип предка; GetType стоит больше производительности, чем простой Name получатель собственности (может быть, DP разные?)

2 ответа

Решение

Обычно это ужасная идея - пытаться ответить на подобные вещи, споря о том, что, по вашему мнению, будет быстрее. Гораздо лучше построить эксперимент для его измерения.

Я немного изменил ваши настройки - я поместил соответствующий Xaml в UserControl и привязал к Name собственность с UserControl не имеет Title имущество. Затем я написал некоторый код для создания нового экземпляра элемента управления и добавления его в пользовательский интерфейс и использовал Stopwatch измерить время, необходимое для его создания и загрузки. (Я запускаю синхронизацию непосредственно перед созданием пользовательского элемента управления и останавливаюсь сразу после того, как пользовательский элемент управления повышает его Loaded событие.)

Я запускаю этот код из DispatcherTimer 20 раз в секунду, поэтому я могу сделать много измерений в надежде уменьшить экспериментальную ошибку. Чтобы минимизировать искажения из-за кода отладки и диагностики, я работаю в сборке Release и вычисляю и печатаю среднее значение только после 2000 итераций.

После 2000 итераций ElementName подход в среднем 887us.

После 2000 итераций RelativeSource подход в среднем 959us.

Так ElementName в этом конкретном эксперименте, немного быстрее, чем RelativeSource, Загрузка тривиальная UserControl только с Grid и один TextBlock где есть только один названный элемент, ElementName подход занимает 92% времени, чтобы загрузить, что RelativeSource подход требует.

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

Я повторил эксперимент с 10 TextBlocks вместо 1. ElementName затем в среднем 2020us в то время как RelativeSource подход составил в среднем 2073us, снова более 2000 итераций для обоих тестов. Как ни странно, здесь есть меньшая разница, не только в относительном выражении, но и в абсолютном выражении - примеры с одним элементом показали разницу в 72 мкс, тогда как примеры из десяти элементов показали разницу в 53 мкс.

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

Еще один вариант: все еще с 10 связанными текстовыми блоками, я добавил еще десять пустых, несвязанных, именованных текстовых блоков в пользовательский элемент управления. Идея состояла в том, чтобы представить более именованные вещи - ElementName теперь должен найти именованный предмет в 11 именованных вещах. Среднее за ElementName сейчас 2775us. RelativeSource подход с этими дополнительными 10 названными элементами вышел в 3041us.

Опять же, я подозреваю изменчивость на моем настольном компьютере здесь - кажется странным, что RelativeSource здесь значительно хуже, чем в сценарии, который должен был быть ElementName Преимущество

В любом случае, что кажется достаточно ясным, так это то, что стоимость загрузки здесь гораздо более чувствительна к количеству элементов, чем к тому, какой стиль привязки вы используете. Очевидно, есть небольшое преимущество ElementName но достаточно маленький (и с достаточно странными результатами), чтобы вызвать подозрение в правильности заключения о том, что это обязательно быстрее.

Таким образом, мы могли бы построить более тщательные эксперименты, чтобы получить лучшую картину. Но, на мой взгляд, если вы не можете убедительно продемонстрировать существенную разницу в производительности при работе на обычном компьютере, то спорить о том, что быстрее, - это просто трата времени.

Итак, в заключение: производительность - это неправильная вещь, на которой нужно концентрироваться. Выберите тот, который делает для более читабельного кода.

Последнему из этих двух нужно пройтись по визуальному дереву в поисках определенного типа предка, где, как и предыдущий, смотрит прямо в область имен окна для зарегистрированного объекта с таким именем... я думаю, что позднее будет немного медленнее... Тем не менее, я не думаю, что будет существенная разница в производительности.

Надеюсь, поможет,

Aj

В целом ElementName следует использовать, когда это возможно.

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

Я получил СЕКУНДЫ, изменив некоторые FindAncestor привязки к ElementName привязки в реальном приложении.

ИМХО ElementName привязка также более читабельна.

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