0

I have a question about the PropertyChanged event firing from a base class. So I have a base class, called MainWindowBase with a property called SelectedItem and a collection called Items, actually derived in a lower base class. I populate Items, then set SelectedItem from the derived class, which calls the base class setter on SelectedItem. The SelectedItem.PropertyChanged handler is never called in the derived class. Why?

class MainWindowViewModel:

class MainWindowViewModel : MainWindowBase<DocumentBase>
{
    public MainWindowViewModel()
    {
        Items.AddRange(new ObservableCollection<PositionViewModel>()
        {
          new PositionViewModel { Name = "Test Case 1" },
          new PositionViewModel { Name = "Test Case 2" },
          new PositionViewModel { Name = "Test Case 3" }
        });

        SelectedItem = Items.FirstOrDefault();

        SelectedItem.PropertyChanged += (sender, args) =>
        {
            Debug.WriteLine("SelectedItem changed!");
        };


        PropertyChanged += MainWindowViewModelPropertyChanged;

        SelectedItem = Items[1];
    }

    public void MainWindowViewModelPropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        ;
    }
}

class MainWindowBase:

public class MainWindowBase<TDocument> : Conductor<TDocument>.Collection.OneActive
    where TDocument : DocumentBase, new()
{

    private TDocument selectedItem;

    public TDocument SelectedItem
    {
        get
        {
            return selectedItem;
        }

        set
        {
            selectedItem = value;
            NotifyOfPropertyChange(() => SelectedItem);
        }
    }
}

PositionViewModel class:

public class PositionViewModel : DocumentBase
{
    public string Name { get; set; }
}

DocumentBase is simply derived from Screen.

Thanks for looking at this, and let me know in the comments if you need any more information. Basically Debug.WriteLine() is never called, but MainWindowViewModelPropertyChanged() is. I would like to just handle a property change for a specific property (SelectedItem) in this case.

Will
  • 421
  • 2
  • 8
  • 23
  • Not sure if I totally understand your code, but a sanity check: do any of the classes in your hierarchy actually declare that they implement INotifyPropertyChanged? – adv12 Jun 13 '17 at 20:17
  • Yes, both Conductor (or rather one of its base classes) and Screen implement INotifyPropertyChanged – Will Jun 13 '17 at 20:23
  • Note that `Items.AddRange(new ObservableCollection()` doesn't make sense. I suppose `Items` is a `List`. `AddRange` just adds items into list, it doesn't matter what `IEnumerable` you will pass as an argument. So you can use just `new[] { ... }`. It is shorter. – Maxim Jun 14 '17 at 02:32

1 Answers1

0

The PropertyChanged event is fired after a property of a class was changed. Or in MSDN words:

Notifies clients that a property value has changed. [...] For example, consider a Person object with a property called FirstName.

The SelectedItem property is defined in MainWindowBase and inherited to MainWindowViewModel. This means if the SelectedItem was changed the event fires inside the class the property contains (MainWindowViewModel in your case).

The PositionViewModel is not recognizing if it is selected or not. The PropertyChanged event of it is only called if a property inside itself was changed. Since you are not calling NotifyOfPropertyChange inside the class this is never possible (except DocumentBase is firing the event).

If you need to do specific actions at selection or deselection you can use the setter to call a method. Here is a basic example:

private TDocument selectedItem;
public TDocument SelectedItem
{
    get
    {
        return selectedItem;
    }
    set
    {
        selectedItem?.YouAreNotSelected();
        value?.YouAreSelected();
        selectedItem = value;
        NotifyOfPropertyChange(() => SelectedItem);
    }
}
Fruchtzwerg
  • 10,999
  • 12
  • 40
  • 49
  • This helps. What I want to do in the PropertyChanged event handler or in MainWindowViewModelPropertyChanged is assign the SelectedItem (according to its derived type) to a PositionViewModel type property in another viewmodel. – Will Jun 13 '17 at 20:33
  • You could handle that inside the setter by checking the type of `value`. – Fruchtzwerg Jun 13 '17 at 20:42
  • I don't generally like to put that much logic in property setters. Thanks for the explanation though, it makes perfect sense. – Will Jun 13 '17 at 20:54