Search code examples
c#mauicommunity-toolkit-mvvm

NotifyPropertyChangedFor not working on ObservableObject


I'm a little lost right now. I'm using the CommunityToolkit.Mvvm for MVVM in a small application. My UI consists of some settings and some parameters; I'm updating (performing calculations) once a property changes.

In this case I'd like to fire NotifyPropertyChangedFor as I do calculations with the focal length of a camera - but this gets never triggered.

So while things are working nicely with 'local' properties I'm having issues with objects that come in via a service (so iot injected) like the focal length.

Simplified example:

I have a data container like this:

public partial class Settings : ObservableObject
{
    private CameraSettings cameraSettings;

    public CameraSettings CameraSettings
    {
        get => cameraSettings ?? (cameraSettings = new CameraSettings());
        set => SetProperty(ref cameraSettings, value);
    }
}

And an object that is actually holding the values:

public partial class CameraSettings: ObservableObject
{
    private int focalLength = 15;

    public int FocalLength
    {
        get => focalLength;
        set => SetProperty(ref focalLength, value);
    }
}

And I have a viewmodel which is supposed to use this:

[ObservableProperty]
[NotifyPropertyChangedFor(nameof(ResultsEditorBox))]
private CameraSettings cameraSettingsContainer;

[ObservableProperty]
[NotifyPropertyChangedFor(nameof(ResultsEditorBox))]
private string connectionType;

public SettingsViewModel(SettingsService settingsService)
{
    cameraSettingsContainer = settingsService.Settings.CameraSettings;
}

The ResultEditorBox is just another local property to update UI

public string ResultsEditorBox
{
    get
    {
        return "UI update done";
    }
}

While using any 'local' observed property like connectionType everything is working as expected and ResultsEditorBox gets called in the end.

If I do the same with my custom object cameraSettingsContainer I see that set => SetProperty(ref focalLength, value); gets called correctly; but the NotifyPropertyChangedFor doesn't trigger.

To my understanding this should work via the CommunityToolkit.Mvvm.

But why is NotifyPropertyChangedFor not working via the CameraSettings object?


Solution

  • What you're trying to do here is not possible like that, because child property changes are not automatically propagated up to the highest level.

    The [NotifyPropertyChangedFor()] attribute only applies to the CameraSettingsContainer property, but not its child properties. You'll need some other way to raise the PropertyChanged event for ResultsEditorBox.

    One way to solve this would be to subscribe to the PropertyChanged event of the CameraSettingsContainer and then raise the notification in the event handler:

    public SettingsViewModel(SettingsService settingsService)
    {
        CameraSettingsContainer = settingsService.Settings.CameraSettings;
        CameraSettingsContainer.PropertyChanged += (s,e) =>
        {
            OnPropertyChanged(nameof(ResultsEditorBox));
        }
    }
    

    I wrote a blog series about MVVM Source Generators, which you may be interested in. It explains how they work and what happens under the hood.