Как я могу улучшить производительность RelativeSource FindAncestor?
Является FindAncestor
ищет элемент во всем визуальном дереве Window?
Если да, то как я могу улучшить это??
Является binding data error
бросить, если мы получим доступ к свойству объекта, найдя элемент с помощью Find Ancestor, и такого элемента не существует?
Если да, то как я могу устранить такую ошибку.
В моем случае ошибка привязки к окну вывода. Чтобы решить эту ошибку, я попытался с настройкой FallbackValue
, но теперь он дает мне предупреждение вместо ошибки, которая является единственным отличием. Все остальное так же, как ошибка.
Может кто-нибудь сказать мне, как именно FindAncestor
работает??
3 ответа
Если вы хотите знать, как 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
, это может быть легко кэшировано. Возможно, "одноразовые кешированные относительные источники" будут новой концепцией.
Концепция может быть такой: напишите свою собственную привязку относительного источника, как вы сделали. Как только привязка будет выполнена в первый раз, используйте помощник по визуальному дереву, чтобы найти родителя определенного типа. Если это сделано, вы можете сохранить найденный родительский объект в свойстве прямого родительского атрибута следующим образом:
var dic = myElementThatUsesRelativeSourceBinding.Parent.
GetCurrentValue(MyCachedRelativeSourceParentsProperty)
as Dictionary<Type, UIElement>;
dic[foundType] = actualValue;
Позже вы будете использовать эту информацию кеша при поиске относительного источника позже. Вместо O(n), он примет O(1) для того же элемента / потомков родителя.
Если вы знаете, что родитель всегда существует, вы должны создать привязку в коде для каждого элемента, который пытается использовать FindAncestor
, Таким образом, вы избегаете обхода дерева.
Вы также можете создать гибридное решение, которое отслеживает изменения визуального дерева и поддерживает "кэш". Если DataGridRow
просит "найти мне относительный источник от типа DataGrid
", нет никакой причины, что вам нужно делать это все время: вы можете кешировать это. OnVisualChildrenChanged
- просто идея, даже не на 100% уверенная в том, что это можно сделать хорошо, но для этого потребуются дополнительная память и словарь.
Это может быть очень сложным, само собой разумеется:-), но было бы здорово для "побочного проекта".
На другой стороне; Вы также должны сгладить визуальное дерево, это даст вам скорость.
При использовании FindAncestor
значение RelativeSourceMode
Перечень для RelativeSource.Mode
Свойство, вы также можете установить уровень предка, чтобы искать с помощью RelativeSource.AncestorLevel
Собственность С последней связанной страницы:
Используйте [значение] 1, чтобы указать ближайший к целевому элементу привязки.
Существует не так много, чтобы рассказать о "Найти предка". Работает просто, поэтому быстро. Это работает так: тип родителя элемента всегда запрашивается. Если тип не совпадает с тем, который вам нужен. Родитель становится фактическим элементом, и процесс повторяется снова. Вот почему "Найти предка" всегда работает визуальное дерево вверх, но никогда не вниз:)
Единственная возможная причина, по которой, я думаю, вы можете почувствовать некоторые проблемы с производительностью при привязках RelativeSource, - это когда вы в ListBox
и у вас есть действительно неприятный шаблон элемента, определенный с кучей привязок RelativeSource внутри. ListBox
имеет тенденцию виртуализировать вещи, что означает, что они отслеживают элементы данных, но воссоздают их контейнеры. Подводя итог, вы начинаете прокручивать, и чем быстрее вы прокручиваете, тем чаще будут создаваться визуальные контейнеры. В конце концов, каждый раз, когда контейнер воссоздается, относительная исходная привязка будет пытаться искать данный тип предка. Это единственный случай, который я могу вспомнить прямо сейчас, когда вы отстанете на несколько миллисекунд. Но это не плохо..
Вы испытываете какую-то проблему, как это? Расскажите подробнее о вашей проблеме, пожалуйста
Как и Шеридан, я бы позволил этим ошибкам быть просто:) однако, если вы их так ненавидите, вы можете работать с мостами
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}}"
Попробуйте это