Binding to an Attached Property

Yesterday, I have some ideas in my mind on how to give out ValidationRule errors after the values passes the converter, and I was trying to see if I can use Attached Properties for that.

When trying to do this, one of the things I'd like to do was set a control's text to the Attached Property's value and that's when I realized that I don't know the syntax to do that.

A quick Google search yields; someone asked the same question and the answer suggested using parentheses.  The following example where the TextBox will display the row index the textbox is residing show how this works:

<Grid>

    <Grid.RowDefinitions>

        <RowDefinition Height="Auto"/>

        <RowDefinition Height="Auto"/>

        <RowDefinition Height="Auto"/>

        <RowDefinition Height="Auto"/>

    </Grid.RowDefinitions>

    <Grid.ColumnDefinitions>

       

    </Grid.ColumnDefinitions>

    <TextBox Text="{Binding (Grid.Row),RelativeSource={RelativeSource Self}}"

             Height="23" Grid.Column="0" Grid.Row="0" VerticalAlignment="Top" />

    <TextBox Text="{Binding (Grid.Row),RelativeSource={RelativeSource Self}}"

             Height="23" Grid.Column="0" Grid.Row="1" VerticalAlignment="Top" />

    <TextBox Text="{Binding (Grid.Row),RelativeSource={RelativeSource Self}}"

             Height="23" Grid.Column="0" Grid.Row="2" VerticalAlignment="Top" />

    <TextBox Text="{Binding (Grid.Row),RelativeSource={RelativeSource Self}}"

             Height="23" Grid.Column="0" Grid.Row="3" VerticalAlignment="Top"

             Name=”textBox4” />

</Grid>

You can also see that I didn't use Path=(Grid.Row), by default the first parameter is assigned to the Path property of the Binding class.

What about if we want to do it in code; it's very similar: 

Binding b = new Binding("(Grid.Row)");

b.Source = textBox4;

BindingOperations.SetBinding(textBox4, TextBox.TextProperty, b);

The binding path is the same; (Grid.Row) and the other important tidbit is that the source is the textbox itself.  This is logical since when assigning a value to an Attached Property, you're assigning that value for a given DependencyObject.  In this case, we want the text to be set to the Grid.Row attached property for that particular textbox too.

Verifying that it works, now I continue on with my class that implements the Attached Property.  However, since I need to refer to my class using XML namespace, how would the Path look?  The path has to use the namespace too, as the sample below shows:

<Grid xmlns:local="clr-namespace:BindingToAttachedProperty">

    <Grid.RowDefinitions>

        <RowDefinition Height="Auto"/>

        <RowDefinition Height="Auto"/>

        <RowDefinition Height="Auto"/>

        <RowDefinition Height="Auto"/>

    </Grid.RowDefinitions>

    <Grid.ColumnDefinitions>

       

    </Grid.ColumnDefinitions>

    <TextBox Text="{Binding Path=(local:LocalClass.SomeValue),RelativeSource={RelativeSource Self}}"

             local:LocalClass.SomeValue="1"

             Height="23" Grid.Column="0" Grid.Row="0" Vertical.Alignment="Top" />

    <TextBox Text="{Binding (local:LocalClass.SomeValue),RelativeSource={RelativeSource Self}}"

             local:LocalClass.SomeValue="2"

             Name="textBox2"

             Height="23" Grid.Column="0" Grid.Row="1" VerticalAlignment="Top" />

</Grid>

I found a weird condition in WPF; you can see that for the first TextBox, the Binding has the Path=, while the second one doesn't.  The sample above works, the first textbox will display 1, and the second textbox will display 2.  However, if you take out that Path= string, the example will not work; the BindingExpression specifies PathError.  I believe this is because without the first Path=, WPF doesn't know what is (local:LocalClass.SomeValue).  By specifying Path=, WPF compiles it correctly, and the subsequent encounter of (local:LocalClass.SomeValue) in textBox2 results in a correct interpretation.

OK, the XAML works; how to do it in code?  I tried all kinds of combination for the path, and could not get anything to work - it took me about 2 hours trying around and finally I got a solution.

Binding b = new Binding;

b.Path = new PropertyPath(LocalClass.SomeValueProperty);

b.Source = textBox2;

BindingOperations.SetBinding(textBox2, TextBox.TextProperty, b);

Most of the time, people will just create a new Binding instance, passing the string path in its constructor.  I could not get this to work; all types of string values that I tried results in PathError.  Finally, I took a good look at the Path property in the Binding class and found that one of the PropertyPath constructor accepts an object parameter that can be a DependencyProperty.

This would be my first 'New Thing I Learned' to document!(/Providers/BlogEntryEditor/FCKeditor/editor/images/smiley/msn/regular_smile.gif).  I'm sure I will look at this information again in the future, and I hope other people can benefit from this.

This article is part of the GWB Archives. Original Author: Muljadi Budiman

New on Geeks with Blogs

  • We Won The One Award I Actually Care About

    Full Scale made the Inc. 5000 for the fifth year straight, the 12th listing across my three companies. Here is why the one award you cannot buy is worth stopping for.

  • Your Customers Build the Features Now

    I let a tool I liked sit dead for a year rather than build the features I wanted. An MCP server meant I never had to, and your customers can do the same to your product.

  • Get the Size of a Directory in Linux the Easy Way

    du -sh for the quick answer, ncdu for the cleanup, df for the disk itself: every command for checking directory size in Linux, plus why du and df never agree.

  • Vim Search and Replace: The Ultimate Guide

    One :%s command replaces every match in a file before a find dialog would even open. The Vim substitute patterns worth the muscle memory: flags, ranges, capture groups, and multi-file edits.