ElementName против RelativeResource?

Что из следующих привязок TextBlocks "Bindings" стоит больше:

<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 стоит больше производительности, чем простой getter Name (может быть, DP разные?)

Ответы

Ответ 1

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

Я немного изменил настройку - я поместил соответствующий 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 итераций для обоих тестов. Как ни странно, здесь здесь меньше различий не только в относительных терминах, но и в абсолютных терминах - одноэлементные примеры показали разницу в 72us, где десятиэлементные примеры показали разницу в 53us.

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

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

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

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

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

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

Ответ 2

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

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

Aj