Easy INPC

38 views
Skip to first unread message

Bill Kempf

unread,
Aug 25, 2011, 11:06:31 AM8/25/11
to wpf-di...@googlegroups.com
Check this code out.
 
public class Employee : INotifyPropertyChanged
{
    public Employee()
    {
        this.RegisterPropertyChangedHandler(() => this.PropertyChanged);
    }
 
    public string FirstName
    {
       get { return this.GetBackingValue(() => this.FirstName); }
       set { this.SetBackingValue(() => this.FirstName, value); }
    }
 
    public string LastName
    {
        get { return this.GetBackingValue(() => this.LastName); }
        set { this.SetBackingValue(() => this.LastName, value); }
    }
 
    public event PropertyChangedEventHandler PropertyChanged;
}
 
Intrigued? http://digitaltapestry.net/blog/easy-modeling (BTW, pardon the blog design... it's currently not that great and I'm working on it.)
 
I'd really like to know what people think of this.

--
 Quidquid latine dictum sit, altum sonatur.
- Whatever is said in Latin sounds profound.

War is peace. Freedom is slavery.  Bugs are features.

Sacha Barber

unread,
Aug 25, 2011, 11:14:31 AM8/25/11
to wpf-di...@googlegroups.com
I like that, sort of mixing DP goodness, with Expressions, very nice indeed. I only saw ConditionalWeakTable a while back on Glenn Blocks blog, good usage.
--
Sacha Barber
sacha....@gmail.com

Mark Smith

unread,
Aug 25, 2011, 11:16:33 AM8/25/11
to wpf-di...@googlegroups.com
Nice trick Bill.  What's the performance characteristics for high-use properties?  I certainly like the minimal code - it reads nicely and is pretty intuitive at the high level (maybe not so much in the implementation).  ConditionalWeakTable is awesome.

mark


Bill Kempf

unread,
Aug 25, 2011, 12:09:47 PM8/25/11
to wpf-di...@googlegroups.com
I've not finished profiling yet, but there's definite overhead here. Just constructing an Expression is surprisingly expensive, and it's not something that gets cached in any way. Then walking the Expression to obtain the PropertyInfo adds even more overhead. All of that before even getting to the TWO or even THREE lookups in dictionary type collections (I'm considering the ConditionalWeakTable to be included here). In practice, especially within a ViewModel, you're not likely to have problems with the performance here in most scenarios. That's not to say the added overhead won't be significant in some scenarios, just that I suspect they'll be the exception, not the rule. Like I point out in the blog post, though, one benefit here is that when you do discover performance problems it's trivial to modify the implementation to get the best possible peformance while not changing the public interface at all.
 
I'm still playing with this concept, but I plan to add another feature as well: being able to declare dependent properties that will automatically raise PropertyChanged. Something along the lines of this:
 
public Employee()
{
   this.RegisterPropertyChangedHandler(() => this.PropertyChanged);
   this.DeclareDependencyFor(() => this.FullName).On(() => this.FirstName).And(() => this.LastName);
}
 
public string FullName
{
   get { return this.FirstName + " " + this.LastName; }

Mark Smith

unread,
Aug 25, 2011, 12:33:31 PM8/25/11
to wpf-di...@googlegroups.com
I agree that 99.9% (maybe more) won't have a performance issue at all.  You tend to spend more time in the logic of the VM vs. the property retrieval.  The area where I've seen higher performance issues is with data grids and high volume data changes.  It's an edge case and I was just curious if you'd done any analysis yet.

I like the concept though, I might (if you are ok with it), try some other alternatives that build on this for a little project I'm playing with.

mark

Bill Kempf

unread,
Aug 25, 2011, 12:36:14 PM8/25/11
to wpf-di...@googlegroups.com
OK, here's a benchmark for comparison. Using the traditional hand coding for a property setter, as illustrated in the blog, and doing 10000000 iterations where I change this property I see an elapsed time of 2984 milliseconds. Doing the same with the BackingStore technique I see an elapsed time of 98174. So, like I said, very significant overhead, but I still don't think it's overly likely to be a performance issue in most code.

Bill Kempf

unread,
Aug 25, 2011, 12:38:23 PM8/25/11
to wpf-di...@googlegroups.com
Absolutely. If you find ways to improve on the idea I'd love to hear about them. I'm going to be using this in a side project I'm working on in order to see how it works in the "real world", though this isn't a production quality project.

Bill Kempf

unread,
Aug 25, 2011, 12:57:57 PM8/25/11
to wpf-di...@googlegroups.com
More data. If I aslo retrieve the value in the loop the traditional approach goes up to 3146 milliseconds. Not a lot of difference there. The BackingStore approach, however, goes up to 183715, which is very significant.
 
In the past I've also used a BackingField<T> idea which comes very close to the performance of hand coding the traditional way.
 
public class Employee : INotifyPropertyChanged
{
    private readonly BackingField<string> firstName;
    private readonly BackingField<string> lastName;
 
    public Employee()
    {
        this.firstName = new BackingField<string>(() => this.FirstName, () => this.PropertyChanged);
        this.lastName = new BackingField<string>(() => this.LastName, () => this.PropertyChanged);
    }
 
    public string FirstName
    {
        get { return this.firstName.Value; }
        set { this.firstName.Value = value; }
    }
 
    public string LastName
    {
        get { return this.lastName.Value; }
        set { this.lastName.Value = value; }
    }
 
    public event PropertyChangedEventHandler PropertyChanged;
}
 
If performance is critical, this approach is nearly as fast as the traditional (the overhead is found in the constructor instead of in every property access), but it's not the easiest to code. You fight intellisense somewhat, and there's certainly more code to write. This variant also increases the size of your objects, which is another tradeoff to consider.

Bill Kempf

unread,
Aug 25, 2011, 1:25:58 PM8/25/11
to wpf-di...@googlegroups.com
For comparison sake, the BackingField approach with the same loop that sets and gets the property value takes 3479 milliseconds. Nearly identical to the hand coded traditional approach. If I could figure out a way to make the code here easier to write it would certainly be the better approach.
 
Like I said, the "holy grail" still alludes us. I really wish Microsoft would save us from all of this ;).

Colin Eberhardt

unread,
Aug 25, 2011, 1:36:03 PM8/25/11
to wpf-di...@googlegroups.com
To be honest, I think I prefer the INPC variant you show below. I don't like cryptic code in property setter / getters. I like the way the 'metadata' is configured in the constructor.

From: Bill Kempf
Sent: 25 August 2011 17:57
To: wpf-di...@googlegroups.com
Subject: Re: [WPF Disciples] Easy INPC

Mike Brown

unread,
Aug 25, 2011, 2:03:27 PM8/25/11
to WPF Disciples
Very similar to my ViewModelProperty concept (which I also robbed from
DependencyProperties). I think your implementation is even cleaner
because it doesn’t require the extra registration step (registration
occurs on first usage). I’ve built in stuff like calculated properties
(that fire their notification whenever the source property(ies)
change(s)) and added fully metadata driven objects.

Recently, I discovered that ExpandoObject supports INPC natively.
Entering the world of dynamic programming has been quite relaxing in a
weird way.


On Aug 25, 11:06 am, Bill Kempf <weke...@gmail.com> wrote:
> Check this code out.
>
> public class Employee : INotifyPropertyChanged
> {
>     public Employee()
>     {
>         this.RegisterPropertyChangedHandler(() => this.PropertyChanged);
>     }
>
>     public string FirstName
>     {
>        get { return this.GetBackingValue(() => this.FirstName); }
>        set { this.SetBackingValue(() => this.FirstName, value); }
>     }
>
>     public string LastName
>     {
>         get { return this.GetBackingValue(() => this.LastName); }
>         set { this.SetBackingValue(() => this.LastName, value); }
>     }
>
>     public event PropertyChangedEventHandler PropertyChanged;
>
> }
>
> Intrigued?http://digitaltapestry.net/blog/easy-modeling(BTW, pardon the

Bill Kempf

unread,
Aug 25, 2011, 2:06:25 PM8/25/11
to wpf-di...@googlegroups.com
Here's a slightly better version of the BackingField approach.
 
public class Employee : INotifyPropertyChanged
{
    private readonly BackingStorage storage;
    private readonly BackingField<string> firstName;
    private readonly BackingField<string> lastName;
 
    public Employee()
    {
        this.storage = new BackingStorage(() => this.PropertyChanged);
        this.firstName = this.storage.CreateField(() => this.FirstName);
        this.lastName = this.storage.CreateField(() => this.LastName);
    }
 
    public string FirstName
    {
        get { return this.storage.GetValue(this.firstName); }
        set { this.storage.SetValue(this.firstName, value); }
    }
 
    public string LastName
    {
        get { return this.storage.GetValue(this.lastName); }
        set { this.storage.SetValue(this.lastName, value); }
    }
 
    public event PropertyChangedEventHandler PropertyChanged;
}
Not a lot different, but I believe this altered design will use less memory. Probably the minimum amount of memory that your going to be able to use. It still maintains performance nearly identical to hand coded properties. It's still a bit tedious to code (I've used variants like this extensively, and can attest to how awful it is to have to write the constructors here), only slightly less onerous than hand coding, so it's biggest benefit is the removal of the magic string.

Mark Smith

unread,
Aug 25, 2011, 2:07:30 PM8/25/11
to wpf-di...@googlegroups.com
> Recently, I discovered that ExpandoObject supports INPC natively.
> Entering the world of dynamic programming has been quite relaxing in a
> weird way.

+1

It's quite interesting how much of the DynamicObject/ExpandoObject framework you can use to implement INPC.

Bill Kempf

unread,
Aug 25, 2011, 2:07:52 PM8/25/11
to wpf-di...@googlegroups.com
Hmmm... an expando property approach would be interesting. Wonder what kind of performance you could expect out of that approach? Have to profile that too :).

Mike Brown

unread,
Aug 25, 2011, 2:12:43 PM8/25/11
to WPF Disciples
Bill,
I think a compromise where you have a generic base class that holds
the backing fields but statically registers them on declaration would
give best of both worlds. I'll share with some of my code with you
later.

On Aug 25, 1:36 pm, Colin Eberhardt <colin.eberha...@gmail.com> wrote:
>   To be honest, I think I prefer the INPC variant you show below. I don't
> like cryptic code in property setter / getters. I like the way the
> 'metadata' is configured in the constructor.
> ------------------------------
> >>> Intrigued?http://digitaltapestry.net/blog/easy-modeling(BTW, pardon

Bill Kempf

unread,
Aug 25, 2011, 2:19:03 PM8/25/11
to wpf-di...@googlegroups.com
I dislike using a base class approach. I'm a fairly strong believer in not using base classes unless polymorphism is needed. I'd love to see any approach you come up with, though! If you can do it with a base class, I can probably do it through an aggregated approach as well.

Bill Kempf

unread,
Aug 25, 2011, 2:16:07 PM8/25/11
to wpf-di...@googlegroups.com
The ExpandoObject approach doesn't "save" you from the "magic strings", though. Just profiled and with expando the loop took 7555 milliseconds. Certain overhead, but less so (by far) than the BackingStore magic. So, this approach might make it easy to implement INPC, but I'm not sure I care for it.

Mike Brown

unread,
Aug 25, 2011, 3:44:03 PM8/25/11
to WPF Disciples
You know looking at my model...I think the base class isn't necessary.
I need to do some refactoring. I've gone back and forth over this
though. I used to be heavily against using the base class. Then I
didn't mind it so much. But looking at what I've done, it can work
either way.

On Aug 25, 2:19 pm, Bill Kempf <weke...@gmail.com> wrote:
> I dislike using a base class approach. I'm a fairly strong believer in not
> using base classes unless polymorphism is needed. I'd love to see any
> approach you come up with, though! If you can do it with a base class, I can
> probably do it through an aggregated approach as well.
>

Laurent Bugnion

unread,
Aug 25, 2011, 4:32:03 PM8/25/11
to wpf-di...@googlegroups.com
Just don't use that when you want any kind of Blend support... And since us poor Blend people get called after you devs had their fun, it means that you should probably never use Expando for INPC ;-)

Cheers
Laurent

Sent from my Windows Phone

From: Bill Kempf
Sent: 25.08.2011 20:54
To: wpf-di...@googlegroups.com
Subject: Re: [WPF Disciples] Re: Easy INPC


Hmmm... an expando property approach would be interesting. Wonder what kind of performance you could expect out of that approach? Have to profile that too :).

On Thu, Aug 25, 2011 at 2:03 PM, Mike Brown <mike....@azurecoding.net> wrote:
Very similar to my ViewModelProperty concept (which I also robbed from
DependencyProperties). I think your implementation is even cleaner
because it doesn’t require the extra registration step (registration
occurs on first usage). I’ve built in stuff like calculated properties
(that fire their notification whenever the source property(ies)
change(s)) and added fully metadata driven objects.

Recently, I discovered that ExpandoObject supports INPC natively.
Entering the world of dynamic programming has been quite relaxing in a
weird way.


On Aug 25, 11:06 am, Bill Kempf <weke...@gmail.com> wrote:
> Check this code out.
>
> public class Employee : INotifyPropertyChanged
> {
>     public Employee()
>     {
>         this.RegisterPropertyChangedHandler(() => this.PropertyChanged);
>     }
>
>     public string FirstName
>     {
>        get { return this.GetBackingValue(() => this.FirstName); }
>        set { this.SetBackingValue(() => this.FirstName, value); }
>     }
>
>     public string LastName
>     {
>         get { return this.GetBackingValue(() => this.LastName); }
>         set { this.SetBackingValue(() => this.LastName, value); }
>     }
>
>     public event PropertyChangedEventHandler PropertyChanged;
>
> }
>
> Intrigued?http://digitaltapestry.net/blog/easy-modeling(BTW, pardon the
> blog design... it's currently not that great and I'm working on it.)
>
> I'd really like to know what people think of this.
>
> --
>  Quidquid latine dictum sit, altum sonatur.
> - Whatever is said in Latin sounds profound.
>
> War is peace. Freedom is slavery.  Bugs are features.
>
>

Bill Kempf

unread,
Aug 25, 2011, 5:05:14 PM8/25/11
to wpf-di...@googlegroups.com
Hmm... I don't think you get how it's used ;).
 
public class Employee : INotifyPropertyChanged
{
    private readonly dynamic store = new ExpandoObject();
 
    public Employee()
    {
        var inpc = this.store as INotifyPropertyChanged;
        inpc.PropertyChanged += (s, e) => OnPropertyChanged(e.PropertyName);
    }
 
    public string FirstName
    {
        get { return this.store.FirstName; }
        set { this.store.FirstName = value; }
    }
 
    public string LastName
    {
        get { return this.store.LastName; }
        set { this.store.LastName = value; }
    }
 
    public event PropertyChangedEventHandler PropertyChanged;
 
    private void OnPropertyChanged(string propertyName)
    {
        var handler = this.PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propertyName);
        }
    }
}
 
Blend won't be able to tell I used ExpandoObject ;).

Peter O'Hanlon

unread,
Aug 27, 2011, 5:02:42 PM8/27/11
to wpf-di...@googlegroups.com
Nice job Bill. That's an interesting approach, and a neat use of ConditionalWeakTable.
--
Peter O'Hanlon
Reply all
Reply to author
Forward
0 new messages