14 ответов:
если вы хотите привязать к другому свойству объекта:
{Binding Path=PathToProperty, RelativeSource={RelativeSource Self}}если вы хотите получить свойство на предка:
{Binding Path=PathToProperty, RelativeSource={RelativeSource AncestorType={x:Type typeOfAncestor}}}если вы хотите получить свойство на шаблонном родителе (так что вы можете сделать 2 способа привязки в ControlTemplate)
{Binding Path=PathToProperty, RelativeSource={RelativeSource TemplatedParent}}или, короче (это работает только для привязки oneway):
{TemplateBinding Path=PathToProperty}
Binding RelativeSource={ RelativeSource Mode=FindAncestor, AncestorType={x:Type ItemType} } ...атрибут по умолчанию
RelativeSourceэтоModeсобственность. Здесь приведен полный набор допустимых значений (от MSDN):
PreviousData позволяет привязать предыдущий элемент данных (не тот элемент управления, который содержит элемент данных) в списке отображаемых элементов данных.
TemplatedParent относится к элементу, к которому относится шаблон (в котором привязан элемент с данными существует) применяется. Это похоже на установку TemplateBindingExtension и применимо только в том случае, если привязка находится внутри шаблона.
Self относится к элементу, на котором вы устанавливаете привязку и позволяет привязать одно свойство этого элемента к другому свойству на том же элементе.
FindAncestor относится к предку в родительской цепочке элемента с привязкой к данным. Вы можете использовать это для привязка к предку определенного типа или его подклассов. Этот режим используется, если вы хотите указать AncestorType и/или AncestorLevel.
представьте себе этот случай, прямоугольник, который мы хотим, чтобы его высота всегда была равна его ширине, скажем, квадрат. Мы можем сделать это, используя имя элемента
<Rectangle Fill="Red" Name="rectangle" Height="100" Stroke="Black" Canvas.Top="100" Canvas.Left="100" Width="{Binding ElementName=rectangle, Path=Height}"/>но в данном случае мы обязаны указать имя объекта привязки, а именно прямоугольник. Мы можем достичь той же цели по-разному, используя RelativeSource
<Rectangle Fill="Red" Height="100" Stroke="Black" Width="{Binding RelativeSource={RelativeSource Self}, Path=Height}"/>В этом случае мы не обязаны указывать имя объекта привязки и ширина всегда будет равна Высота всякий раз, когда высота изменяется.
Если вы хотите, чтобы параметр ширина была половиной высоты, то вы можете сделать это, добавив конвертер в расширение разметки привязки. Давайте теперь представим себе другой случай:
<TextBlock Width="{Binding RelativeSource={RelativeSource Self}, Path=Parent.ActualWidth}"/>приведенный выше случай используется для привязки данного свойства данного элемента к одному из его прямых родительских элементов, поскольку этот элемент содержит свойство, которое называется родительским. Это приводит нас к другому относительному исходному режиму, который является FindAncestor one.
Bechir Bejaoui предоставляет варианты использования RelativeSources в WPF в его статью здесь:
RelativeSource-это расширение разметки, которое используется в частности случаи привязки, когда мы пытаемся привязать свойство данного объекта к другое свойство самого объекта, когда мы пытаемся привязать свойство объекта к другому из его относительных родителей, при привязке a значение свойства зависимостей для части XAML в случае пользовательского элемента управления развитие и, наконец, в случае использования дифференциала ряда связанные данные. Все эти ситуации выражаются как относительный источник режим. Я разоблачу все эти случаи один за другим.
- Self Режим:
представьте себе этот случай, прямоугольник, который мы хотим, чтобы его высота всегда равный его ширине, скажем, квадрат. Мы можем сделать это с помощью имя элемента
<Rectangle Fill="Red" Name="rectangle" Height="100" Stroke="Black" Canvas.Top="100" Canvas.Left="100" Width="{Binding ElementName=rectangle, Path=Height}"/>но в этом случае мы обязаны указать название привязка объекта, а именно прямоугольника. Мы можем достичь той же цели по-разному используя RelativeSource
<Rectangle Fill="Red" Height="100" Stroke="Black" Width="{Binding RelativeSource={RelativeSource Self}, Path=Height}"/>в этом случае мы не обязаны указывать название привязки объект и ширина всегда равна высоте всякий раз, когда высота меняется.
если вы хотите, чтобы параметр ширина была половина высоты, то это можно сделать, добавив конвертер в расширение разметки привязки. Давайте теперь представьте себе другой случай:
<TextBlock Width="{Binding RelativeSource={RelativeSource Self}, Path=Parent.ActualWidth}"/>приведенный выше случай используется для привязки данного свойства данного элемента к один из его прямых родителей, так как этот элемент имеет свойство, называется родительской. Это приводит нас к другому относительному исходному режиму, который является находка первая.
- Режим FindAncestor
в этом случае свойство данного элемента будет привязано к одному из его родители, конечно. Основное отличие с выше случай является фактом это до вас, чтобы определить тип предка и предка ранг в иерархии, чтобы связать свойство. Кстати попробуй поиграть с этот кусок XAML
<Canvas Name="Parent0"> <Border Name="Parent1" Width="{Binding RelativeSource={RelativeSource Self}, Path=Parent.ActualWidth}" Height="{Binding RelativeSource={RelativeSource Self}, Path=Parent.ActualHeight}"> <Canvas Name="Parent2"> <Border Name="Parent3" Width="{Binding RelativeSource={RelativeSource Self}, Path=Parent.ActualWidth}" Height="{Binding RelativeSource={RelativeSource Self}, Path=Parent.ActualHeight}"> <Canvas Name="Parent4"> <TextBlock FontSize="16" Margin="5" Text="Display the name of the ancestor"/> <TextBlock FontSize="16" Margin="50" Text="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Border}, AncestorLevel=2},Path=Name}" Width="200"/> </Canvas> </Border> </Canvas> </Border> </Canvas>приведенная выше ситуация состоит из двух элементов TextBlock, которые встроены в пределах ряда границ и элементов холста они представляют их иерархические родители. Второго элемента TextBlock будет отображать название данный родитель на относительном уровне источника.
поэтому попробуйте изменить AncestorLevel=2 на AncestorLevel=1 и посмотреть, что происходит. Затем попробуйте изменить тип предка от AncestorType=граница к AncestorType=холст и посмотреть, что происходит.
отображаемый текст будет меняться в зависимости от типа предка и уровень. Тогда что произойдет, если уровень предка не подходит для тип предка? Это хороший вопрос, я знаю, что вы собираетесь спросить его. В ответ не будет выдано никаких исключений и ничего не будет отображается на уровне текстового блока.
- TemplatedParent
этот режим позволяет привязать данное свойство ControlTemplate к свойству элемента управления, к которому применяется ControlTemplate. Хлынуть понять проблему вот пример ниже
<Window.Resources> <ControlTemplate x:Key="template"> <Canvas> <Canvas.RenderTransform> <RotateTransform Angle="20"/> </Canvas.RenderTransform> <Ellipse Height="100" Width="150" Fill="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Background}"> </Ellipse> <ContentPresenter Margin="35" Content="{Binding RelativeSource={RelativeSource TemplatedParent},Path=Content}"/> </Canvas> </ControlTemplate> </Window.Resources> <Canvas Name="Parent0"> <Button Margin="50" Template="{StaticResource template}" Height="0" Canvas.Left="0" Canvas.Top="0" Width="0"> <TextBlock FontSize="22">Click me</TextBlock> </Button> </Canvas>если я хочу применить свойства данного элемента управления к его элементу управления затем я могу использовать режим TemplatedParent. Существует также подобный одному это расширение разметки, которое является TemplateBinding что является своего рода короткой рукой первого, но TemplateBinding вычисляется во время компиляции, в отличие от TemplatedParent, который оценивается сразу после первого времени выполнения. Как вы можете отметить на рисунке ниже, фон и содержание применяются изнутри кнопки к шаблону управления.
Не забывайте TemplatedParent:
<Binding RelativeSource="{RelativeSource TemplatedParent}"/>или
{Binding RelativeSource={RelativeSource TemplatedParent}}
в WPF
RelativeSourceпривязка предоставляет триpropertiesв наборе:1. Режим: это
enumчто может иметь четыре значения:a. PreviousData (
value=0): он присваивает Предыдущее значениеpropertyto связанныйb. TemplatedParent (
value=1): это используется при определенииtemplatesof любой управление и хотите привязать к значению / свойствуcontrol.например, определение
ControlTemplate:<ControlTemplate> <CheckBox IsChecked="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Value, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" /> </ControlTemplate>c. Self (
value=2): когда мы хотим связать сselfилиpropertyсамостоятельно.например: отправить проверенное состояние
checkboxкакCommandParameterпри установкеCommandonCheckBox<CheckBox ...... CommandParameter="{Binding RelativeSource={RelativeSource Self},Path=IsChecked}" />d. FindAncestor (
value=3): когда хотите привязать от родителяcontrolвVisual Tree.например: связать
checkboxнаrecordsесли agrid,еслиheadercheckboxпроверен<CheckBox IsChecked="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type iDP:XamDataGrid}}, Path=DataContext.IsHeaderChecked, Mode=TwoWay}" />2. AncestorType: когда режим
FindAncestorзатем определите, какой тип предкаRelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type iDP:XamDataGrid}}3. AncestorLevel: когда режим
FindAncestorтогда какой уровень предка (если есть два одинаковых типа родителя вvisual tree)RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type iDP:XamDataGrid, AncestorLevel=1}}выше все варианты использования для
RelativeSource binding.
стоит отметить, что для тех, кто натыкается на это мышление Silverlight:
Silverlight предлагает только уменьшенное подмножество этих команд
Я создал библиотеку для упрощения синтаксиса привязки WPF, включая упрощение использования RelativeSource. Вот несколько примеров. Раньше:
{Binding Path=PathToProperty, RelativeSource={RelativeSource Self}} {Binding Path=PathToProperty, RelativeSource={RelativeSource AncestorType={x:Type typeOfAncestor}}} {Binding Path=PathToProperty, RelativeSource={RelativeSource TemplatedParent}} {Binding Path=Text, ElementName=MyTextBox}после:
{BindTo PathToProperty} {BindTo Ancestor.typeOfAncestor.PathToProperty} {BindTo Template.PathToProperty} {BindTo #MyTextBox.Text}вот пример того, как упрощается привязка метода. Раньше:
// C# code private ICommand _saveCommand; public ICommand SaveCommand { get { if (_saveCommand == null) { _saveCommand = new RelayCommand(x => this.SaveObject()); } return _saveCommand; } } private void SaveObject() { // do something } // XAML {Binding Path=SaveCommand}после:
// C# code private void SaveObject() { // do something } // XAML {BindTo SaveObject()}вы можете найти библиотеку здесь:http://www.simplygoodcode.com/2012/08/simpler-wpf-binding.html
обратите внимание в Примере' BEFORE', что Я использую для привязки метода, что код уже был оптимизирован с помощью
RelayCommandкоторый последний раз я проверил не является родной частью WPF. Без этого пример " До " был бы еще длиннее.
некоторые полезные биты и куски:
вот как это сделать в основном в коде:
Binding b = new Binding(); b.RelativeSource = new RelativeSource(RelativeSourceMode.FindAncestor, this.GetType(), 1); b.Path = new PropertyPath("MyElementThatNeedsBinding"); MyLabel.SetBinding(ContentProperty, b);Я в значительной степени скопировал это из привязка относительного источника в коде за.
кроме того, страница MSDN довольно хороша, поскольку примеры идут:RelativeSource Class
Я только что написал другое решение для доступа к DataContext родительского элемента в Silverlight, который работает для меня. Он использует
Binding ElementName.
Это пример использования этого шаблона, который работал для меня на пустых сетках данных.
<Style.Triggers> <DataTrigger Binding="{Binding Items.Count, RelativeSource={RelativeSource Self}}" Value="0"> <Setter Property="Background"> <Setter.Value> <VisualBrush Stretch="None"> <VisualBrush.Visual> <TextBlock Text="We did't find any matching records for your search..." FontSize="16" FontWeight="SemiBold" Foreground="LightCoral"/> </VisualBrush.Visual> </VisualBrush> </Setter.Value> </Setter> </DataTrigger> </Style.Triggers>
Я не читал каждый ответ, но я просто хочу добавить эту информацию в случае относительной привязки команды источника кнопки.
при использовании относительного источник
Mode=FindAncestor, привязка должна быть как:Command="{Binding Path=DataContext.CommandProperty, RelativeSource={...}}"Если вы не добавляете DataContext в свой путь, во время выполнения он не может получить свойство.
если элемент не является частью визуального дерева, то RelativeSource никогда не будет работать.
в этом случае вам нужно попробовать другую технику, впервые предложенную Томасом Левеском.
у него есть решение в своем блоге под [WPF] как привязать к данным, когда DataContext не наследуется. И это работает абсолютно блестяще!
в маловероятном случае, если его блог не работает, приложение A содержит зеркальную копию его статья.
пожалуйста, не комментируйте здесь, пожалуйста комментарий непосредственно на его блоге.
приложение A: зеркало блога
свойство DataContext в WPF чрезвычайно удобно, потому что оно автоматически наследуется всеми дочерними элементами элемента, которому вы его назначаете; поэтому вам не нужно устанавливать его снова для каждого элемента, который вы хотите привязать. Однако в некоторых случаях DataContext недоступен: это происходит для элементы, которые не являются частью зрительного или логического дерева. Это может быть очень трудно, то привязать свойство на этих элементах...
давайте проиллюстрируем простым примером: мы хотим отобразить список продуктов в DataGrid. В сетке мы хотим иметь возможность отображать или скрывать столбец цены на основе значения свойства ShowPrice, предоставляемого ViewModel. Очевидный подход заключается в привязке видимости столбца к ShowPrice свойство:
<DataGridTextColumn Header="Price" Binding="{Binding Price}" IsReadOnly="False" Visibility="{Binding ShowPrice, Converter={StaticResource visibilityConverter}}"/>к сожалению, изменение значения ShowPrice не имеет никакого эффекта, и столбец всегда виден... почему? Если мы посмотрим на окно вывода в Visual Studio, мы заметим следующую строку:

Comments