47

I created a ViewModel and bound its property to two textboxes on UI. The value of the other textbox changes when I change the value of first and focus out of the textbox but I'm not implementing INotifyPropertyChanged. How is this working?

Following is XAML

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WpfApplication1"
        Title="MainWindow" Height="350" Width="525">
    <Window.DataContext>
        <local:ViewModel />
    </Window.DataContext>
    <StackPanel>
        <TextBox Text="{Binding Name}" />
        <TextBox Text="{Binding Name}" />
    </StackPanel>
</Window>

And following is my ViewModel

class ViewModel
{
    public string Name { get; set; }
}
svick
  • 236,525
  • 50
  • 385
  • 514
Muhammad Hasan Khan
  • 34,648
  • 16
  • 88
  • 131

3 Answers3

60

I tested it, you are right. Now i searched for it on the web, and found this.

Sorry to take so long to reply, actually you are encountering a another hidden aspect of WPF, that's it WPF's data binding engine will data bind to PropertyDescriptor instance which wraps the source property if the source object is a plain CLR object and doesn't implement INotifyPropertyChanged interface. And the data binding engine will try to subscribe to the property changed event through PropertyDescriptor.AddValueChanged() method. And when the target data bound element change the property values, data binding engine will call PropertyDescriptor.SetValue() method to transfer the changed value back to the source property, and it will simultaneously raise ValueChanged event to notify other subscribers (in this instance, the other subscribers will be the TextBlocks within the ListBox.

And if you are implementing INotifyPropertyChanged, you are fully responsible to implement the change notification in every setter of the properties which needs to be data bound to the UI. Otherwise, the change will be not synchronized as you'd expect.

Hope this clears things up a little bit.

So basically you can do this, as long as its a plain CLR object. Pretty neat but totally unexpected - and i have done a bit of WPF work the past years. You never stop learning new things, right?

As suggested by Hasan Khan, here is another link to a pretty interesting article on this subject.

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

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. [...]

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.

Edit:

Updating this, since i still get comments and upvotes now and then from here, so it clearly is still relevant, even thouh i myself have not worked with WPF for quite some time now. However, as mentioned in the comments, be aware that this may cause memory leaks. Its also supposedly heavy on the Reflection usage, which has been mentioned as well.

Community
  • 1
  • 1
  • 4
    +1 I've been using WPF for years and never realised this - maybe you should put it on the "Hidden WPF features" thread on here? – Steve Greatrex Oct 14 '11 at 12:07
  • Interesting. I didn't know that I've also been working in WPF for quite a while now. – Muhammad Hasan Khan Oct 14 '11 at 12:09
  • Then why didnt we take this approach for all types of source objects in WPF? Why was there a need for `INotifyPropertyChanged`? – WPF-it Oct 14 '11 at 12:21
  • You should add this link to your answer. http://10rem.net/blog/2010/12/17/puff-the-magic-poco-binding-and-inotifypropertychanged-in-wpf – Muhammad Hasan Khan Oct 14 '11 at 12:21
  • @AngelWPF - I read tests that showed that the automagically added change events are slower than a custom implemented INotifyPropertyChanged interface – Emond Oct 14 '11 at 12:25
  • @HasanKhan Great article, added it –  Oct 14 '11 at 12:28
  • 1
    @AngelWPF - the link Hasan Khan posted explains that it will only cause the UI to be updated if the property is changed from the UI - changes from code will not be propagated – Steve Greatrex Oct 14 '11 at 12:28
  • 3
    I have updated my answer with all related info i deemed valueable for a quick glance. Another day, another secret exposed! I love StackOverflow :) –  Oct 14 '11 at 12:39
  • I just ran into this. I was showing an intern how data binding could work with inheritance and changing the DataContext, etc. When I setup the example, I ran it, expecting it to fail because I didn't implement INotifyPropertyChanged... and lo! It worked! – EJA Jun 12 '12 at 19:14
  • 2
    So, people should be aware that if you don't implement INotifyPropertyChanged on a CLR object ... you will cause memory leaks. See http://www.cplotts.com/2009/04/14/wpf-memory-leaks/. – cplotts Sep 21 '16 at 15:42
  • Not implementing `INotifyPropertyChanged` will result in heavy use of reflection in order to resolve the binding references. This is not a "hidden" feature as it is well documented in the data binding overview. It's clearly stated, that you can bind to any object and property. Only constraint is that the `Binding.Target` has to be a `DependencyProperty`. – BionicCode May 31 '20 at 22:10
  • @cplotts Thanks for pointing out, i have updated my answer with this info. –  Jun 08 '20 at 12:08
  • @bioniccode Thanks for pointing out, i have updated my answer with this info. –  Jun 08 '20 at 12:08
  • Saved my life, when unconsciously used this hidden feature and suddenly my binding broke. I lost more than a day trying to understand what broke. Even after fixing it, I didn't realised it was an undocumented feature. – profimedica Nov 26 '22 at 15:26
2

I just found out that this also works in WinForms, kinda :/

public class Test
{
    public bool IsEnabled { get; set; }
}

var test = new Test();
var btn = new Button { Enabled = false, Text = "Button" };
var binding = new Binding("Enabled", test, "IsEnabled");
btn.DataBindings.Add(binding);
var frm = new Form();
frm.Controls.Add(btn);
test.IsEnabled = true;
Application.Run(frm);

Strangely though, this doesn't disable the button:

btn.Enabled = false;

This does:

test.IsEnabled = false;
Viet Norm
  • 283
  • 1
  • 3
  • 12
0

I can explain why the property is updated when focus changes: all Bindings have an UpdateSourceTrigger property which indicates when the source property will be updated. The default value for this is defined on each DependencyProperty and for the TextBox.Text property is set to LostFocus, meaning that the property will be updated when the control loses focus.

I believe UrbanEsc's answer explains why the value is updated at all

Steve Greatrex
  • 15,789
  • 5
  • 59
  • 73