6

FindAncestor在Window的整个Visual树中搜索一个元素吗?

如果是,那我该如何改进呢?

binding data error如果我们通过使用 Find Ancestor 查找元素来访问对象的属性并且不存在这样的元素,是否会抛出?

如果是,那么我该如何解决这样的错误。

在我的情况下,绑定错误是在输出窗口上抛出的。为了解决这个错误,我尝试了设置FallbackValue,但现在它给了我警告而不是错误,这是唯一的区别。其他一切都与错误相同。

有人能告诉我究竟是如何FindAncestor工作的吗?

4

3 回答 3

4

如果你想知道FindAncestor内部是如何工作的,你应该阅读内部代码。http://referencesource.microsoft.com/#PresentationFramework/Framework/MS/Internal/Data/ObjectRef.cs,6a2d9d6630cad93d

您应该尝试不要使用 FindAncestor那么多。它可能会很慢,而且孩子们不应该依赖“在某个地方有一个父母有我需要的东西”的知识。

也就是说,FindAncestor它有时也可以成为你的朋友。

这取决于您的情况,但例如,通常DataGridRow使用 whichFindAncestor来查找有关DataGrid或某些其他父元素的信息。

问题在于:它非常慢。假设您有 1000 个 DataGridRows,每行使用FindAncestor,加上每行有 7 列,它本身必须遍历逻辑树中的约 200 个元素。它不必很慢,DataGridRow始终具有相同的父级DataGrid,可以轻松缓存。也许“一次性缓存的 relativeSources”将是一个新概念。

这个概念可以是这样的:编写你自己的 relativeSource 绑定。第一次完成绑定后,使用可视化树助手查找特定类型的父级。如果这样做了,您可以将找到的父级存储在直接父级 attachewd 属性中,如下所示:

var dic = myElementThatUsesRelativeSourceBinding.Parent.
      GetCurrentValue(MyCachedRelativeSourceParentsProperty) 
          as Dictionary<Type, UIElement>;

dic[foundType] = actualValue;

稍后,您在稍后搜索相关源时使用此缓存信息。而不是采用 O(n),而是采用 O(1) 来处理父级的相同元素/子级。

如果您知道父级始终存在,您应该在代码隐藏中为每个尝试使用的元素创建绑定FindAncestor。这样可以避免遍历树。

您还可以创建一个混合解决方案来跟踪视觉树的变化,并维护“缓存”。如果 aDataGridRow要求“find me relative source off type DataGrid”,你没有理由一直这样做:你可以缓存它。有OnVisualChildrenChanged- 只是一个想法,甚至不能 100% 确定它是否可以很好地完成,但这需要额外的内存和字典。

这可能会变得非常复杂,不用说:-),但对于“副业”来说会很酷。

在另一边;您还应该展平视觉树,它会提高您的速度。

于 2014-12-31T16:51:39.090 回答
1

在使用EnumerationFindAncestor的值作为Property时,您还可以设置要使用Property查找的祖先级别。从最后一个链接页面:RelativeSourceModeRelativeSource.ModeRelativeSource.AncestorLevel

使用[a value of] 1 表示最接近绑定目标元素的元素。

于 2014-12-22T11:57:40.583 回答
1

关于“寻祖”的内容不多。它工作简单,这就是它快速的原因。它的工作原理是这样的:总是询问元素的父元素的类型。如果类型与您需要的类型不匹配。父元素成为实际元素,并且再次重复该过程。这就是为什么“查找祖先”总是使视觉树向上但从不向下的原因:)

我认为您可能会感觉到RelativeSource 绑定存在一些性能问题的唯一可能原因是当您进入ListBox并且您确实定义了一个包含一堆RelativeSource 绑定的令人讨厌的项目模板时。ListBox倾向于虚拟化东西,这意味着它跟踪数据项但重新创建它们的容器。总而言之,你开始滚动,你滚动得越快,这些视觉容器被重新创建的频率就越高。最后,每次重新创建容器时,相对源绑定都会尝试寻找给定的祖先类型。这是我现在能想到的唯一一种情况,你最终会滞后几毫秒。但这还不错。。

您是否遇到过这样的问题?请告诉我们更多关于您的问题

像 Sheridan 一样,我会让那些错误成为 :) 但是如果你那么讨厌它们,你可以使用桥梁

ABridge是您需要自己实现的东西。

看看这个链接:http ://social.technet.microsoft.com/wiki/contents/articles/12355.wpfhowto-avoid-binding-error-when-removing-a-datagrid-row-with-relativesource-static -bridgerelay.aspx

基本上,您将该桥元素Xaml作为资源放在您的某处,当您需要时,您RelativeSource可以使用StaticResource扩展,如下所示:

Binding="{Binding MyPath, Source={StaticResource MyBridge}}"

试试看

于 2014-12-29T10:28:41.647 回答