user3911053
user3911053

Reputation:

Singleton OnPropertyChanged Not Firing

I have a class called DataModel where I am storing an ObservableCollection of projects. I was using a static ObservableCollection, but since I want to bind to it, and OnPropertyChanged doesn't seem to work correctly for static properties, I created it as a singleton:

public sealed class DataModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    private static readonly DataModel instance = new DataModel();
    private DataModel() { }

    public static DataModel Instance
    {
        get
        {
            return instance;
        }
    }

    #region Projects
    private ObservableCollection<Project> projects = new ObservableCollection<Project>();
    public ObservableCollection<Project> Projects
    {
        get
        {
            return projects;
        }
        set
        {
            if (projects == value)
            {
                return;
            }

            projects = value;
            OnPropertyChanged("Projects");
        }
    }
    #endregion Projects

    public void OnPropertyChanged(string name)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
    }
}

Then when I click a button,

Project newProject = new Project() { Title = "Test" };
DataModel.Instance.Projects.Add(newProject);

From what I could come up with from various sources, this ought to work correctly. However, the OnPropertyChanged event is never called. If I do

DataModel.Instance.Projects = new ObservableCollection<Project>();

it is called. But adding a Project to the collection won't call it.

Upvotes: 1

Views: 214

Answers (2)

BoltClock
BoltClock

Reputation: 723719

OnPropertyChanged is only automatically fired when that property is reassigned. That is why reassigning your entire collection causes it to be fired. Modifying the collection fires the collection's own CollectionChanged event instead, since you're not actually changing the Projects reference, just mutating the same collection it's referring to.

If your collection is bound to a control's ItemsSource property correctly, e.g.

<ListView ItemsSource="{Binding Projects}"/>

where the data context is your DataModel instance, you should not need to do anything beyond adding the new item.

If you need to do something when the collection is changed, subscribe to its CollectionChanged event instead:

private DataModel()
{
    Projects.CollectionChanged += Projects_CollectionChanged;
}

private void Projects_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
    if (e.Action == NotifyCollectionChangedAction.Add)
    {
        // An item was added...
    }
}

Upvotes: 2

Nikhil Vartak
Nikhil Vartak

Reputation: 5117

I expect it NOT to work. Because you are adding item to Observation collection in which case there is no reason setter would be called and thus OnPropertyChanged. That's why it works when you initialize DataModel.Instance.Projects from calling code. You could call property changed explicitly as below:

Project newProject = new Project() { Title = "Test" };
DataModel.Instance.Projects.Add(newProject);
DataModel.Instance.OnPropertyChanged("Projects");

Disclaimer: Although this is possible, you really need not do this. That is why they have provided us with ObservableCollection. Any item/s added or removed to/from such collection are automatically notified to the View. If this was not true, why would anybody use ObservableCollection instead of simple List for data bindings.

Upvotes: 0

Related Questions