FindAncestor是否在整个窗口的视觉树中搜索元素?
如果是,那我该如何改进呢?
如果通过查找具有查找祖先的元素来访问对象的属性,是否会引发binding data error &不存在这样的元素?
如果是,那么我如何解决这样的错误。
在我的例子中,绑定错误正在输出窗口上抛出。为了解决这个错误,我尝试设置FallbackValue,但是现在它给了我警告而不是错误,这是唯一的区别。其他的一切都是错误。
有人能告诉我FindAncestor到底是怎么工作的吗?
发布于 2014-12-31 16:51:39
如果您想知道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绑定。第一次完成绑定后,使用可视树帮助器查找特定类型的父级。如果这样做了,您可以将已找到的父级存储在直接父级附加项属性中,如下所示:
var dic = myElementThatUsesRelativeSourceBinding.Parent.
GetCurrentValue(MyCachedRelativeSourceParentsProperty)
as Dictionary<Type, UIElement>;
dic[foundType] = actualValue;稍后,在搜索相对源时使用此缓存信息。它不是取O(n),而是对父元素/子元素取O(1)。
如果您知道父元素总是存在的,那么应该在代码隐藏中为每个尝试使用FindAncestor的元素创建绑定。这样你就可以避免穿过树。
您还可以创建一个混合解决方案来跟踪可视树的变化,并主要实现“缓存”。如果DataGridRow请求“在DataGrid类型下查找相对源”,那么您没有理由一直这样做:您可以缓存它。还有OnVisualChildrenChanged --这只是一个想法,甚至100%都不能确定它是否能很好地完成,但是这需要额外的内存和字典。
这可能会变得非常复杂,不用说:-),但是对于“边项目”来说是很酷的。
另一方面,你也应该平放视觉树,它会提高你的速度。
发布于 2014-12-22 11:57:40
在为FindAncestor使用 Enumeration的 Property值时,还可以设置要查找使用 Property的祖先级别。从上一页链接:
使用值1表示与绑定目标元素最近的值。
发布于 2014-12-29 10:28:41
关于“寻找祖先”,没什么可说的。它工作简单,这就是为什么它的速度快。它的工作方式是这样的:元素的父类型总是被问到。如果类型与您需要的类型不匹配。父元素变成实际元素,并且进程再次被重复。这就是为什么“查找祖先”总是在视觉树上工作,但从不下降的原因:)
我认为RelativeSource绑定可能会出现一些性能问题,唯一可能的原因是当您在ListBox中定义了一个带有大量RelativeSource绑定的讨厌项模板时。ListBox倾向于虚拟化一些东西,这意味着它会跟踪数据项,但会重新创建它们的容器。总之,你开始滚动,你滚动得越快,那些视觉容器就会被重新创建得越频繁。最后,每次重新创建容器时,相对源绑定都会尝试查找给定的祖先类型。这是我现在能想到的唯一一种情况,在这种情况下,你最终会落后几毫秒。但这还不错..。
你遇到这样的问题了吗?请多告诉我们你的问题。
就像Sheridan一样,我会让这些错误成为现实:)然而,如果你那么恨它们,你可以和桥一起工作。
Bridge是您自己实现所需的东西。
看看这个链接: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}}"
试试看
https://stackoverflow.com/questions/27601961
复制相似问题