【问题标题】:ElementName vs. RelativeResource?ElementName vs.RelativeResource?
【发布时间】:2010-11-30 18:24:33
【问题描述】:

以下哪些 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 不同?)

【问题讨论】:

  • 偏离性能主题的注释(但仍然是 ElementNameRelativeSource):请记住,ElementName'早期绑定',而 @987654333 @ 是 'late-binding',这可能会导致意想不到的结果,如我的这个问题所示:stackoverflow.com/questions/18419041/…

标签: wpf binding performance relativesource elementname


【解决方案1】:

通过争论你认为哪个会更快来尝试回答这类问题通常是一个糟糕的主意。最好构建一个实验来衡量它。

我稍微修改了您的设置 - 我将相关的 Xaml 放入 UserControl,并绑定到 Name 属性,因为 UserControl 没有 Title 属性。然后我编写了一些代码来创建控件的新实例并将其添加到 UI,并使用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 个绑定文本块,我向用户控件添加了另外 10 个空的、未绑定的、命名的文本块。这里的想法是引入更多命名事物 - ElementName 现在必须在 11 个命名事物中找到一个命名项目。 ElementName 的平均值现在是 2775us。带有这 10 个额外命名元素的 RelativeSource 方法出现在 3041us。

再次,我怀疑我的台式机上的可变性 - RelativeSource 在这里的表现明显比在应该更多 ElementName 的优势的场景中表现得更差。

无论如何,确实似乎相当清楚的是,这里的加载成本对元素数量的敏感程度远高于对您使用的绑定样式的敏感度。 ElementName 显然有一个小优势,但足够小(并且结果也足够奇怪),足以让人怀疑得出它必然更快的结论的有效性。

因此,我们可以构建更仔细的实验​​以获得更好的画面。但在我看来,如果你不能最终证明在普通计算机上运行时性能上有显着差异,那么争论哪个更快基本上是在浪费时间。

因此,总而言之:在这里关注性能是错误的。选择更易读的代码。

【讨论】:

  • 很棒的帖子。 :) 我对性能差异很好奇。但是,将重点放在哪个更易读的 xaml 上是有意义的。 :)
  • 感谢 Ian 为这个出色的答案所做的努力!
【解决方案2】:

两者中的后者需要遍历可视化树以寻找特定的祖先类型,而先验直接查看窗口的名称范围以查找具有该名称的已注册对象...我猜后者会稍微慢一些...也就是说,我认为不会有显着的性能差异。

希望对你有帮助,

Aj

【讨论】:

  • 有道理,但问题是它如何查找一个名字,因为如果这个名字有太多的兄弟姐妹、叔叔和叔叔,那么对于每个级别,它都会搜索所有这些,而使用 @ 987654322@ 它只会寻找祖先。另一方面,我认为获取每个祖先的类型 (GetType) 的操作本身可能比仅获取兄弟姐妹的名称需要更长的时间,更不用说许多控件未命名,字符串比较甚至更快。如果您可以将答案依赖于真实来源,例如使用反射器、msdn 等进行搜索,我将不胜感激。
  • @Shimmy,我认为正确的测试证明相当困难,至少无论如何要产生准确和一致的结果。老实说,我认为这超出了我的想象,因此我不想发布一些不仅仅是有根据的猜测。不过,在谈到这个话题时,我读了 Josh Smith 的一篇文章,他讨论了逻辑树和可视树;不考虑性能差异,但他确实包含了一个遍历视觉和逻辑树的示例应用程序。也许您可以使用它来深入了解您的询问 - codeproject.com/KB/WPF/WpfElementTrees.aspx
【解决方案3】:

一般情况下,应尽可能使用ElementName

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

我通过在实际应用程序中将一些 FindAncestor 绑定更改为 ElementName 绑定获得了 SECONDS。

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

【讨论】:

    猜你喜欢
    • 2012-05-15
    • 1970-01-01
    • 2016-05-02
    • 2012-02-25
    • 2012-10-12
    • 1970-01-01
    • 1970-01-01
    • 2022-10-01
    • 2012-07-14
    相关资源
    最近更新 更多