'PropertyChanged?.Invoke(...) call calling the setter again when stepping through a Set statement

I have a simple base class that implements INotifyPropertyChanged. The code works. But when I was stepping through a Set statement, when the Set statement called SetProperty(), I noticed that the PropertyChanged?.Invoke(...) call was calling the setter again.

So the setter code in the subclass looks something like:

private string someProperty ;
public string SomeProperty { get => someProperty ;
set {
    // Do some tests on value to make sure it's valid
    SetProperty(ref someProperty, value);
    // Now do some other stuff once that is set
}

When I step through it the call stack shows:

  • SomeProperty.Set( valuetype value); ????? Why again???? --- 5
  • External Code --- 4
  • OnPropertyChanged(string propertyName ) --- 3
  • SetProperty(field, value) --- 2
  • SomeProperty.Set( valuetype value) ---- Initial set execution

Code snippet:

public abstract class ViewModelBase : INotifyPropertyChanged
{        
    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged(string propertyName)
    {
        Dev.Tools.Assert(propertyName != null, "propertyName can't be null.... ");
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    // This is used to support change tracking.  But 
    //   the problem happens even when TrackChangedFields is false.
    // The EqualityComparer prevents this from being recursive.
    public virtual bool SetProperty<T>(ref T field, T newValue, [CallerMemberName] string propertyName = null)
    {
        if (!EqualityComparer<T>.Default.Equals(field, newValue))
        {
            field = newValue;
            OnPropertyChanged(propertyName);

            if (TrackChangedFields && !IgnoreFieldList.Contains(propertyName))
            {
                ChangedFieldList.Add(new ChangedRecordDetail(propertyName, field, newValue, ViewModelName));
            }
            return true;
        }
        return false;
    }

Any idea why the PropertyChanged?.Invoke() call is causing the set to fire again?

Again, this code works fine. I just don't understand why the 2nd call to the setter is happening nor what to do to only have the setter called once.



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source