Как использовать RelativeSource
с привязками WPF и каковы различные варианты использования?
.net
wpf
xaml
data-binding
relativesource
Дэвид Шмитт
источник
источник
AncestorType
.FindAncestor
ранееAncestorType
, я получаю следующую ошибку: «RelativeSource не находится в режиме FindAncestor». (В VS2013, версия для сообщества){Binding Path=DataContext.SomeProperty, RelativeSource=...
. Это было несколько неожиданно для меня, как новичка, когда я пытался привязать к DataContext родителя в DataTemplate.Атрибутом по умолчанию
RelativeSource
являетсяMode
свойство. Полный набор допустимых значений приведен здесь ( из MSDN ):PreviousData Позволяет вам связать предыдущий элемент данных (не тот элемент управления, который содержит элемент данных) в списке отображаемых элементов данных.
TemplatedParent Указывает на элемент, к которому применяется шаблон (в котором существует элемент с привязкой к данным). Это похоже на установку TemplateBindingExtension и применимо только в том случае, если Binding находится внутри шаблона.
Self Относится к элементу, для которого вы устанавливаете привязку, и позволяет привязать одно свойство этого элемента к другому свойству того же элемента.
FindAncestor Относится к предку в родительской цепочке элемента с привязкой к данным. Вы можете использовать это для привязки к предку определенного типа или его подклассам. Этот режим вы используете, если хотите указать AncestorType и / или AncestorLevel.
источник
Вот более наглядное объяснение в контексте архитектуры MVVM:
источник
{Binding Message}
(немного проще ...)Path=DataContext.Message
чтобы получить привязку к работе. Это имеет смысл, учитывая, что вы можете делать относительные привязки к ширине / высоте / и т.д. контроля.Bechir Bejaoui раскрывает варианты использования RelativeSources в WPF в своей статье здесь :
источник
ListView
. У родителя есть еще 2ListView
уровня ниже. Это помогло мне предотвратить передачу данных в каждой последующей VM каждогоListView
«sDataTemplate
В WPF
RelativeSource
привязка выставляет триproperties
для установки:1. Режим: это
enum
может иметь четыре значения:2. AncestorType: когда режим,
FindAncestor
то определите, какой тип предка3. AncestorLevel: когда режим,
FindAncestor
то какой уровень предка (если есть два родителя одного типаvisual tree
)Вот ссылка на ссылку .
источник
Не забудьте TemplatedParent:
или
источник
Стоит отметить, что для тех, кто наткнулся на это представление о Silverlight:
Silverlight предлагает только сокращенное подмножество этих команд
источник
Я создал библиотеку, чтобы упростить синтаксис привязки WPF, в том числе упростить использование RelativeSource. Вот несколько примеров. Перед:
После:
Вот пример того, как привязка метода упрощается. Перед:
После:
Вы можете найти библиотеку здесь: http://www.simplygoodcode.com/2012/08/simpler-wpf-binding.html
Обратите внимание, что в примере «BEFORE», который я использую для привязки метода, код уже был оптимизирован, и
RelayCommand
последний проверенный мной код не является родной частью WPF. Без этого пример «ДО» был бы еще длиннее.источник
Некоторые полезные фрагменты:
Вот как это сделать в основном в коде:
Я в основном скопировал это из Binding Relative Source в коде Behind .
Кроме того, страница MSDN довольно хороша в том, что касается примеров: RelativeSource Class
источник
Я только что опубликовал другое решение для доступа к DataContext родительского элемента в Silverlight, которое работает для меня. Это использует
Binding ElementName
.источник
Я не читал каждый ответ, но я просто хочу добавить эту информацию в случае относительного связывания исходной команды кнопки.
Когда вы используете относительный источник с
Mode=FindAncestor
, привязка должна быть такой:Если вы не добавите DataContext в свой путь, во время выполнения он не сможет получить свойство.
источник
Это пример использования этого шаблона, который работал для меня на пустых сетках данных.
источник
Если элемент не является частью визуального дерева, то RelativeSource никогда не будет работать.
В этом случае вам нужно попробовать другую технику, впервые предложенную Томасом Левеском.
У него есть решение в его блоге в разделе [WPF] Как связывать данные, когда DataContext не наследуется . И это работает абсолютно блестяще!
В маловероятном случае, когда его блог не работает, приложение А содержит зеркальную копию его статьи .
Пожалуйста, не комментируйте здесь, пожалуйста, комментируйте непосредственно в своем блоге .
Приложение A: Зеркало блога
Свойство DataContext в WPF чрезвычайно удобно, поскольку оно автоматически наследуется всеми дочерними элементами элемента, которому вы его назначаете; поэтому вам не нужно устанавливать его заново для каждого элемента, который вы хотите связать. Однако в некоторых случаях DataContext недоступен: это происходит для элементов, которые не являются частью визуального или логического дерева. Тогда может быть очень сложно связать свойство с этими элементами ...
Давайте проиллюстрируем это на простом примере: мы хотим отобразить список продуктов в DataGrid. В сетке мы хотим иметь возможность отображать или скрывать столбец Price, основываясь на значении свойства ShowPrice, предоставляемого ViewModel. Очевидный подход заключается в привязке видимости столбца к свойству ShowPrice:
К сожалению, изменение значения ShowPrice не имеет никакого эффекта, и столбец всегда виден ... почему? Если мы посмотрим на окно вывода в Visual Studio, мы заметим следующую строку:
Мы можем попытаться настроить привязку, чтобы получить желаемый результат, например, установив RelativeSource на сам DataGrid:
Или мы можем добавить CheckBox, привязанный к ShowPrice, и попытаться связать видимость столбца со свойством IsChecked, указав имя элемента:
Но ни один из этих обходных путей, похоже, не работает, мы всегда получаем один и тот же результат ...
На данный момент, кажется, что единственным жизнеспособным подходом было бы изменить видимость столбцов в коде, который мы обычно предпочитаем избегать при использовании шаблона MVVM ... Но я не собираюсь сдаваться так скоро, по крайней мере, не в то время как есть другие варианты, чтобы рассмотреть 😉
Решение нашей проблемы на самом деле довольно простое и использует преимущества класса Freezable. Основная цель этого класса - определить объекты, которые имеют изменяемое и доступное только для чтения состояние, но в нашем случае интересной особенностью является то, что объекты Freezable могут наследовать DataContext, даже если они не находятся в визуальном или логическом дереве. Я не знаю точный механизм, который позволяет это поведение, но мы собираемся использовать его, чтобы заставить нашу работу связывания ...
Идея состоит в том, чтобы создать класс (я назвал его BindingProxy по причинам, которые должны стать очевидными очень скоро), который наследует Freezable и объявляет свойство зависимости Data:
Затем мы можем объявить экземпляр этого класса в ресурсах DataGrid и связать свойство Data с текущим DataContext:
Последний шаг - указать этот объект BindingProxy (легко доступный со StaticResource) в качестве источника для привязки:
Обратите внимание, что к пути привязки был добавлен префикс «Данные», поскольку теперь этот путь относится к объекту BindingProxy.
Привязка теперь работает правильно, и столбец правильно отображается или скрывается на основе свойства ShowPrice.
источник