ElementName与RelativeResource?

时间:2010-11-30 18:24:34

标签: wpf binding performance relativesource elementname

以下哪些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属性getter(可能DP不同?)
    • 的性能更高

3 个答案:

答案 0 :(得分:26)

通过争论你认为哪个更快,试图回答这类事情通常是一个可怕的想法。建立一个测量它的实验要好得多。

我稍微修改了你的设置 - 我将相关的Xaml放入UserControl,并绑定到Name属性,因为UserControl没有Title属性。然后我编写了一些代码来创建控件的新实例并将其添加到UI,并使用Stopwatch来测量构造和加载它所花费的时间。 (我在构建用户控件之前开始计时,并在用户控件引发其Loaded事件后停止。)

我每隔20次从DispatcherTimer运行此代码,因此我可以进行大量测量,以期减少实验误差。为了最大限度地减少由于调试和诊断代码引起的失真,我在Release版本中运行,并且我只计算并打印2000次迭代完成后的平均值。

2000次迭代后,ElementName逼近平均值为887us。

2000次迭代后,RelativeSource逼近平均值为959us。

因此,ElementName在此特定实验中比RelativeSource略快。加载一个只有UserControl和一个Grid的琐碎TextBlock,其中只有一个命名元素,ElementName方法看起来需要92%的时间加载{ {1}}接近。

当然,我在这里测量一个小的,人为的例子。 ElementName方法的性能可能会根据范围内有多少命名元素而有所不同。并且可能存在其他可能在实际情况中产生完全不同结果的意外因素。因此,如果您想获得更好的图片,我建议您在真实应用程序的上下文中执行类似的测量。

我用10个TextBlocks而不是1 RelativeSource重复实验,然后平均2020us,而ElementName方法平均为2073us,两次测试再次超过2000次迭代。奇怪的是,这里有一个较小的差异,不仅仅是相对而言,但从绝对意义上说 - 单元素的例子显示出72us的差异,其中十元素的例子显示出53us的差异。

我开始怀疑我通过在主机上运行我的测试来引起更多的可变性,而不是使用尽可能少的东西仔细配置以最小化噪音。

还有一个变体:仍然有10个绑定文本块,我向用户控件添加了10个空的,未绑定的命名文本块。这里的想法是引入更多命名的东西 - RelativeSource现在必须在11个命名的东西中找到一个命名的项目。 ElementName的平均值现在为2775us。这些额外的10个命名元素的ElementName方法出现在3041us。

同样,我怀疑我的桌面计算机存在多变 - 似乎很奇怪RelativeSource在这方面的表现要比本来应该更加RelativeSource的情况更糟糕。

无论如何, 看起来相当清楚的是,这里的加载成本对元素数量的敏感程度远远高于你使用哪种绑定样式。 ElementName显然有一个小优势,但足够小(并且有足够奇怪的结果)会对有效性产生怀疑,认为它必然更快。

因此,我们可以构建更仔细的实验​​,以获得更好的画面。但在我看来,如果在普通计算机上运行时无法确定地表现出性能上的显着差异,那么基本上浪费时间来争论哪个更快。

总之:在这里关注表现是错误的。选择能够获得更具可读性的代码。

答案 1 :(得分:4)

两个中的后一个需要走视觉树寻找特定的祖先类型,其中,先前直接看到窗口的名称范围内的注册对象具有该名称...我的猜测是后者稍微慢一些......那就是说,我认为不会有明显的性能差异。

希望它有所帮助,

AJ

答案 2 :(得分:1)

通常,应尽可能使用ElementName

给定的示例和基准示例非常简单。 在现实世界中,元素具有较大的可视树,FindAncestor绑定必须遍历更多元素才能找到元素。

在现实应用中,我通过将某些FindAncestor绑定更改为ElementName绑定而获得了SECONDS。

恕我直言,ElementName绑定也更具可读性。