1

My "parent" view-model (AnalyzeVm) has a child view-model (ScanVm) that represents something that can be saved to disk. I want to give the parent a command (SaveCmd) that is enabled only when the ScanVm.IsDirty property is true.

I already use DelegateCommand and its ObservesProperty functions all over the place so I tried to use it for this. But in this one case I cannot get the ObservesProperty expression to trigger a call to CanExecute.

The difference here (from all the other places I use ObservesProperty that work fine) is that I'm monitoring a property of the child object. Not of my own

I need to understand why this is not working. I thought this was a valid thing to do.

Here are the two view models (stripped down for clarity)

// Parent view-model.  Derives from a class that implements INotifyPropertyChanged.

public class AnalyzeVm : BaseViewModel
{
    private ScanVm _scan;

    public AnalyzeVm(ScanVm scan)
    {
        _scan = scan;

        // Set up the command.  Try to make it monitor a property of the ScanVm
        // object instead of one of our own.

        SaveScanCmd = new DelegateCommand(
            () => { _scan.Save() }                 // execute -- saves the scan
            () => { return _scan.IsDirty; })       // only valid when scan is dirty
            .ObservesProperty(() => scan.IsDirty); // So observe IsDirty property

        // Now just as a sanity check, add a handler for that property changing
        // to the PropertyChangedEventManager and log when it does.

        PropertyChangedEventManager.AddHandler(
            scan, 
            (_, _) => Debug.WriteLine("IsDirty changed"), 
            nameof(ScanContext.IsDirty));
    }

    public ICommand SaveScanCmd { get; }

    // other code...
}

// ScanVm class.  

public class ScanVm : BaseViewModel
{
    private bool _isDirty;
    public bool IsDirty
    { 
        get => _isDirty;
        set => SetProperty(ref _isDirty, value);  // Raises PropertyChanged event
    }
    public void Save()
    {
        // Code here to save the ScanVm
       
        IsDirty = false;  // No longer dirty
    }
    // ... other code
}

I am sure that the IsDirty property is properly changing and firing the event. I confirmed it many times. And I'm already using Observes property successfully when I observe my own class' properties. For example, I were to, take the SaveCmd and move it into the ScanVm class itself -- so that the property expression just observed the ScanVm's own property, then it works fine. I do that all over the place in my code.

This is the only place I'm trying to observe another object's property. Is it valid to do? if so, what am I doing wrong?

Joe
  • 5,394
  • 3
  • 23
  • 54

1 Answers1

1

ObservesProperty primarily works on properties of the containing object

public bool IsDirty {...}

...ObservesProperty( () => IsDirty );

plus nested properties

public ScanVM Child {...}

...ObservesProperty( () => Child.IsDirty );

It just doesn't observe properties on any given instance, because it starts looking from the containing object (AnalyzeVm in this case).

Haukinger
  • 10,420
  • 2
  • 15
  • 28
  • Bummer. I guess I was hoping that it could somehow pick up the instance from the expression. I'll retool the command. Thanks – Joe Apr 14 '22 at 09:59
  • There _should_ be an error message somewhere like `"scan" is no property of "AnalyzeVm"`, but probably it's just not there. – Haukinger Apr 14 '22 at 14:37
  • I tried and got an exception when observing the property of a field or parameter, actually, not very clear, but clearly not working. – Haukinger Apr 14 '22 at 15:30
  • I don't know why I don't get one, but if it's not what it was designed for, I suppose it's moot. – Joe Apr 14 '22 at 15:33