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
привязка также более читабельна.