Если вы хотите знать, как работает 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
, его можно легко кэшировать. Возможно, «одноразовое кэширование относительных источников» станет новой концепцией.
Концепция может быть такой: напишите свой собственный bindingSource, как вы это сделали. Как только привязка выполняется в первый раз, используйте помощник визуального дерева, чтобы найти родителя определенного типа. Если это будет сделано, вы можете сохранить найденную родителя в прямой собственности родителя attachewd, как это:
var dic = myElementThatUsesRelativeSourceBinding.Parent.
GetCurrentValue(MyCachedRelativeSourceParentsProperty)
as Dictionary<Type, UIElement>;
dic[foundType] = actualValue;
Позже вы используете эту информацию кэша в поисках относительного источника позже. Вместо того, чтобы принимать O (n), он примет O (1) для одного и того же элемента/дочерних элементов родителя.
Если вы знаете, что родительский объект всегда существует, вы должны создать привязку в коде для каждого элемента, который пытается использовать FindAncestor
. Таким образом, вы избегаете пересечения дерева.
Вы также можете создать гибридное решение, которое отслеживает изменения визуального дерева и основной «кеш». Если DataGridRow
просит «найти меня с исходным кодом типа DataGrid
», нет причин, по которым вам нужно делать это все время: вы можете кэшировать его. Есть OnVisualChildrenChanged
- просто идея, даже не уверенная на 100%, если это можно сделать красиво, но для этого потребуется дополнительная память и словарь.
Это может быть очень сложным, само собой разумеется :-), но было бы здорово для «побочного проекта».
С другой стороны; вы также должны сгладить визуальное дерево, это даст вам скорость.
Он ищет первый (или второй, третий ... если вы установили элемент AncestorLevel), который соответствует типу в родителях текущего элемента. Таким образом, он не будет искать весь VisualTree, он будет искать родителей, пока не найдет то, что вы хотите – nkoniishvt
Но если такой элемент не найден, то? ...Я мало знаю о «Уровне предков» .. но это полезно, только если в их родительской иерархии существует более одного элемента одного типа. –
@AmolNavannavar Действительно, значением по умолчанию является 1. Не найдено ни одного элемента, у вас, вероятно, будет ошибка привязки (это не приведет к сбою приложения) – nkoniishvt