15

I have a ViewModel with a complex property type and want to bind my view to a nested property of this object.

My ViewModel is implementing INotifyPropertyChanged (or do be extact BaseViewModel is implementing it). The class of the parent property is not implementing INotifyPropertyChanged.

The class Car is not implementing INotifyPropertyChanged. But I'm not changing the property Manufacturer, I change the MyCarProperty property, and so I expect that the OnNotifyPropertyChanged event will trigger the value update?

When I'm updating the value of the parent property, the nested property is not updating. Can you tell me how can I implement this functionality?

ViewModel

public class ViewModel : BaseViewModel
{
    private Car _myCarProperty;

    public Car MyCarProperty
    {
        get { return _myCarProperty; }
        set
        {
            if (value == _myCarProperty) return;

            _myCarProperty = value;
            OnPropertyChanged();
        }
    }
}

Binding in the View

<TextBlock Text="{Binding Path=MyCarProperty.Manufacturer}" />

When I change the value of MyCarProperty the View does not update.

Thanks for any help!

Edit: OnPropertyChanged() implementation

#region INotifyPropertyChanged

public event PropertyChangedEventHandler PropertyChanged;

[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
    PropertyChangedEventHandler handler = PropertyChanged;
    if (handler != null)
    {
        handler(this, new PropertyChangedEventArgs(propertyName));
    }
}

#endregion INotifyPropertyChanged
StayOnTarget
  • 11,743
  • 10
  • 52
  • 81
Felix C
  • 1,755
  • 5
  • 26
  • 40
  • have you notify child property? – J R B Aug 14 '13 at 10:38
  • The class `Car` is not implementing `INotifyPropertyChanged`. But I'm not changing the property `Manufacturer`, I change the `MyCarProperty` property, and so I expect that the OnNotifyPropertyChanged event will trigger the value update? - please see my edited question. – Felix C Aug 14 '13 at 10:53
  • 1
    Can you show us how OnPropertyChanged is implemented? – Roland Bär Aug 14 '13 at 11:26
  • I added the OnPropertyChanged implementation. – Felix C Aug 14 '13 at 14:15
  • @FelixC Is your `BaseViewModel` telling the compiler it's implementing INotifyPropertyChanged, e.g. `public class BasseViewModel: INotifyPropertyChanged`? Your example seemed to work when I did a little mock up. – Chris Aug 14 '13 at 14:38
  • Yes, sure it is ;-) can you provide your code via pastebin.com or any similiar site? I'm a little bit confused that it's working for you. – Felix C Aug 15 '13 at 07:38
  • Sure, I'm probably missing something/assuming something odd: http://pastebin.com/cPpJ0NE0 – Chris Aug 15 '13 at 09:02
  • I tested nested property, seem like the changes will propagate in my case without any extra work, you must have messed up something else in your example – gavin Jun 24 '15 at 01:00

3 Answers3

20

"The class Car is not implementing INotifyPropertyChanged. But I'm not changing the property Manufacturer, I change the MyCarProperty property, and so I expect that the OnNotifyPropertyChanged event will trigger the value update?"

Nope, it won't trigger the value update a level down. Bindings don't listen to property changes for an entire path, they listen only to the object that they're bound to.

I see a couple options off the top of my head (in order of my preference when I run into this):

  1. Bind to the car, not the sub property, and create a data template that displays what you want out of it.
  2. Manually kick the binding by calling UpdateTarget on it's BindingExpression when you need to.

I know it looks like there's a lot more to learn on the data template route, but I promise you that data templates will prove vastly more powerful, scalable, maintainable, and useful than manually kicking bindings as you work more in WPF. (Also, once you understand them, I think they're actually less work than manually kicking bindings).

Good luck!

StayOnTarget
  • 11,743
  • 10
  • 52
  • 81
Greg D
  • 43,259
  • 14
  • 84
  • 117
  • Thanks Greg! I know about data templates and should not have any problems with them. I had the same issue some time ago and I remember that I found something in the past that sounds like "deep looking bindings", but I guess it was only the `VeryObservableCollection` I found [here](http://stackoverflow.com/questions/6542035/listview-not-updated-correctly-with-observablecollection) - which does not help with this issue. I hoped that something similiar would be existing. But the data template idea is perfect :) – Felix C Aug 14 '13 at 14:12
  • 3
    Sorry, what? WPF doesn't listen to changes along the path? I wish I knew this before I started using chained paths everywhere. Hey, stop. It works! ;) – Eugene Strizhok Jan 10 '14 at 15:14
  • 1
    @Greg D, the "data template" link is outdated. Sorry, i just feel bored. – Andrey K. Dec 15 '15 at 18:04
  • Bored indeed! Updated with what I presume was the original link. :) – Greg D Dec 15 '15 at 18:15
12

The accepted answer explains how to handle the case where a sub-property on a Binding Source is changed and you wish to update the view - which is not what the question is asking. WPF will in fact respond to changes from many levels down, so long as you are notifying changes for any properties being changed within the specified path.

As for this:

"The class Car is not implementing INotifyPropertyChanged. But I'm not changing the property Manufacturer, I change the MyCarProperty property, and so I expect that the OnNotifyPropertyChanged event will trigger the value update?"

WPF handles this already.

In your example, ViewModel is the Binding Source. When you set MyCarProperty (firing the NotifyPropertyChanged event), WPF will re-evaluate the Binding Target Value using the Binding Path for the new Binding Source object - updating your view with the new Manufacturer.

I have tested this with a simple WPF app - it also holds true for very deeply nested Paths:

https://pastebin.com/K2Ct4F0F

<!-- When MyViewModel notifies that "MyCarProperty" has changed, -->
<!-- this binding updates the view by traversing the given Path -->
<TextBlock Text="{Binding Path=MyCarProperty.Model.SuperNested[any][thing][you][want][to][try][and][access].Name}" />
notracs
  • 433
  • 5
  • 8
3

I'm not an WPF expert, but I think it's because you've chosen the wrong path.

<TextBlock Text="{Binding Path=MyCarProperty, Value=Manufacturer}" />

update:

<TextBlock Text="{Binding Source=MyCarProperty, Path=Manufacturer}" />
Jeroen van Langen
  • 21,446
  • 3
  • 42
  • 57