ElementName 与relativeresource?
以下 TextBlock 的绑定会消耗更多性能:
<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>
我确信当 TextBlock 处于具有许多兄弟姐妹和祖先的高嵌套级别时,我的问题可能会有所不同。
注意事项
(仅基于个人想法,我可能在每个特定的想法上都是错误的!):
ElementName
:- 可能会通过其所有子元素、兄弟姐妹、叔叔和叔祖父(包括祖先)搜索和比较当前元素以进行更多控制(也许有一个包含所有注册名称的哈希表?)
- 获取控件的
Name
属性应该比调用GetType
消耗更少的性能。 - 比较字符串比比较类型更便宜,尤其是当您知道大多数控件甚至没有设置其
Name
时。
查找祖先
:- 只会遍历祖先,而不是兄弟姐妹“叔叔”、“表兄弟”等。
- 很可能使用
GetType
来确定祖先类型; GetType 比简单的Name
属性 getter 花费更多的性能(也许 DP 不同?)
What of the following TextBlocks' Bindings costs more performance:
<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>
I am sure my question might take different when the TextBlocks are in a high nesting level having many siblings and ancestors.
Considerations
(based on personal thoughts only, I might be wrong in each particular one!):
ElementName
:- Might search and compare current element to more control, thru all its children, siblings, uncles and great uncles including ancestors (maybe there is a HashTable of all the registered names?)
- Getting a
Name
property of a control should cost less performance than callingGetType
. - Comparing a string is cheaper than comparing types, especially when you know that most of the controls don't even have their
Name
set.
FindAncestor
:- Will only iterate thru ancestors, not siblingls 'uncles', 'cousins' etc.
- Most likely uses
GetType
to determine ancestor type; GetType costs more performance then a simpleName
property getter (maybe DPs are different?)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
试图通过争论你认为哪个会更快来回答这类问题通常是一个糟糕的主意。最好构建一个实验来测量它。
我稍微修改了您的设置 - 我将相关的 Xaml 放入 UserControl 中,并绑定到
Name
属性,因为UserControl
没有Title
> 财产。然后,我编写了一些代码来创建控件的新实例并将其添加到 UI,并使用秒表来测量构建和加载它所需的时间。 (我在构造用户控件之前开始计时,并在用户控件引发其Loaded
事件后立即停止。)我从
DispatcherTimer
运行此代码 20 次其次,我可以进行大量测量,希望减少实验误差。为了最大限度地减少调试和诊断代码造成的失真,我在发布版本中运行,并且仅在 2000 次迭代完成后计算和打印平均值。经过 2000 次迭代后,
ElementName
方法平均需要 887us。经过 2000 次迭代后,
RelativeSource
方法的平均耗时为 959us。因此,在这个特定的实验中,
ElementName
比RelativeSource
稍快。加载一个简单的UserControl
,其中只有一个Grid
和一个TextBlock
,其中只有一个命名元素,ElementName
方法看起来加载时间是RelativeSource
方法的 92%。当然,我在这里测量一个小的、人为的例子。 ElementName 方法的性能可能会根据范围内命名元素的数量而有所不同。并且可能还有其他不可预见的因素,在实际场景中可能会产生完全不同的结果。因此,如果您想获得更好的图像,我建议您在实际应用程序中执行类似的测量。
我用 10 个 TextBlock(而不是 1 个)重复了该实验。
ElementName
的平均时间为 2020us,而RelativeSource
方法的平均时间为 2073us,两次测试的迭代次数均超过 2000 次。奇怪的是,这里的差异较小,不仅是相对而言,而且是绝对而言 - 单元素示例显示了 72us 的差异,而十元素示例显示了 53us 的差异。我开始怀疑我在主机上运行测试会导致更多的变化,而不是在主机上仔细配置尽可能少的东西以最大程度地减少噪音。
另一种变化:仍然有 10 个绑定文本块,我向用户控件添加了另外 10 个空的、未绑定的命名文本块。这里的想法是引入更多命名事物 -
ElementName
现在必须在 11 个命名事物中找到一个命名项目。ElementName
的平均值现在为 2775us。包含这 10 个额外命名元素的RelativeSource
方法在 3041us 后问世。再次,我怀疑我的桌面计算机上存在变异性 - 奇怪的是,
RelativeSource
在这里的表现明显比在本应该对ElementName
更有优势的情况下表现得更差。不管怎样,看起来相当清楚的是,这里的加载成本对元素数量的敏感度远高于对您使用的绑定样式的敏感度。 ElementName 显然有一个小优势,但足够小(并且结果足够奇怪),足以让人怀疑它必然更快的结论的有效性。
因此我们可以进行更仔细的实验以获得更好的了解。但在我看来,如果你不能最终证明在普通计算机上运行时性能有显着差异,那么争论哪个更快基本上是浪费时间。
所以结论是:这里关注性能是错误的。选择使代码更具可读性的那个。
It's usually a terrible idea to try to answer this sort of thing by arguing about which you think will be faster. Far better to construct an experiment to measure it.
I modified your setup a little - I put the relevant Xaml into a UserControl, and bound to the
Name
property sinceUserControl
doesn't have aTitle
property. I then wrote some code to create a new instance of the control and add it to the UI, and used theStopwatch
to measure the time taken to construct and load it. (I start the timing just before constructing the user control, and I stop just after the user control raises itsLoaded
event.)I run this code from a
DispatcherTimer
20 times a second so I can take lots of measurements in the hope of reducing experimental error. To minimize distortions due to debugging and diagnostic code, I'm running in a Release build, and I only calculate and print the average after 2000 iterations have completed.After 2000 iterations, the
ElementName
approach averages 887us.After 2000 iterations, the
RelativeSource
approach averages 959us.So
ElementName
is, in this particular experiment, slightly quicker thanRelativeSource
. Loading a trivialUserControl
with just aGrid
and oneTextBlock
where there's only one named element, theElementName
approach looks to take 92% of the time to load that theRelativeSource
approach takes.Of course, I'm measuring a small, artificial example here. The performance of the ElementName approach might vary based on how many named elements are in scope. And there may be other unanticipated factors that might produce completely different results in real scenarios. So I would recommend performing similar measurements in the context of a real application if you want to get a better picture.
I repeated the experiment with 10 TextBlocks instead of 1.
ElementName
then averaged 2020us while theRelativeSource
approach averaged 2073us, again over 2000 iterations for both tests. Weirdly, there's a smaller difference here, not just in relative terms, but in absolute terms - the one-element examples showed a difference of 72us, where the ten-element examples showed a difference of 53us.I'm starting to suspect that I'm causing more variability by running my tests on my main machine, rather than one carefully configured with as little stuff as possible to minimize noise.
One more variation: still with 10 bound text blocks, I added ten more empty, unbound, named text blocks to the user control. The idea here was to introduce more named things -
ElementName
now has to locate a named item within 11 named things. The average forElementName
is now 2775us. TheRelativeSource
approach with these extra 10 named elements came out at 3041us.Again, I suspect variability on my desktop machine here - it seems weird that
RelativeSource
has performed significantly worse here than in the scenario that should have been more toElementName
's advantage.Anyway, what does seem reasonably clear is that the cost of loading here is far more sensitive to the number of elements than it is to which style of binding you use. There is apparently a small advantage to
ElementName
but small enough (and with weird enough results) to cast suspicion on the validity of concluding that it is necessarily faster.So we could construct more careful experiments to get a better picture. But in my view, if you can't conclusively demonstrate a significant difference in performance when running on an ordinary computer, then it's basically a waste of time arguing about which is quicker.
So in conclusion: performance is the wrong thing to focus on here. Pick whichever makes for more readable code.
两者中的后者需要遍历视觉树来寻找特定的祖先类型,而前者则直接查看窗口的名称范围以查找具有该名称的注册对象...我的猜测是后者稍微慢一些...也就是说,我认为不会有显着的性能差异。
希望有帮助,
阿杰
The later of the two needs to walk the visual tree looking for a particular ancestor type, where as the prior looks directly to the window's namescope for a registered object with that name...my guess would be the later is marginally slower...that said, I don't think there will be a significant performance difference.
Hope it helps,
Aj
一般来说,应尽可能使用
ElementName
。给出的示例和基准示例非常简单。
在现实世界的示例中,元素具有更大的视觉树,
FindAncestor
绑定必须遍历更多元素才能找到该元素。通过将实际应用程序中的一些
FindAncestor
绑定更改为ElementName
绑定,我获得了几秒的时间。恕我直言,
ElementName
绑定也更具可读性。In general the
ElementName
should be used when possible.The given example and benchmark example is quite simple.
In real world examples the elements have a larger visual tree and the
FindAncestor
binding must traverse a lot more elements in order to find the element.I gained SECONDS by changing some
FindAncestor
bindings toElementName
bindings in a real world application.IMHO the
ElementName
binding is more readable, too.