FindAncestor
是否在Window的整个Visual树中搜索元素?
如果是,那么我该如何改进呢?
如果我们通过查找具有Find Ancestor&amp ;;的元素来访问对象的属性,则抛出binding data error
没有这样的元素?
如果是,那么我该如何解决这样的错误。
在我的情况下,绑定错误正在抛出输出窗口。为了解决这个错误,我尝试设置FallbackValue
,但现在它给了我警告而不是错误,这是唯一的区别。其他一切都和错误一样。
有人可以告诉我FindAncestor
究竟是如何运作的吗?
答案 0 :(得分:4)
如果您想了解FindAncestor
内部如何工作,您应该阅读内部代码。 http://referencesource.microsoft.com/#PresentationFramework/Framework/MS/Internal/Data/ObjectRef.cs,6a2d9d6630cad93d
您应该尝试不要使用 FindAncestor
那么多。它可能很慢,而且孩子们不应该依赖于“父母哪里有我需要的东西”的知识。
也就是说,FindAncestor
本身也可能是你的朋友。
这取决于您的情况,但是,例如,DataGridRow
使用FindAncestor
来查找有关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
的每个元素创建绑定。这样就可以避免遍历树。
您还可以创建一个混合解决方案,跟踪可视树的变化,并保持“缓存”。如果DataGridRow
要求“找到我的相对来源类型DataGrid
”,则没有理由需要一直这样做:您可以缓存它。有OnVisualChildrenChanged
- 只是一个想法,甚至不能100%确定它是否可以很好地完成,但这需要额外的内存和字典。
这可能变得非常复杂,不用说:-),但对于“侧面项目”来说会很酷。
另一方面;你也应该展平视觉树,它会让你获得速度。
答案 1 :(得分:1)
对RelativeSourceMode
Enumeration使用RelativeSource.Mode
Property的FindAncestor
值时,您还可以使用{{3>设置要查找的祖先级别 }}。从上一个链接页面:
使用 [值] 1表示最接近绑定目标元素的那个。
答案 2 :(得分:0)
关于“寻找祖先”的说法不多。它工作简单,这就是它快速的原因。它的工作原理如下:始终询问元素的父类型。如果类型与您需要的类型不匹配。父项成为实际元素,并且该过程再次重复。这就是为什么“Find Ancestor”总是在视觉树上工作但从不失败的原因:)
我认为您可能会感觉到RelativeSource绑定的某些性能问题的唯一可能原因是当您进入ListBox
时,您确实有一个令人讨厌的项目模板,其中包含一堆RelativeSource绑定。 ListBox
倾向于虚拟化东西,这意味着它会跟踪数据项,但会重新创建容器。总而言之,您开始滚动并且滚动得越快,那些可视容器将被重新创建。最后,每次重新创建容器时,相对源绑定将尝试寻找给定的祖先类型。这是我现在能想到的唯一一个你最终会落后几毫秒的情况。但那还不错..
您是否遇到过类似的问题?请告诉我们有关您的问题的更多信息
像Sheridan一样,我会让那些错误只是:)但是如果你恨他们那么多,你可以使用桥梁
您需要自己实施Bridge
。
基本上,您将该桥元素放在Xaml
作为资源的某个位置,当您需要RelativeSource
时,使用StaticResource
扩展名,而不是这样:
Binding="{Binding MyPath, Source={StaticResource MyBridge}}"
试一试