How do I use WPF bindings with RelativeSource?

.NetWpfXamlData BindingRelativesource

.Net Problem Overview


How do I use RelativeSource with WPF bindings and what are the different use-cases?

.Net Solutions


Solution 1 - .Net

If you want to bind to another property on the object:

{Binding Path=PathToProperty, RelativeSource={RelativeSource Self}}

If you want to get a property on an ancestor:

{Binding Path=PathToProperty,
    RelativeSource={RelativeSource AncestorType={x:Type typeOfAncestor}}}

If you want to get a property on the templated parent (so you can do 2 way bindings in a ControlTemplate)

{Binding Path=PathToProperty, RelativeSource={RelativeSource TemplatedParent}}

or, shorter (this only works for OneWay bindings):

{TemplateBinding Path=PathToProperty}

Solution 2 - .Net

Binding RelativeSource={
    RelativeSource Mode=FindAncestor, AncestorType={x:Type ItemType}
}
...

The default attribute of RelativeSource is the Mode property. A complete set of valid values is given here (from MSDN):

  • PreviousData Allows you to bind the previous data item (not that control that contains the data item) in the list of data items being displayed.

  • TemplatedParent Refers to the element to which the template (in which the data-bound element exists) is applied. This is similar to setting a TemplateBindingExtension and is only applicable if the Binding is within a template.

  • Self Refers to the element on which you are setting the binding and allows you to bind one property of that element to another property on the same element.

  • FindAncestor Refers to the ancestor in the parent chain of the data-bound element. You can use this to bind to an ancestor of a specific type or its subclasses. This is the mode you use if you want to specify AncestorType and/or AncestorLevel.

Solution 3 - .Net

Here's a more visual explanation in the context of a MVVM architecture:

enter image description here

Solution 4 - .Net

Bechir Bejaoui exposes the use cases of the RelativeSources in WPF in his article here:

> The RelativeSource is a markup extension that is used in particular > binding cases when we try to bind a property of a given object to > another property of the object itself, when we try to bind a property > of a object to another one of its relative parents, when binding a > dependency property value to a piece of XAML in case of custom control > development and finally in case of using a differential of a series of > a bound data. All of those situations are expressed as relative source > modes. I will expose all of those cases one by one. > > 1. Mode Self: > > Imagine this case, a rectangle that we want that its height is always > equal to its width, a square let's say. We can do this using the > element name > > Height="100" Stroke="Black" > Canvas.Top="100" Canvas.Left="100" > Width="{Binding ElementName=rectangle, > Path=Height}"/> > > But in this above case we are obliged to indicate the name of the > binding object, namely the rectangle. We can reach the same purpose > differently using the RelativeSource > > Stroke="Black" > Width="{Binding RelativeSource={RelativeSource Self}, > Path=Height}"/> > > For that case we are not obliged to mention the name of the binding > object and the Width will be always equal to the Height whenever the > height is changed. > > If you want to parameter the Width to be the half of the height then > you can do this by adding a converter to the Binding markup extension. > Let's imagine another case now: > > > > The above case is used to tie a given property of a given element to > one of its direct parent ones as this element holds a property that is > called Parent. This leads us to another relative source mode which is > the FindAncestor one. > > 2. Mode FindAncestor > > In this case, a property of a given element will be tied to one of its > parents, Of Corse. The main difference with the above case is the fact > that, it's up to you to determine the ancestor type and the ancestor > rank in the hierarchy to tie the property. By the way try to play with > this piece of XAML > > > Width="{Binding RelativeSource={RelativeSource Self}, > Path=Parent.ActualWidth}" > Height="{Binding RelativeSource={RelativeSource Self}, > Path=Parent.ActualHeight}"> > > Width="{Binding RelativeSource={RelativeSource Self}, > Path=Parent.ActualWidth}" > Height="{Binding RelativeSource={RelativeSource Self}, > Path=Parent.ActualHeight}"> > > Margin="5" Text="Display the name of the ancestor"/> > Margin="50" > Text="{Binding RelativeSource={RelativeSource
> FindAncestor, > AncestorType={x:Type Border}, > AncestorLevel=2},Path=Name}" > Width="200"/> >
>
>
>
>
> > The above situation is of two TextBlock elements those are embedded > within a series of borders and canvas elements those represent their > hierarchical parents. The second TextBlock will display the name of > the given parent at the relative source level. > > So try to change AncestorLevel=2 to AncestorLevel=1 and see what > happens. Then try to change the type of the ancestor from > AncestorType=Border to AncestorType=Canvas and see what's happens. > > The displayed text will change according to the Ancestor type and > level. Then what's happen if the ancestor level is not suitable to the > ancestor type? This is a good question, I know that you're about to > ask it. The response is no exceptions will be thrown and nothings will > be displayed at the TextBlock level. > > 3. TemplatedParent > > This mode enables tie a given ControlTemplate property to a property > of the control that the ControlTemplate is applied to. To well > understand the issue here is an example bellow > > > > > > > > Fill="{Binding > RelativeSource={RelativeSource TemplatedParent}, > Path=Background}"> > > > Content="{Binding RelativeSource={RelativeSource
> TemplatedParent},Path=Content}"/> >
>
>
> > > > > If I want to apply the properties of a given control to its control > template then I can use the TemplatedParent mode. There is also a > similar one to this markup extension which is the TemplateBinding > which is a kind of short hand of the first one, but the > TemplateBinding is evaluated at compile time at the contrast of the > TemplatedParent which is evaluated just after the first run time. As > you can remark in the bellow figure, the background and the content > are applied from within the button to the control template.

Solution 5 - .Net

In WPF RelativeSource binding exposes three properties to set:

1. Mode: This is an enum that could have four values:

> a. PreviousData(value=0): It assigns the previous value of the property to > the bound one

> b. TemplatedParent(value=1): This is used when defining the templates of > any control and want to bind to a value/Property of the control.

> For example, define ControlTemplate:

  <ControlTemplate>
        <CheckBox IsChecked="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Value, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
 </ControlTemplate>

> c. Self(value=2): When we want to bind from a self or a property of self.

> For example: Send checked state of checkbox as CommandParameter while setting the Command on CheckBox

<CheckBox ...... CommandParameter="{Binding RelativeSource={RelativeSource Self},Path=IsChecked}" />

> d. FindAncestor(value=3): When want to bind from a parent control >in Visual Tree.

> For example: Bind a checkbox in records if a grid,if header checkbox is checked

<CheckBox IsChecked="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type iDP:XamDataGrid}}, Path=DataContext.IsHeaderChecked, Mode=TwoWay}" />

2. AncestorType: when mode is FindAncestor then define what type of ancestor

RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type iDP:XamDataGrid}}

3. AncestorLevel: when mode is FindAncestor then what level of ancestor (if there are two same type of parent in visual tree)

RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type iDP:XamDataGrid, AncestorLevel=1}}

> Above are all use-cases for RelativeSource binding.

Here is a reference link.

Solution 6 - .Net

Don't forget TemplatedParent:

<Binding RelativeSource="{RelativeSource TemplatedParent}"/>

or

{Binding RelativeSource={RelativeSource TemplatedParent}}

Solution 7 - .Net

It's worthy of note that for those stumbling across this thinking of Silverlight:

Silverlight offers a reduced subset only, of these commands

Solution 8 - .Net

I created a library to simplify the binding syntax of WPF including making it easier to use RelativeSource. Here are some examples. Before:

{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}

After:

{BindTo PathToProperty}
{BindTo Ancestor.typeOfAncestor.PathToProperty}
{BindTo Template.PathToProperty}
{BindTo #MyTextBox.Text}

Here is an example of how method binding is simplified. Before:

// 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}

After:

// C# code
private void SaveObject() {
 // do something
}

// XAML
{BindTo SaveObject()}

You can find the library here: http://www.simplygoodcode.com/2012/08/simpler-wpf-binding.html

Note in the 'BEFORE' example that I use for method binding that code was already optimized by using RelayCommand which last I checked is not a native part of WPF. Without that the 'BEFORE' example would have been even longer.

Solution 9 - .Net

Some useful bits and pieces:

Here's how to do it mostly in code:

Binding b = new Binding();
b.RelativeSource = new RelativeSource(RelativeSourceMode.FindAncestor, this.GetType(), 1);
b.Path = new PropertyPath("MyElementThatNeedsBinding");
MyLabel.SetBinding(ContentProperty, b);

I largely copied this from Binding Relative Source in code Behind.

Also, the MSDN page is pretty good as far as examples go: RelativeSource Class

Solution 10 - .Net

I just posted another solution for accessing the DataContext of a parent element in Silverlight that works for me. It uses Binding ElementName.

Solution 11 - .Net

This is an example of the use of this pattern that worked for me on empty datagrids.

<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>

Solution 12 - .Net

I didn't read every answer, but I just want to add this information in case of relative source command binding of a button.

When you use a relative source with Mode=FindAncestor, the binding must be like:

Command="{Binding Path=DataContext.CommandProperty, RelativeSource={...}}"

If you don't add DataContext in your path, at execution time it can't retrieve the property.

Solution 13 - .Net

If an element is not part of the visual tree, then RelativeSource will never work.

In this case, you need to try a different technique, pioneered by Thomas Levesque.

He has the solution on his blog under [WPF] How to bind to data when the DataContext is not inherited. And it works absolutely brilliantly!

In the unlikely event that his blog is down, Appendix A contains a mirror copy of his article.

Please do not comment here, please comment directly on his blog post.

Appendix A: Mirror of blog post

The DataContext property in WPF is extremely handy, because it is automatically inherited by all children of the element where you assign it; therefore you don’t need to set it again on each element you want to bind. However, in some cases the DataContext is not accessible: it happens for elements that are not part of the visual or logical tree. It can be very difficult then to bind a property on those elements…

Let’s illustrate with a simple example: we want to display a list of products in a DataGrid. In the grid, we want to be able to show or hide the Price column, based on the value of a ShowPrice property exposed by the ViewModel. The obvious approach is to bind the Visibility of the column to the ShowPrice property:

<DataGridTextColumn Header="Price" Binding="{Binding Price}" IsReadOnly="False"
                Visibility="{Binding ShowPrice,
                Converter={StaticResource visibilityConverter}}"/>

Unfortunately, changing the value of ShowPrice has no effect, and the column is always visible… why? If we look at the Output window in Visual Studio, we notice the following line:

> System.Windows.Data Error: 2 : Cannot find governing FrameworkElement or FrameworkContentElement for target element. BindingExpression:Path=ShowPrice; DataItem=null; target element is ‘DataGridTextColumn’ (HashCode=32685253); target property is ‘Visibility’ (type ‘Visibility’) > > The message is rather cryptic, but the meaning is actually quite simple: WPF doesn’t know which FrameworkElement to use to get the DataContext, because the column doesn’t belong to the visual or logical tree of the DataGrid.

We can try to tweak the binding to get the desired result, for instance by setting the RelativeSource to the DataGrid itself:

<DataGridTextColumn Header="Price" Binding="{Binding Price}" IsReadOnly="False"
                Visibility="{Binding DataContext.ShowPrice,
                Converter={StaticResource visibilityConverter},
                RelativeSource={RelativeSource FindAncestor, AncestorType=DataGrid}}"/>

Or we can add a CheckBox bound to ShowPrice, and try to bind the column visibility to the IsChecked property by specifying the element name:

<DataGridTextColumn Header="Price" Binding="{Binding Price}" IsReadOnly="False"
                Visibility="{Binding IsChecked,
                Converter={StaticResource visibilityConverter},
                ElementName=chkShowPrice}"/>

But none of these workarounds seems to work, we always get the same result…

At this point, it seems that the only viable approach would be to change the column visibility in code-behind, which we usually prefer to avoid when using the MVVM pattern… But I’m not going to give up so soon, at least not while there are other options to consider 

The solution to our problem is actually quite simple, and takes advantage of the Freezable class. The primary purpose of this class is to define objects that have a modifiable and a read-only state, but the interesting feature in our case is that Freezable objects can inherit the DataContext even when they’re not in the visual or logical tree. I don’t know the exact mechanism that enables this behavior, but we’re going to take advantage of it to make our binding work…

The idea is to create a class (I called it BindingProxy for reasons that should become obvious very soon) that inherits Freezable and declares a Data dependency property:

public class BindingProxy : Freezable
{
    #region Overrides of Freezable
 
    protected override Freezable CreateInstanceCore()
    {
        return new BindingProxy();
    }
 
    #endregion
 
    public object Data
    {
        get { return (object)GetValue(DataProperty); }
        set { SetValue(DataProperty, value); }
    }
 
    // Using a DependencyProperty as the backing store for Data.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty DataProperty =
        DependencyProperty.Register("Data", typeof(object), typeof(BindingProxy), new UIPropertyMetadata(null));
}

We can then declare an instance of this class in the resources of the DataGrid, and bind the Data property to the current DataContext:

<DataGrid.Resources>
    <local:BindingProxy x:Key="proxy" Data="{Binding}" />
</DataGrid.Resources>

The last step is to specify this BindingProxy object (easily accessible with StaticResource) as the Source for the binding:

<DataGridTextColumn Header="Price" Binding="{Binding Price}" IsReadOnly="False"
                Visibility="{Binding Data.ShowPrice,
                Converter={StaticResource visibilityConverter},
                Source={StaticResource proxy}}"/>

Note that the binding path has been prefixed with “Data”, since the path is now relative to the BindingProxy object.

The binding now works correctly, and the column is properly shown or hidden based on the ShowPrice property.

Solution 14 - .Net

I am constantly updating my research on Binding.

 Original Here

DataContext

DataContext is the DependencyProperty included in the FrameworkElement.
PresentationFramework.dll

namespace System.Windows
{
    public class FrameworkElement : UIElement
    {
        public static readonly DependencyProperty DataContextProperty;
        public object DataContext { get; set; }
    }
}

And, all UI Controls in WPF inherit the FrameworkElement class.
> At this point in learning Binding or DataContext, you don't have to study FrameworkElement in greater depth.
> However, this is to briefly mention the fact that the closest object that can encompass all UI Controls is the FrameworkElement.

DataContext is always the reference point for Binding.

Binding can directly recall values for the DataContext type format starting with the nearest DataContext.

<TextBlock Text="{Binding}" DataContext="James"/>

The value bound to Text="{Binding}" is passed directly from the nearest DataContext, TextBlock.
Therefore, the Binding result value of Text is 'James'.

  • Type integer
    When assigning a value to DataContext directly from Xaml, resource definitions are required first for value types such as Integer and Boolean. Because all strings are recognized as String.

    1. Using System mscrolib in Xaml

    > Simple type variable type is not supported by standard.
    > You can define it with any word, but mostly use sys words.

    xmlns:sys="clr-namespace:System;assembly=mscorlib"
    
    2. Create YEAR resource key in xaml

    > Declare the value of the type you want to create in the form of a StaticResource.

    <Window.Resources>
        <sys:Int32 x:Key="YEAR">2020</sys:Int32>
    </Window.Resources>
    ...
    <TextBlock Text="{Binding}" DataContext="{StaticResource YEAR"/>
    
  • All type of value
    There are very few cases where Value Type is binding directly into DataContext.
    Because we're going to bind an object.

    <Window.Resources>
        <sys:Boolean x:Key="IsEnabled">true</sys:Boolean>
        <sys:double x:Key="Price">7.77</sys:double>
    </Window.Resources>
    ...
    <StackPanel>
        <TextBlock Text="{Binding}" DataContext="{StaticResource IsEnabled}"/>
        <TextBlock Text="{Binding}" DataContext="{StaticResource Price}"/>
    </StackPanel>
    
  • Another type
    Not only String but also various types are possible. Because DataContext is an object type.

Finally...

In using Binding at WPF, most developers are not fully aware of the existence, function and importance of DataContext.
It may mean that Binding is being connected by luck.
> Especially if you are responsible for or participating in a large WPF project, you should understand the DataContext hierarchy of the application more clearly. In addition, the introduction of WPF's various popular MVVM Framework systems without this DataContext concept will create even greater limitations in implementing functions freely.


Binding

DataContext Binding

string property

<TextBox Text="{Binding Keywords}"/>


Element Binding
<CheckBox x:Name="usingEmail"/>
<TextBlock Text="{Binding ElementName=usingEmail, Path=IsChecked}"/>


MultiBinding
<TextBlock Margin="5,2" Text="This disappears as the control gets focus...">
  <TextBlock.Visibility>
      <MultiBinding Converter="{StaticResource TextInputToVisibilityConverter}">
          <Binding ElementName="txtUserEntry2" Path="Text.IsEmpty" />
          <Binding ElementName="txtUserEntry2" Path="IsFocused" />
      </MultiBinding>
  </TextBlock.Visibility>
</TextBlock>


Self Property Binding
<TextBlock x:Name="txt" Text="{Binding ElementName=txt, Path=Tag}"/>

If you have to bind your own property, you can use Self Property Binding, instead of using Element Binding.
You no longer have to declare x:Name to bind your own property.

<TextBlock Text="{Binding RelativeSource={RelativeSource Self}, Path=Tag}"/>


Find Ancestor Binding

Imports based on the parent control closest to it.

<TextBlock Text="{Binding RelativeSource={RelativeSource AncestorType=Window}, Path=Title}"/>

In addition to the properties of the controls found, the properties within the DataContext object can be used if it exists.

<TextBlock Text="{Binding RelativeSource={RelativeSource AncestorType=Window}, Path=DataContext.Email}"/>


TemplatedParent Binding

This is a method that can be used within ControlTemplate, and you can import the control that is the owner of the ControlTemplate.

<Style TargetType="Button">
  <Setter Property="Template">
      <Setter.Value>
          <ControlTemplate TargetType="Button">
              <TextBlock Text="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Content}"/>
          </ControlTemplate>
      </Setter.Value>
  </Setter>

You can access to all Property and DataContext.

<TextBlock Text="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Content}"/>


Static Property Binding

You can access binding property value directly.

1. Declare static property.
namespace Exam
{
  public class ExamClass
  {
      public static string ExamText { get; set; }
  }
} 
2. Using static class in XAML.
<Window ... xmlns:exam="clr-namespace:Exam">
3. Binding property.
<TextBlock Text="{Binding exam:ExamClass.ExamText}"/>

Or, you can set Resource key like using Converter.

<Window.Resource>
  <cvt:VisibilityToBooleanConverter x:Key="VisibilityToBooleanConverter"/>
  <exam:ExamClass x:Key="ExamClass">
</Window.Resource>
...

<TextBlock Text="{Binding Source={StaticResource ExamClass}, Path=ExamText}"/>

> I have never used the Static Property under normal circumstances. This is because data that deviates from its own DataContext can disrupt the flow of whole WPF applications and impair readability significantly. However, this method is actively used in the development stage to implement fast testing and functions, as well as in the DataContext (or ViewModel).


Bad Binding & Good Binding

✔️ If the property you want to bind is included in Datacontext,
      you don't have to use ElementBinding.

      Using ElementBinding through connected control is not a functional problem,
      but it breaks the fundamental pattern of Binding.

 Bad Binding
<TextBox x:Name="text" Text="{Binding UserName}"/>
...
<TextBlock Text="{Binding ElementName=text, Path=Text}"/>
 Good Binding
<TextBox Text="{Binding UserName}"/>
...
<TextBlock Text="{Binding UserName}"/>


✔️ Do not use ElementBinding when using property belonging to higher layers control.
 Bad Binding
<Window x:Name="win">
  <TextBlock Text="{Binding ElementName=win, Path=DataContext.UserName}"/>
  ...
 Good Binding
<Window>
  <TextBlock Text="{Binding RelativeSource={RelativeSource AncestorType=Window}, Path=DataContext.UserName}"/>
  ...
 Great!
<Window>
  <TextBlock DataContext="{Binding RelativeSource={RelativeSource AncestorType=Window}, Path=DataContext}" 
             Text="{Binding UserName}"/>
  ...


✔️ Do not use ElementBinding when using your own properties.
 Bad Binding
<TextBlock x:Name="txt" Text="{Binding ElementName=txt, Path=Foreground}"/>
 Good Binding
<TextBlock Text="{Binding RelativeSource={RelativeSource Self}, Path=Foreground}"/>

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionDavid SchmittView Question on Stackoverflow
Solution 1 - .NetAbe HeidebrechtView Answer on Stackoverflow
Solution 2 - .NetDrew NoakesView Answer on Stackoverflow
Solution 3 - .NetJeffrey KnightView Answer on Stackoverflow
Solution 4 - .NetCornel MarianView Answer on Stackoverflow
Solution 5 - .NetKylo RenView Answer on Stackoverflow
Solution 6 - .NetBob KingView Answer on Stackoverflow
Solution 7 - .NetMatthew BlackView Answer on Stackoverflow
Solution 8 - .NetLuis PerezView Answer on Stackoverflow
Solution 9 - .NetNathan CooperView Answer on Stackoverflow
Solution 10 - .NetJuveView Answer on Stackoverflow
Solution 11 - .NetEddView Answer on Stackoverflow
Solution 12 - .NetKevin VDFView Answer on Stackoverflow
Solution 13 - .NetContangoView Answer on Stackoverflow
Solution 14 - .Netjames.leeView Answer on Stackoverflow