17

Are there any data binding frameworks (BCL or otherwise) that allow binding between any two CLR properties that implement INotifyPropertyChanged and INotifyCollectionChanged? It seems to be it should be possible to do something like this:

var binding = new Binding();
binding.Source = someSourceObject;
binding.SourcePath = "Customer.Name";
binding.Target = someTargetObject;
binding.TargetPath = "Client.Name";
BindingManager.Bind(binding);

Where someSourceObject and someTargetObject are just POCOs that implement INotifyPropertyChanged. However, I am unaware of any BCL support for this, and am not sure if there are existing frameworks that permit this.

UPDATE: Given that there is no existing library available, I have taken it upon myself to write my own. It is available here.

Thanks

Kent Boogaart
  • 175,602
  • 35
  • 392
  • 393

6 Answers6

11

I wrote Truss to fill the void.

snipsnipsnip
  • 2,268
  • 2
  • 33
  • 34
Kent Boogaart
  • 175,602
  • 35
  • 392
  • 393
8

I'm not aware of any library that does this - but you could write your own fairly easily.

Here's a basis I knocked up in a few minutes that establishes two way data binding between two simple properties:

public static class Binder
{

    public static void Bind(
        INotifyPropertyChanged source,
        string sourcePropertyName,
        INotifyPropertyChanged target,
        string targetPropertyName)
    {
        var sourceProperty
            = source.GetType().GetProperty(sourcePropertyName);
        var targetProperty
            = target.GetType().GetProperty(targetPropertyName);

        source.PropertyChanged +=
            (s, a) =>
            {
                var sourceValue = sourceProperty.GetValue(source, null);
                var targetValue = targetProperty.GetValue(target, null);
                if (!Object.Equals(sourceValue, targetValue))
                {
                    targetProperty.SetValue(target, sourceValue, null);
                }
            };

        target.PropertyChanged +=
            (s, a) =>
            {
                var sourceValue = sourceProperty.GetValue(source, null);
                var targetValue = targetProperty.GetValue(target, null);
                if (!Object.Equals(sourceValue, targetValue))
                {
                    sourceProperty.SetValue(source, targetValue, null);
                }
            };
    }
}

Of course, this code lacks a few niceties. Things to add include

  • Checking that source and target are assigned
  • Checking that the properties identified by sourcePropertyName and targetPropertyName exist
  • Checking for type compatibility between the two properties

Also, Reflection is relatively slow (though benchmark it before discarding it, it's not that slow), so you might want to use compiled expressions instead.

Lastly, given that specifying properties by string is error prone, you could use Linq expressions and extension methods instead. Then instead of writing

Binder.Bind( source, "Name", target, "Name")

you could write

source.Bind( Name => target.Name);
Bevan
  • 43,618
  • 10
  • 81
  • 133
  • I was actually asking because I was considering writing my own. Didn't want to reinvent the wheel and all...thanks. – Kent Boogaart Mar 10 '09 at 09:21
  • Update: I have linked to my library in the question. – Kent Boogaart Apr 23 '09 at 07:25
  • I needed a simple barebone databinding class for my current project-in-a-hurry, and the one above nearly fits what I need. I just replaced the property names used with Reflection by two Action delegates in which I get/set from the POCO and apply transformations and formatting. I will definitely give a good try to Truss in a next project, because it sounds really interresting to me. – Larry Nov 17 '10 at 13:53
  • Hello, a little late (it's 2012), but don't you think the event source.PropertyChanged would be raised for any property change in the source and we are interested only in one property? Is it good performance wise? – thewpfguy Jun 13 '12 at 07:23
  • @thewpfguy, when the PropertyChanged event fires, there are three cases to handle: Our property; Not our property; and every property (Empty string). In theory, as you identified, we should write code that identifies which case is happening and react accordingly. In practice, we're talking about saving only microseconds of CPU time. When we're talking about duration on a human perceptible scale, those microseconds just don't matter. If you're throwing thousands of PropertyChanged notifications every second, your code has bigger problems. – Bevan Jun 13 '12 at 20:22
  • @Bevan Thanks for the comment. Yes I do agree a microsecond here or there does not matter. But the problem we have in our app, is that the whole app is bound to single business object and this object has got many properties - around 100 and of course all of them have RaisePropertyChanged. Now we need to bind one of its property to one of my own in a view model. So I was little concerned that using the solution you provided would fire up for all the properties, or is there other way to bind two POCO properties. – thewpfguy Jun 14 '12 at 04:36
  • @Bevan, to add why I am not using the property available in DataContext and using my own in View Model (and that's why I want to bind the two) - is because the class of the object used in DataContext is not in our hands. We cannot update it. – thewpfguy Jun 14 '12 at 04:39
  • In that case, wrap the body of the delegate given above in a test, checking to see if the property being notified is the required one. – Bevan Jun 14 '12 at 09:15
1

AutoMapper can copy values between two instances, but you have to write your own code to make this happen automatically.

snipsnipsnip
  • 2,268
  • 2
  • 33
  • 34
Thomas Eyde
  • 3,820
  • 2
  • 25
  • 32
1

Maybe Bindable LINQ or continuous linq can help here. If you're trying to add model properties that are actually "derived properties" of your actual, updating data, to make it easier for you UI to bind to, these two frameworks should help.

snipsnipsnip
  • 2,268
  • 2
  • 33
  • 34
Kurt Schelfthout
  • 8,880
  • 1
  • 30
  • 48
0

I wrote an small Bind project with full support for binding between neasted properties async binding actions. The sintax can't be simpler:

//Two way binding between neasted properties:
Bind.TwoWay(()=> client.Area.Data.Name == this.AreaName);

//On change action execute:
Bind
    .OnChange(()=> client.Personal.Name)
    .Do(x => clientName = x);
Rafael
  • 2,642
  • 2
  • 24
  • 30
-2

If you defined your properties as DependencyProperty's you could do it. Both WF and WPF have an implementation of it (first link is for WPF. For WF it is this one) so you need to decide which to use - but both should suffice for your needs.

Robert MacLean
  • 38,975
  • 25
  • 98
  • 152
  • 2
    DependencyProperty implies inheriting from DependencyObject, which is not a POCO. – Kent Boogaart Mar 11 '09 at 14:16
  • Eh? Not sure what your logic is for voting this up Will. Neither suggestion will suffice for my needs as neither suggestion involves POCOs. Another post has already shown you can do it with POCOs - I'm just asking for a framework that does the hard lifting. – Kent Boogaart Mar 11 '09 at 14:52