Search code examples
c#wpfmvvmcaliburn.microinotifypropertychanged

PropertyChanged event not firing


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.


Solution

  • 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);
        }
    }