Welcome to Pete Brown's 10rem.net

First time here? If you are a developer or are interested in Microsoft tools and technology, please consider subscribing to the latest posts.

You may also be interested in my blog archives, the articles section, or some of my lab projects such as the C64 emulator written in Silverlight.

(hide this)

Puff the Magic POCO Binding and INotifyPropertyChanged in WPF

Pete Brown - 17 December 2010

Yesterday I wrote a post about different ways of working with INotifyPropertyChanged. One of my readers (who only went by "Guest") pointed out that binding "magically" worked in WPF with POCOs (Plain Old CLR Objects) that didn't bother to implement INotifyPropertyChanged. I thought for sure he/she was wrong … until I tried it myself. Magic, I say! Magic!

Then again, as one of the WPF team members pointed out to me, this is a great example of Clarke's third law. :)

Take this example:

<Window x:Class="WpfApplication1.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">
<Grid>
<ListBox x:Name="PeopleList"
Height="287"
HorizontalAlignment="Left"
DisplayMemberPath="LastName"
Margin="12,12,0,0"
VerticalAlignment="Top"
Width="138" />
<TextBox Height="23"
HorizontalAlignment="Left"
Margin="265,24,0,0"
x:Name="LastNameField"
VerticalAlignment="Top"
DataContext="{Binding ElementName=PeopleList, Path=SelectedItem}"
Text="{Binding LastName}"
Width="120" />
<TextBlock Height="23"
HorizontalAlignment="Left"
Margin="178,27,0,0"
Text="Last Name"
VerticalAlignment="Top" />
</Grid>
</Window>

Here's the Person Class

class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
}

Here's the Code-behind

public partial class MainWindow : Window
{
private ObservableCollection<Person> _people;

public MainWindow()
{
InitializeComponent();

_people = new ObservableCollection<Person>();

_people.Add(new Person() { LastName = "Brown" });
_people.Add(new Person() { LastName = "Fitz" });
_people.Add(new Person() { LastName = "Hanselman" });
_people.Add(new Person() { LastName = "Heuer" });
_people.Add(new Person() { LastName = "Galloway" });
_people.Add(new Person() { LastName = "Stagner" });
_people.Add(new Person() { LastName = "Liberty" });
_people.Add(new Person() { LastName = "Litwin" });
_people.Add(new Person() { LastName = "Papa" });
_people.Add(new Person() { LastName = "Guthrie" });

PeopleList.ItemsSource = _people;
}
}

When you run this little application, and modify the value in the TextBox, the value in the ListBox is updated, seemingly by magic.

image

There it is. The value in the ListBox updated right when I tabbed off of the last name field. Magic code? Spirits? Too much alcohol? What is happening here?

What's Really Happening

The Person class has a PropertyDescriptor for each property. The PropertyDescriptor has the AddValueChanged method by which a listener can sign up to get the property change notifications from that descriptor. That's what the behind-the-scenes binding is doing - wiring up a value changed event for the property descriptor in play in the binding.

Note this only works when using binding. If you update the values from code, the change won't be notified.

What's happening is actually a perfectly valid (if not optimal) way to handle binding and change notification. What WPF is doing behind the scenes in this case is something you could explicitly put in your own code if you wish.

Implications

The PropertyDescriptor class is pretty heavy. In addition, WPF must request the full set of descriptors for the class, not just a single descriptor. If you have a class with a large number of properties, regardless of how many are actually involved in binding, the CPU and memory usage associated with that call can be both significant and measurable. In one instance, the memory used to get all the property descriptors for a large class was around 800K!

But doesn't WPF need that for binding anyway?

No. WPF uses the much lighter weight PropertyInfo class when binding. If you explicitly implement INotifyPropertyChanged, all WPF needs to do is call the PropertyInfo.GetValue method to get the latest value. That's quite a bit less work than getting all the descriptors. Descriptors end up costing in the order of 4x the memory of the property info classes.

Note also that if you have a reference from the POCO back in the UI (we don't do that, right…right?) you may be subject to the memory leak described in KB938416. That only applies to the PropertyDescriptor-based approach, which in this post, is POCO only.

Summary

Implementing INotifyPropertyChanged can be a fair bit of tedious development work. However, you'll need to weigh that work against the runtime footprint (memory and CPU) of your WPF application. Implementing INPC yourself will save runtime CPU and memory.

Thanks to the WPF team for the detailed information about what's going on here. I love being able to talk to the people who actually wrote the code :)

Note that Silverlight does not have the PropertyDescriptor class, so this doesn't apply there.

       
posted by Pete Brown on Friday, December 17, 2010
filed under:        

25 comments for “Puff the Magic POCO Binding and INotifyPropertyChanged in WPF”

  1. wekempfsays:
    "Note this only works when using binding. If you update the values from code, the change won't be notified."

    That's key, and probably should be in big bold letters here. You very rarely can rely on this "magic", since command handlers will almost always modify the values.
  2. guestsays:
    Thanks for a detailed insight for the little trick, good to know the behind story and a clarification from the team.

    It's still quite a convenient quick approach for certain scenarios. :-)
  3. guestsays:
    The problem I have with INPC is, I have data from 3rd party, or remote services, or underlying servicing layer which have no knowledge at all about the UI technology in the presenting layer, and wont change their data type for me. So what I need is a Just-In-Time wrapping solution, or I can only use POCO
  4. Naimishsays:
    So if anyone wants not to let this magic happens, what should be done?

    I found from here http://support.microsoft.com/kb/938416 that Set the mode of the data binding to OneTime.

    Can anyone please explain with the code?

    Thanks.....
  5. James Chaldecottsays:
    Unfortunately, we found it quite easy to hit the memory leak (until we knew better).

    If you implement a PresentationModel/ViewModel but think to yourself "None of these properties ever change, there's no point implementing INotifyPropertyChanged", then you can easily cause it.

    Like this:

    // BAD CODE: This will leak!
    public class MyPresentationModel : IMyPresentationModel
    {
    public void MyPresentationModel(IMyView view)
    {
    this.ViewTitle = "Leaky View";

    this.View = view;
    this.View.Model = this;
    }

    public string ViewTitle { get; private set; }
    }

    <!-- MyView.xaml -->
    <TextBlock Text="{Binding ViewTitle}" />

    In this case the PM has a reference to its view, and the view binds to CLR properties on the PM. If the PM does not implement INotifyPropertyChanged, then both the PM and the view (and *anything connected to them in the visual tree*) will leak.

    Note again that even if only one binding on a single V/VM pair (that may be part of a large composite view) is triggering this issue, the WHOLE of any view using it that you remove from the application's visual tree will leak, because all elements in the tree have a strong reference to their parent and all their children.

    We add/remove complex views to the visual tree a lot, so this hurt us terribly until we found it (in just a few pretty insignificant views). Note that all you have to do to avoid the leak is *implement* INotifyPropertyChanged, not actually fire the events.
  6. Eric Hillsays:
    @guest who said "The problem I have with INPC is, I have data from 3rd party. . . ." - That is exactly what the ViewModel layer is for in MVVM. All your 3rd-party service has to provide is a way for you to find out that something about it has changed. The ViewModel layer will monitor such change notifications and then change one or more of it's properties that the View is bound to so that the View updates. I have implemented MVVM where the underlying model was native C++ code. No worries, the ViewModel class (implemented in C++/CLI in this case) bridges the gap. If you use Josh Smith's ViewModel base class, it implements INPC on your behalf; you just call OnPropertyChanged when one of your properties changes.

    Eric
  7. guestsays:
    Yes. by 'Just-In-Time wrapping' I realy meant 'generating a ViewModel on the fly'.

    That data object has complex structure, many properties and collections of other data objects, and its static while presenting, while directly bind this to the UI 'ALREADY WORKS', to manually clone the whole data hierarchy and build another complex 'VideoModel' wrapping layer solely for implementing INPC and make the binding engine even happier is ridiclous, unless I can do it on-the-fly, without much effort.
  8. Mikhailsays:
    I would like to see this in C# 5:

    1. for each object property Xyz auto-generate static field named XyzProperty.
    2. notify syntax becomes NotifyPropertyChanged( XyzProperty );
    3. now we have handy syntax to assign properties dynamically:
    myProp = myClass.XyzProperty;
    ...
    myObj[ myProp ] = newValue;
  9. guestsays:
    Well, using DynamicProxy or other things to generate ViewModel leads to its own overhead, this make the benefits of implementing INPC negligible, and the simplest method cant be simpler than zero, it looks like binding model to the ui directly is the way to go in my scenario, maybe MVVM is not for me. :-P

    and, since the data model has no knowledge of ui at all, obviously it wont have a reference in the visual tree, so memory leak is unlikely to happen, right ? :-)
  10. Thomassays:
    There is a bug/interesting feature in WPF in the implementation when binding to "plain of objects" that do not implement INPC. It seems like WPF uses some internal cache for such bindiing. If I remember it correctly, the problem is that it is caching the property descriptor, but a side effect is that if the binding is made in a data template, the data template will be references by the cache and the data template in turn will reference the data context. In practice this means that your whole view model will be referenced and will cause a memory leak. The cache is a static object.
    For this reason we try very hard to avoid such bindings.
  11. guestsays:
    @Thomas, Thank you but what I am asking is, how is it triggered exactly in you 'data template' scenario, especially the condition : "Object X contains a direct reference or an indirect reference to the target of the data-binding operation."
    So what is referenced by what ?
  12. Thomassays:
    As I remember it we had nothing more than constructs like:

    <DataTemplate DataType="{x:Type MyViewModel}">
    <TextBlock Text="{Binding SomeProperty}" />
    </DataTemplate>

    class MyViewModel
    {
    public string SomeProperty {get {return "Hohoho"; } }
    }

    Meybe there were some more conditions for the problem. It was more than a year ago that we struggled with this.
    See also https://connect.microsoft.com/WPF/feedback/details/351091/wpf-data-binding-memory-leak


  13. Rodsays:
    Hey Pete, I read this and I still find necessary to implement INPC for my POCO's.

    Just like you point out, WPF bindings will reflect the property information (or property descriptors) to access the getters... But what happen when changes to a property comes for the back-end? What happen when my POCO is able to react to some changes and update internal properties?
    WPF will ignore those changes because there is nothing interacting with the presentation layer.

    Here my sample:

    --- A View model ----
    using System.Threading;
    using System.Windows.Threading;

    namespace PocoSample
    {
    public class TestViewModel
    {
    private readonly Timer _timer;

    public TestViewModel()
    {
    _timer = new Timer(TimeOut, this, 0, 2000);
    }

    public int Seconds { get; set; }

    private void TimeOut(object state)
    {
    Dispatcher.CurrentDispatcher.Invoke(DispatcherPriority.Normal, (Action)(() => { Seconds += 2; }));
    }
    }
    }
    --- End of View model ---

    --- XAML Code ---
    <Window x:Class="PocoSample.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:PocoSample"
    Title="MainWindow" Height="350" Width="525">

    <Window.Resources>
    <local:TestViewModel x:Key="Instance" />
    </Window.Resources>

    <Grid DataContext="{StaticResource Instance}">
    <TextBlock Text="{Binding Seconds, StringFormat='Should Display {0}'}" />
    </Grid>
    </Window>
    --- End of XAML Code ---

    The object should be updating every now and then the seconds property for the view model, but the presentation layer is just ignoring it (in really, it doesn't know about the change).
    This is the real reason why you need the INPG; you should expose this in your post.

    Cheers

    PS: I know the sample is a bit silly, but you could have the exact same thing with a DateOfBirth that sets the Age for your instance. Even though WPF will update DateOfBirth it won't realise about Age changes.
  14. Petesays:
    @Rod

    Thanks. That's a perfectly valid example. I mentioned in the post that the "magic" doesn't work if you change values from code, and I definitely wasn't advocating the use of the implicit change notifications :)

    Pete

Comment on this Post

Remember me