locked
Object Graph with multipe ObservableCollections and easy way to listen to property change events. RRS feed

  • Question

  • I am having analysis paralysis.  I think there much be a simpler way to do something.  Hoping someone can recommend an approach.

    I pasted the key parts of the code below.  Basically, I have a "ProjectPortfolio" class that contains 2 lists of Projects: ObservableCollection<Project> lists.  What I want to implement is, whenever a certain property of instance of a"Project" changes, i want to remove that project from its current list and then add to the other list.

    I want ProjectPortfolio to listen to any property change to any projects in its 2 lists.  I cannot override the Add method of the ObservableCollection which is where my brain wants to take the code..so i can subscribe to the "Project" property change event.

    My gut says I am overlooking something very easy.  Any advice?

    Thanks,

    Dan

        public class ProjectPortfolio : INotifyPropertyChanged
        {
            private Metrics _metrics;
            private Projects _inProjects;
            private Projects _outProjects;
            
            public ProjectPortfolio()
            {
                _metrics = new Metrics();
                _inProjects = new Projects();
                _outProjects = new Projects();
      
        public class Projects: ObservableCollection
        {
    
        }
      
        public class Project : INotifyPropertyChanged
        {
            #region Fields/Properties
    
            private DateTime _startDate;
            public DateTime StartDate
            {
                get
                {
                    return _startDate;
                }
                set
                {
                    if (_startDate != value)
                    {
                        _startDate = value;
                        OnPropertyChanged("StartDate");
                    }
                }
            }
     
    Saturday, December 13, 2008 9:59 PM

Answers

  • Ultimately, the real issue for me was for some reason, my intellisense was not working on the ObservableCollection.  It was only showing IEnumerable extenstion methods, therefore, i did not see the events.  I know its weird, but once I added the namespace using System.Collections.ObjectModel;, intellisense starting working.  I cannot reproduce now.  Oh well, i learned alot on the detour. 

    Here is what i ended up doing based upon replies in this thread:

    In the constuctor:

     

                _inProjects = new Projects();
                _outProjects = new Projects();
                _outProjects.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(projects_CollectionChanged);
                _inProjects.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(projects_CollectionChanged);
    
      

     

            protected internal void OnProjectPortfolioChanged(ProjectPortfolioEventArgs e)
            {
                // Make a temporary copy of the event to avoid possibility of
                // a race condition if the last subscriber unsubscribes
                // immediately after the null check and before the event is raised.
                EventHandler handler = this.ProjectPortfolioChanged;
                // Event will be null if there are no subscribers
                if (handler != null)
                {
                    // Use the () operator to raise the event.
                    handler(this, e);
                }
            }
            private void projects_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
            {
                switch (e.Action)
                {
                    case System.Collections.Specialized.NotifyCollectionChangedAction.Add:
                        foreach (var item in e.NewItems)
                        {
                            Project project = (Project)item;
                            project.PropertyChanged += new PropertyChangedEventHandler(project_PropertyChanged);
                        }
                        break;
                    case System.Collections.Specialized.NotifyCollectionChangedAction.Remove:
                        foreach (var item in e.OldItems)
                        {
                            Project project = (Project)item;
                            project.PropertyChanged -= new PropertyChangedEventHandler(project_PropertyChanged);
                        }
                        break;
                    case System.Collections.Specialized.NotifyCollectionChangedAction.Replace:
                        break;
                    case System.Collections.Specialized.NotifyCollectionChangedAction.Reset:
                        break;
                    default:
                        break;
                }
            }
     
    Thursday, December 18, 2008 12:11 AM

All replies

  • bump please

    Monday, December 15, 2008 7:47 AM
  •  I may be off the mark here, but can you not do:

    _inProjects = new Projects();

    _inProjects.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(_inProjects_CollectionChanged);

    The event raised then seems to contain a e.NewItems collection of the newly added Project objects.

     I did a quick example, but used the Generic form (ObservableCollection<Project>), don't know if that makes a difference.

    Slicc

    Monday, December 15, 2008 8:33 AM
  • I feel you are doing something like dirty tracking. Instead of maintaining a separate list, you can add a property, let's say: IsModified, to your class. In your RaisePropertyChanged method, set this property to true. So at the time you want to get a list of projects that have been modified, just do the following:

    var modifiedList = projectCollection.Where(p => p.IsModified).ToList();

    I felt this is much easier way to do dirty tracking than event-listener pattern.

    Monday, December 15, 2008 10:05 AM
  • Ultimately, the real issue for me was for some reason, my intellisense was not working on the ObservableCollection.  It was only showing IEnumerable extenstion methods, therefore, i did not see the events.  I know its weird, but once I added the namespace using System.Collections.ObjectModel;, intellisense starting working.  I cannot reproduce now.  Oh well, i learned alot on the detour. 

    Here is what i ended up doing based upon replies in this thread:

    In the constuctor:

     

                _inProjects = new Projects();
                _outProjects = new Projects();
                _outProjects.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(projects_CollectionChanged);
                _inProjects.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(projects_CollectionChanged);
    
      

     

            protected internal void OnProjectPortfolioChanged(ProjectPortfolioEventArgs e)
            {
                // Make a temporary copy of the event to avoid possibility of
                // a race condition if the last subscriber unsubscribes
                // immediately after the null check and before the event is raised.
                EventHandler handler = this.ProjectPortfolioChanged;
                // Event will be null if there are no subscribers
                if (handler != null)
                {
                    // Use the () operator to raise the event.
                    handler(this, e);
                }
            }
            private void projects_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
            {
                switch (e.Action)
                {
                    case System.Collections.Specialized.NotifyCollectionChangedAction.Add:
                        foreach (var item in e.NewItems)
                        {
                            Project project = (Project)item;
                            project.PropertyChanged += new PropertyChangedEventHandler(project_PropertyChanged);
                        }
                        break;
                    case System.Collections.Specialized.NotifyCollectionChangedAction.Remove:
                        foreach (var item in e.OldItems)
                        {
                            Project project = (Project)item;
                            project.PropertyChanged -= new PropertyChangedEventHandler(project_PropertyChanged);
                        }
                        break;
                    case System.Collections.Specialized.NotifyCollectionChangedAction.Replace:
                        break;
                    case System.Collections.Specialized.NotifyCollectionChangedAction.Reset:
                        break;
                    default:
                        break;
                }
            }
     
    Thursday, December 18, 2008 12:11 AM