Friday, November 21, 2008

How to set bindings on CLR Properties using DataResource

It can be pretty annoying that bindings are only allowed on dependency properties of elements that are part of an element tree. For example, in all of these scenarios binding isn't allowed:
  • on an InputBinding's CommandParameter (not a dependency property)
  • on an object in an element's Resources if that object doesn't derive from Freezable (not part of an element tree)
  • on an element set to a FrameworkElement’s Tag property (not part of an element tree)
  • on a ValidationRule (not a dependency object)


This post introduces a new technique allowing you to add bindings to CLR properties and is a perfectly good workaround for all the scenarios above. it's good because it:
  • helps you use binding in many more scenarios :)
  • is very easy to use: just drop one source file (DataResource.cs) into your app and use it like this:
    
    <Window.Resources>
        
        <my:DataResource x:Key="actualWidth" BindingTarget="{Binding ActualWidth}"/>
    </Window.Resources>
    
    <my:MyControl>
        <my:MyControl.MyClrProperty>
            <my:DataResourceBinding DataResource="{StaticResource actualWidth}"/>
        </my:MyControl.MyClrProperty>
    </my:MyControl>
    
It works by using:
  • Mike Hillberg's technique of using Freezable to gain access to the DataContext of the host element
  • a custom markup extension to retrieve the object that the DataResource is bound to and returns this as the host of the markup extension
DataResource.cs
Download sample app with source code



15 comments:

Tyson said...

Thanks for this great litte trick, it works wonders in sooo many places.

However, one problem I'm still yet to get around is using it to bind to the Command property of Mouse/Key Bindings. It works fine, but if the binding resolves to null (which it usually does to start with before the DataContext has been initialized properly) then the InputBinding complains about setting a null command. Very frustrating. Any ideas?

Cheers.

Dan Lamping said...

Hi Tyson,

You could explicitly add support for this case in DataResource.cs like this:

Null Command Support

I can't think anything more elegant than this though.

Hope this helps
Dan

-dk said...

In DataResourceBindingExtension you are using a private Convert method that seems unnecessary. Is there a particular scenario I am missing that could require this cast. Both calls to Convert should be changed to this...

object value = dataResource.BindingTarget;

Dan Lamping said...

If you download the code in this post then you will see why it is required.

Is there a problem with it in another scenario?

Thanks for you feedback!
Dan

-dk said...

I am using DataResource.cs to bind KeyBindings to Commands on a ViewModel. I noticed it was simply throwing exceptions and ignoring them.

The way I understand this code the Convert method is completely unnecessary :-/ What is the purpose of casting when the result is always assigned to type object?

So basically the code was working fine except for the fact that it was throwing and swallowing exceptions in all my scenarios.

-dk

Dan Lamping said...

Hi there,

The Convert method is used to convert the object using the IConvertible interface.

This allows you, for example, to set a dependency property of type double using a string. The conversion is handled for you.

This is to make it work in the same way as a normal Binding.

However it is bad practice to just catch the exception in the way that I have...I should check that the conversion is required first.

Thanks
Dan

-dk said...

aha! now I see. I am always binding to the expected type so it was never necessary. Makes sense now.

Thanks,
-dk

Karl Schlag said...

Hi,

I'm trying to use your solution with a DataTemplate in a ListBox, but that doesn't seem to work.

<DataTemplate DataType="{x:Type my:Person}">
<DataTemplate.Resources>
<my:DataResource x:Key="myid"
BindingTarget="{Binding
ActualWidth}"/>
</DataTemplate.Resources>

<TextBlock Text="{Binding Path=ID}">
<TextBlock.InputBindings>
<MouseBinding
Command="ApplicationCommands.Open"
MouseAction="LeftDoubleClick">
<MouseBinding.CommandParameter>
<my:DataResourceBinding
DataResource="{StaticResource myid}"/>
</MouseBinding.CommandParameter>
</MouseBinding>
</TextBlock.InputBindings>
</TextBlock>
</DataTemplate>

When I display the parameter value in a messagebox, it shows "System.Object".

If I move the <my:DataResource ... /> to the <Window.Resources> block, everything works fine. But that doesn't solve my problem because I'm trying to bind the "ID" property of the ListBox' data object (a simple class with only one property) as it in the TextBlock Text property (Text="{Binding Path=ID}").

Is there any solution?

Thanks in advance!

JAuinger said...

THANK YOU!!!!!!! It´s amazing what this little trick can do for you.

Great work!

Best regards
Jochen

Duncan said...

Cheers Dan!

You see even after you've left i2 we're still nicking your code :-)

Duncan.

Anonymous said...

Great minds think alike.

I have been annoyed with this for a while, and then decided to fix it once and for all.

Take a look at my article: http://www.codeproject.com/KB/WPF/BindingHub.aspx

You can attach multiple Bindings to DependencyProperty, you can attach Bindings to non-DependencyProperties, you can have conditional Bindings, switch on and off, trigger updates, et cetera.

Check it out if you like it.

Michael Agroskin

jahanggir alam said...




In George Gannon Property Training you will get two days commercial to residential master
class source which is going to give you the strength to protect you from any types of awkward
or risky situation. Here you will have detail support from your mentor with consultancy and
pure gather of the knowledge with advice.


UK Property Training
UK Property Advice
Commercial Property Mentoring
Mentoring in Property
Property Development Mentoring
Property Mentoring UK

md mamun rana said...


It is not a matter of one day or one month, to learn about this area you will need time and
the more you will learn about the properties the more you are going to lead. You will obviously
have a portfolio and you have to make it more attractive and rich. The training will make you educated
about the maintenance issues as well. You will learn that how you have to handle any property related issue.
Handing if tenants are not so easy, you are going to learn it from there as well.

Progressive Property Mentoring
Property Mentoring
Property Training
Property Education
London Property Mentoring
UK Property Mentoring
UK Property Education

Md Masud Rana said...


It is becoming a very competitive to do any business in UK, especially if it is related with
the property. This is a very beneficial criteria and that’s why people are interested to work
with property management. UK Property Mentoring is needed for that reason.

Progressive Property Mentoring
Property Mentoring
Property Training
Property Education
London Property Mentoring
UK Property Mentoring
UK Property Education

Salma Kona Gugly said...


George established his ways after a lot of struggle and now he became one successful person
with extreme level of knowledge in properties. Making money is a tough work, in fact very hard work.
But unfortunately people think that they can make money without any type of training. But that is never
going to work. If you are investing money in your business then you should take proper training. Those
training are going to make you eligible to fight with any critical situation.

Progressive Property Mentoring
Property Mentoring
Property Training
Property Education
London Property Mentoring
UK Property Mentoring
UK Property Education