none
Data binding without INotifyPropertyChanged

    Question

  • Hi All,

    I have a very simple example application as follows:

    • A simple object with a few properties. It does not implement INotifyPropertyChanged.
    • A listbox bound to a List<> of the above object, with a suitable datatemplate
    • A number of textboxes which are bound to properties of my object.
    All pretty standard and the data binding works just fine.

    Although, there is something that surprises me about how the application is working. If I edit the text displayed in my textbox, the corresponding property of the current item is updated when the textbox looses focus. No surprises here!

    However, what surprises me is that I see the listbox update to reflect this new value also. How is this working?

    I thought that for this to occur it was mandatory for my object to implement INotifyPropertyChanged, so that the property change as a result of the bound textbox causes an event to be raised which the listbox handles and updates its view accordingly?

    Interestingly, if I do implement INotifyPropertyChanged, but only raise event for some of the objects properties, then the non-notified properties no longer cause the listbox to update when modifying them with the textbox.

    Baffled.

    On a more general note, how does the listbox receive notification of changes to individual items? does it have to provide a handler for teh PropertyChanged event for every single item within the List?

    Thanks,
    Colin E.


    • Changed type Marco Zhou Thursday, July 24, 2008 10:49 AM OP doesn't revert back
    • Changed type Colin Eberhardt Monday, July 28, 2008 10:14 AM Added required details
    Thursday, July 17, 2008 8:05 AM

Answers

  • 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.
    • Marked as answer by Marco Zhou Thursday, July 31, 2008 11:01 AM
    Thursday, July 31, 2008 11:01 AM

All replies

  • A colleague of mine pointed out this previous thread which answers the question:

    http://forums.msdn.microsoft.com/en/wpf/thread/8e4f9b09-fd14-4be7-9d4b-f6038cd61e6d

    However, I am still interested to know how a listbox is notified of a change to any of the items which it contains.

    Colin E.

    Thursday, July 17, 2008 9:51 AM
  • -> I thought that for this to occur it was mandatory for my object to implement INotifyPropertyChanged, so that the property change as a result of the bound textbox causes an event to be raised which the listbox handles and updates its view accordingly?

    No, update from binding target to binding source doesn't require the data source object to implement INotifyPropertyChanged, INotifyPropertyChanged interface is used when you need to notify the binding target.

    -> Interestingly, if I do implement INotifyPropertyChanged, but only raise event for some of the objects properties, then the non-notified properties no longer cause the listbox to update when modifying them with the textbox.

    I cannot reproduce this problem, could you please provide a small, complete and ready-to-run example to demonstrate the issue you are encountering?

    Thanks
    Monday, July 21, 2008 9:18 AM
  • We are changing the issue type to “Comment” because you have not followed up with the necessary information. If you have more time to look at the issue and provide more information, please feel free to change the issue type back to “Question” by clicking the "Options" link at the top of your post, and selecting "Change Type" menu item from the pop menu. If the issue is resolved, we will appreciate it if you can share the solution so that the answer can be found and used by other community members having similar questions.

     

    Thank you!

    Thursday, July 24, 2008 10:49 AM
  • Hi,

    Thanks for looking into this, here is a simple example which illustrates.

    A window with listbox, and a simple 'detail' view beneath.

    <Window x:Class="WPFFontSizeBinding.Window1" 
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
        xmlns:c="clr-namespace:WPFFontSizeBinding" 
        Title="Window1" Height="300" Width="300"
        <Grid> 
            <StackPanel Orientation="Vertical"
                <ListBox ItemsSource="{Binding}" IsSynchronizedWithCurrentItem="True"
                    <ListBox.ItemTemplate> 
                        <DataTemplate> 
                            <StackPanel Orientation="Horizontal"
                                <TextBlock Text="{Binding Path=Name}"/> 
                            <TextBlock Text=", "/> 
                            <TextBlock Text="{Binding Path=Age}"/> 
                        </StackPanel> 
                        </DataTemplate> 
                    </ListBox.ItemTemplate> 
                </ListBox> 
                 
                <Grid Height="49"
                    <Grid.RowDefinitions> 
                        <RowDefinition Height="25*" /> 
                        <RowDefinition Height="24*" /> 
                    </Grid.RowDefinitions> 
                    <Grid.ColumnDefinitions> 
                        <ColumnDefinition Width="139*" /> 
                        <ColumnDefinition Width="139*" /> 
                    </Grid.ColumnDefinitions> 
                                     
                    <Label Grid.Column="0" Grid.Row="0">Name:</Label> 
                    <TextBox Grid.Column="1" Grid.Row="0"  Text="{Binding Path=Name}"/> 
                     
                    <Label Grid.Column="0" Grid.Row="1">Age:</Label> 
                    <TextBox Grid.Column="1" Grid.Row="1"  Text="{Binding Path=Age}"/> 
                </Grid> 
            </StackPanel> 
        </Grid> 
    </Window> 

    The code-behind:

    public partial class Window1 : Window 
        public class MyObject  
        { 
            private string name; 
            private string age; 
     
            public string Name 
            { 
                get { return name; } 
                set { name = value; } 
            } 
             
            public string Age 
            { 
                get { return age; } 
                set { age = value; } 
            } 
        } 
     
        private List<MyObject> objects = new List<MyObject>(); 
     
        public Window1() 
        { 
            objects.Add(new MyObject() { Name = "Frank", Age = "34" }); 
            objects.Add(new MyObject() { Name = "Bob", Age = "56" }); 
            objects.Add(new MyObject() { Name = "Ian", Age = "12" }); 
     
            InitializeComponent(); 
     
            this.DataContext = objects; 
        } 
     

    If you edit one of the properties via its associated TextBox, when the control looses focus, the respective items within the ListBox is updated. Therefore there is some form of notification occurring because the binding target (listbox) has been updated to reflect a change in binding source, all of this without the bound object implementing INotifyPropertyChanged.

    Stranger still, when I partially implement INotifyPropertyChanged:

    public class MyObject : INotifyPropertyChanged 
        private string name; 
        private string age; 
     
        public string Name 
        { 
            get { return name; } 
            set { 
                name = value; 
                if (PropertyChanged != null
                { 
                    PropertyChanged(thisnew PropertyChangedEventArgs("Name")); 
                } 
            } 
        } 
         
        public string Age 
        { 
            get { return age; } 
            set { age = value; } 
        } 
     
        public event PropertyChangedEventHandler PropertyChanged; 

    With the code modified as per the above, the age property displayed in the ListBox no longer reflects any changes made in the TextBox.

    The above is not actually causing me any problems, other than being a little confusing! I would love to know how the ListBox is being notified that a property has changed when my object does not implement INotifyPropertyChanged, and why, when i partially implement it for my object, this no longer happens.

    Thanks in advance,
    Colin E.
    Monday, July 28, 2008 10:14 AM
  • 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.
    • Marked as answer by Marco Zhou Thursday, July 31, 2008 11:01 AM
    Thursday, July 31, 2008 11:01 AM
  • Hi,

    That answers my question perfectly. Many thanks!

    Colin E.

    Thursday, July 31, 2008 12:17 PM
  • Can you clarify if this does work in Silverlight too?

    Microsoft MVP J# 2004-2010, Borland Spirit of Delphi 2001

    Thursday, May 24, 2012 4:22 PM
  • hey
    Avatar of Marco Zhou

    Marco Zhou

    Det Norske Veritas

    21,195 Points1042
    Recent Achievements
    Forums Replies VFirst Helpful VoteThread Mover II

    steven frierdich

    Tuesday, August 21, 2012 2:02 PM