Binding to Self/'this' in XAML

C#WpfXaml

C# Problem Overview


Simple WPF/XAML question. In XAML, how do I reference the Self/this object in a given context? In a very basic app with a main window, one control, and a coded C# property of the window, I want to bind a property of the control to the hand coded property of the window.

In code, this is very easy - in the Window's constructor, I added this:

Binding bind = new Binding();
bind.Source = this;
bind.Path = new PropertyPath("ButtonWidth");
button1.SetBinding(WidthProperty, bind);

Obviously, I have a property called ButtonWidth, and a control called button1. I can't figure out how to do this in XAML. Various attempts like the following example have not worked:

<Button x:Name="button1" Width="{Binding Source=Self Path=ButtonWidth}"/>

<Button x:Name="button1" Width="{Binding RelativeSource={RelativeSource Self} Path=ButtonWidth}"/> 

etc

Thanks

C# Solutions


Solution 1 - C#

First use a comma between the RelativeSource and Path in your Binding:

<Button x:Name="button1" Width="{Binding RelativeSource={RelativeSource Self}, 
                                Path=ButtonWidth}"/> 

Secondly, the RelativeSource binds to the Button. Button has no property called ButtonWidth. I am guessing you need to Bind to your parent control.

So try this RelativeSource binding:

<Button x:Name="button1" Width="{Binding RelativeSource=
    {RelativeSource FindAncestor, AncestorType={x:Type YourNamespace:YourParentControl}}, 
    Path=ButtonWidth}"/> 

Solution 2 - C#

I think what you are looking for is this:

<Window x:Class = "blah blah all the regular stuff"

DataContext="{Binding RelativeSource={RelativeSource Self}}"

>

Solution 3 - C#

One way I get around having to deal with RelativeSource and the like is to name the root XAML element:

<Window x:Class="TestApp2.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="350" Width="525"
    x:Name="_this"
    >
    <Grid>
        <Button x:Name="button" Width="{Binding ElementName=_this,Path=ButtonWidth}" />
    </Grid>
</Window>

If you want to set the DataContext you could also do this:

<Window x:Class="TestApp2.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="350" Width="525"
    x:Name="_this"
    >
    <Grid DataContext="{Binding ElementName=_this}">        
        <Button x:Name="button" Width="{Binding Path=ButtonWidth}" />
    </Grid>
</Window>

I find this to be a good trick to not have to remember all the complexities of the RelativeSource binding.

Solution 4 - C#

The problem with naming the XAML root element is that, if you get into the habit of using the same name (i.e, "_this", "Root", etc.) for all the roots in your project, then late-binding in nested templates may access the wrong element. This is because, when {Binding} ElementName=... is used in a Template, names are resolved at runtime by walking up the NameScope tree until the first match is found.

Clint's solution avoids naming the root element, but it sets the root element into its own DataContext, which might not be an option if the DataContext is needed for, say, data. It also seems a bit heavy-handed to introduce another binding on an element just for the purpose of providing access to it. Later, if access is no longer needed, that {Binding} will become clutter: responsibility for access properly belongs with the target and binding.

Accordingly, here is a simple markup extension to access the XAML root element without naming it:

using System.Xaml;
using System.Windows.Markup;

public sealed class XamlRootExtension : MarkupExtension
{
    public override Object ProvideValue(IServiceProvider sp)
    {
        var rop = sp.GetService(typeof(IRootObjectProvider)) as IRootObjectProvider;
        return rop == null ? null : rop.RootObject;
    }
};

XAML:

<Window x:Class="MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:global="clr-namespace:">

    <TextBlock Text="{Binding Source={global:XamlRoot},Mode=OneTime}" />

</Window>

note: for clarity, I didn't define the MarkupExtension in a namespace; using an empty clr-namespace alias as shown here d̲o̲e̲s̲ actually work in for accessing the global:: namespace (although the VS2013 designer seems to complains about it).

Result:

enter image description here
A window whose content is bound to itself.


n.b.

Solution 5 - C#

Unfortunately, naming the root element with "ElementName=.." seems to be the only way with UWP as {RelativeSource Self} is not supported there.

Oddly enough, this still works when the name is overrid in layout, e.g.

<UserControl x:Class="Path.MyClass" x:Name="internalName">
   <Border Background={Binding Path=Background, ElementName=internalName}" ...

then

<Page>
   <local:MyClass x:Name=externalName />

</Page>

BTW, Windows 10 fixed an error (present at Windows 8.1), when same internal name is used for different elements in same layout.

Still, I would prefer to use {RelativeSource Self}, since it appears more logical and safer to me.

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
QuestionTom DaviesView Question on Stackoverflow
Solution 1 - C#ArcturusView Answer on Stackoverflow
Solution 2 - C#Clint StLaurentView Answer on Stackoverflow
Solution 3 - C#DamianView Answer on Stackoverflow
Solution 4 - C#Glenn SlaydenView Answer on Stackoverflow
Solution 5 - C#cyanideView Answer on Stackoverflow