If you want to know how FindAncestor
works internally, you should read the internal code. http://referencesource.microsoft.com/#PresentationFramework/Framework/MS/Internal/Data/ObjectRef.cs,6a2d9d6630cad93d
You should try and not use FindAncestor
that much. It can be slow, plus the children shouldn't rely on the knownledge of "there exist somewhere a parent who has what I need".
That said, FindAncestor
itself can be also your friend at times.
It depends on your case, but for example, it's common to have a DataGridRow
which uses FindAncestor
in order to find information about DataGrid
or some other parent element.
The problem with that is: IT'S SUPER SLOW. Say you have 1000 DataGridRows, and each row uses FindAncestor
, plus each row has 7 columns, which itself has to traverse through ~200 elements in logical tree. It does not have to be slow, DataGridRow
has always the same parent DataGrid
, it can be easily cached. Perhaps "One-time cached relativeSources" would be the new concept.
The concept can be like this: write your own relativeSource binding as you've done. Once the binding is done first time, use visual tree helper to find a parent of specific type. If that is done, you can store the found parent IN the direct parent attachewd property, as so:
var dic = myElementThatUsesRelativeSourceBinding.Parent.
GetCurrentValue(MyCachedRelativeSourceParentsProperty)
as Dictionary<Type, UIElement>;
dic[foundType] = actualValue;
Later, you use this cache information in the search of relative source later. Instead of taking O(n), it will take O(1) for the same element / children of parent.
If you know that the parent always exists, you should create the binding in code-behind, for each element that tries to use FindAncestor
. This way you avoid traversing the tree.
You could also create a hybrid solution which tracks the changes of visual tree, and mainains "cache". If a DataGridRow
asks for "find me relative source off type DataGrid
", there is no reason that you need to do it all the time: you could cache it. There's OnVisualChildrenChanged
- just an idea, not even 100% sure if it can be done nicely, but this will require extra memory, and dictionary.
This can get very complex, needless to say :-), but would be cool for "side project".
On another side; you should also flatten visual tree, it would gain you a speed.