2014-12-22 6 views
6

Is FindAncestor ищет элемент во всем визуальном дереве окна?Как повысить производительность RelativeSource FindAncestor?

Если да, то как я могу улучшить его?

Действительно ли binding data error выброшено, если мы получим доступ к объекту объекта путем поиска элемента с Find Ancestor & нет такого элемента?

Если да, то как я могу разрешить такую ​​ошибку.

В моем случае ошибка привязки бросает окно вывода. Чтобы решить эту ошибку, я попытался установить FallbackValue, но теперь это дает мне предупреждение вместо ошибки, которая является единственной разницей. Все остальное такое же, как и ошибка.

Может ли кто-нибудь сказать мне, как именно FindAncestor работает ??

+0

Он ищет первый (или второй, третий ... если вы установили элемент AncestorLevel), который соответствует типу в родителях текущего элемента. Таким образом, он не будет искать весь VisualTree, он будет искать родителей, пока не найдет то, что вы хотите – nkoniishvt

+0

Но если такой элемент не найден, то? ...Я мало знаю о «Уровне предков» .. но это полезно, только если в их родительской иерархии существует более одного элемента одного типа. –

+0

@AmolNavannavar Действительно, значением по умолчанию является 1. Не найдено ни одного элемента, у вас, вероятно, будет ошибка привязки (это не приведет к сбою приложения) – nkoniishvt

ответ

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, его можно легко кэшировать. Возможно, «одноразовое кэширование относительных источников» станет новой концепцией.

Концепция может быть такой: напишите свой собственный bindingSource, как вы это сделали. Как только привязка выполняется в первый раз, используйте помощник визуального дерева, чтобы найти родителя определенного типа. Если это будет сделано, вы можете сохранить найденную родителя в прямой собственности родителя attachewd, как это:

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

dic[foundType] = actualValue; 

Позже вы используете эту информацию кэша в поисках относительного источника позже. Вместо того, чтобы принимать O (n), он примет O (1) для одного и того же элемента/дочерних элементов родителя.

Если вы знаете, что родительский объект всегда существует, вы должны создать привязку в коде для каждого элемента, который пытается использовать FindAncestor. Таким образом, вы избегаете пересечения дерева.

Вы также можете создать гибридное решение, которое отслеживает изменения визуального дерева и основной «кеш». Если DataGridRow просит «найти меня с исходным кодом типа DataGrid», нет причин, по которым вам нужно делать это все время: вы можете кэшировать его. Есть OnVisualChildrenChanged - просто идея, даже не уверенная на 100%, если это можно сделать красиво, но для этого потребуется дополнительная память и словарь.

Это может быть очень сложным, само собой разумеется :-), но было бы здорово для «побочного проекта».

С другой стороны; вы также должны сгладить визуальное дерево, это даст вам скорость.

+0

Спасибо @Chris .. Информация, которую вы предоставили, очень ценна. Но я также хочу знать о новой концепции «Одноразовые кешированные источники» .... –

+0

@AmolBavannavar: Я тоже что-то написал об этом. –

+0

Спасибо @ Крис Eelmaa .. Это помогло мне Lottt ... –

1

При использовании значения RelativeSourceMode EnumerationFindAncestor для RelativeSource.Mode Property, вы можете также установить уровень предка искать с помощью RelativeSource.AncestorLevel Property. Из последней связанной страницы:

Используйте [значение] 1, чтобы указать, является ближайшим к связывающему элементу мишени.

+0

Да, я знаю это, но что, если их нет, такой элемент существует в его родительской иерархии ??? .. @Sheridan Я хочу улучшить это? .. Я не делаю внутреннего работа FindAncestor ... –

+0

Если такой элемент не существует, вы получите ошибку «Binding» ... почему вы используете «RelativeSource», если этот исходный элемент может не существовать в первую очередь? * Это * ваша проблема, а не функция FindAncestor. В любом случае, все визуальное дерево можно пройти за долю секунды, поэтому я действительно не могу понять ваше отчаяние, пытаясь уменьшить это время. Используя класс ['VisualTreeHelper'] (http://msdn.microsoft.com/en-us/library/system.windows.media.visualtreehelper (v = vs.110) .aspx), вы можете легко написать свой собственный код чтобы увидеть, как быстро дерево может пройти. – Sheridan

+0

Да, я использовал «Конвертер» для того же ... Проверьте «эту ссылку» моего потока http://stackoverflow.com/q/27182878/4112271 .. Но проблема в том, что я не использую 'конвертер', если 'FindAncestor' делает то же самое. –

0

Невозможно рассказать о "Find Ancestor". Он работает просто, поэтому его быстро. Он работает следующим образом: всегда запрашивается тип родителя элемента. Если тип не соответствует тому, который вам нужен. Родитель становится фактическим элементом, и процесс повторяется снова. Именно поэтому «Найти Предок» всегда работает визуальное дерево вверх, но никогда не вниз :)

Единственная возможная причина, где я думаю, что вы могли бы чувствовать некоторые проблемы с производительностью RelativeSource привязок это когда вы в ListBox и у вас есть действительно противный шаблон элемента, определенный с помощью связки RelativeSource внутри. ListBox имеет тенденцию виртуализировать материал, что означает, что он отслеживает элементы данных, но воссоздает их контейнеры. Подводя итог, вы начинаете прокрутку, и чем быстрее вы прокручиваете чаще, тем визуальные контейнеры собираются воссоздать. В конце каждый раз, когда контейнер воссоздается, относительная привязка источника будет пытаться искать данный тип предка. Это единственный случай, о котором я могу думать прямо сейчас, когда вы закончите отставание в несколько миллисекунд. Но это неплохо.

Вы испытываете какую-то проблему вроде этого? Расскажите нам о проблеме, пожалуйста,

Как Шеридан я позволил бы эти erros просто :) Но если вы ненавидите их так много, вы могли бы работать с мостами

A 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}}"

Попробуйте

+0

Я уже знаю эту идею для решения этих проблем .. но мне нужен «подробный ответ» для обоих вопросов. Потому что я не знаю, как работает «Find Ancestor»? –

+0

Невозможно рассказать о «Find Ancestor». Он работает просто, поэтому его быстро. Он работает следующим образом: всегда запрашивается тип родителя элемента. Если тип не соответствует тому, который вам нужен. Родитель становится фактическим элементом, и процесс повторяется снова. Вот почему «Find Ancestor» всегда работает с визуальным деревом, но никогда не спускается :) Для использования «Find Ancestor» требуется функциональное дерево. –

+0

Hey @dev hedgehog yes Я реализовал то же самое с помощью 'Converter', в котором я прошел элемент до родителя! = Null Или тип найден, начиная с' Relative Source Self' ... http: //stackoverflow.com/questions/27182878/how -to-create-converter-to-work-like-findancestor-for-check-istypefound? lq = 1 –

 Смежные вопросы

  • Нет связанных вопросов^_^