Wrapper for an object that implements the INotifyPropertyChanged and INotifyCollectionChanged. This class is thread-safe and uses weak events to prevent memory leaks.
            public void ReturnsFalseForNonPropertyChangedItem()
            {
                var model = new object();
                var wrapper = new ChangeNotificationWrapper(model);

                Assert.IsFalse(wrapper.SupportsNotifyPropertyChanged);                
            }
            public void ReturnsTrueForCollectionChangedItem()
            {
                var collection = new ObservableCollection<int>();
                var wrapper = new ChangeNotificationWrapper(collection);

                Assert.IsTrue(wrapper.SupportsNotifyCollectionChanged);
            }
            public void ReturnsTrueForPropertyChangedItem()
            {
                var model = new TestModel();
                var wrapper = new ChangeNotificationWrapper(model);

                Assert.IsTrue(wrapper.SupportsNotifyPropertyChanged);
            }
            public void ReturnsFalseForNonCollectionChangedItem()
            {
                var collection = new List<int>();
                var wrapper = new ChangeNotificationWrapper(collection);

                Assert.IsFalse(wrapper.SupportsNotifyCollectionChanged);
            }
Example #5
0
        /// <summary>
        /// Handles the object events subscription. This means that the old value will be removed from the event subscriptions, and
        /// the new value will be subscribed to.
        /// </summary>
        /// <param name="propertyName">Name of the property.</param>
        /// <param name="propertyValue">The property value.</param>
        private void HandleObjectEventsSubscription(string propertyName, object propertyValue)
        {
            if (DisableEventSubscriptionsOfChildValues)
            {
                return;
            }

            lock (_propertyValuesLock)
            {
                if (_propertyValueChangeNotificationWrappers.ContainsKey(propertyName))
                {
                    var oldWrapper = _propertyValueChangeNotificationWrappers[propertyName];
                    if (oldWrapper != null)
                    {
                        oldWrapper.PropertyChanged               -= OnPropertyObjectPropertyChanged;
                        oldWrapper.CollectionChanged             -= OnPropertyObjectCollectionChanged;
                        oldWrapper.CollectionItemPropertyChanged -= OnPropertyObjectCollectionItemPropertyChanged;
                        oldWrapper.UnsubscribeFromAllEvents();
                    }
                }

                if (!ChangeNotificationWrapper.IsUsefulForObject(propertyValue))
                {
                    _propertyValueChangeNotificationWrappers[propertyName] = null;
                }
                else
                {
                    var wrapper = new ChangeNotificationWrapper(propertyValue);
                    wrapper.PropertyChanged               += OnPropertyObjectPropertyChanged;
                    wrapper.CollectionChanged             += OnPropertyObjectCollectionChanged;
                    wrapper.CollectionItemPropertyChanged += OnPropertyObjectCollectionItemPropertyChanged;
                    _propertyValueChangeNotificationWrappers[propertyName] = wrapper;
                }
            }
        }
Example #6
0
        /// <summary>
        /// Handles the object events subscription. This means that the old value will be removed from the event subscriptions, and
        /// the new value will be subscribed to.
        /// </summary>
        /// <param name="propertyName">Name of the property.</param>
        /// <param name="propertyValue">The property value.</param>
        private void HandleObjectEventsSubscription(string propertyName, object propertyValue)
        {
            if (DisableEventSubscriptionsOfChildValues)
            {
                return;
            }

            lock (_lock)
            {
                ChangeNotificationWrapper oldWrapper;

                if (_propertyValueChangeNotificationWrappers == null)
                {
                    _propertyValueChangeNotificationWrappers = new Dictionary <string, ChangeNotificationWrapper>();
                }

                if (_propertyValueChangeNotificationWrappers.TryGetValue(propertyName, out oldWrapper))
                {
                    oldWrapper.PropertyChanged               -= OnPropertyObjectPropertyChanged;
                    oldWrapper.CollectionChanged             -= OnPropertyObjectCollectionChanged;
                    oldWrapper.CollectionItemPropertyChanged -= OnPropertyObjectCollectionItemPropertyChanged;
                    oldWrapper.UnsubscribeFromAllEvents();
                }

                if (!ChangeNotificationWrapper.IsUsefulForObject(propertyValue))
                {
                    if (oldWrapper != null)
                    {
                        _propertyValueChangeNotificationWrappers.Remove(propertyName);
                    }
                }
                else
                {
                    var wrapper = new ChangeNotificationWrapper(propertyValue);
                    wrapper.PropertyChanged               += OnPropertyObjectPropertyChanged;
                    wrapper.CollectionChanged             += OnPropertyObjectCollectionChanged;
                    wrapper.CollectionItemPropertyChanged += OnPropertyObjectCollectionItemPropertyChanged;
                    _propertyValueChangeNotificationWrappers[propertyName] = wrapper;
                }
            }
        }
            public void HandlesCollectionItemPropertyChangesCorrectly()
            {
                var collection = new ObservableCollection<TestModel>();
                var model = new TestModel();
                collection.Add(model);

                var wrapper = new ChangeNotificationWrapper(collection);

                bool collectionItemPropertyChanged = false;

                wrapper.CollectionItemPropertyChanged += (sender, e) => collectionItemPropertyChanged = true;

                model.FirstName = "Geert";

                Assert.IsTrue(collectionItemPropertyChanged);
            }
            public void HandlesCollectionChangesByResetCorrectly()
            {
                var collection = new FastObservableCollection<TestModel>();
                var wrapper = new ChangeNotificationWrapper(collection);

                var itemsReset = false;
                var itemsAdded = false;
                var itemsRemoved = false;

                var model = new TestModel();
                collection.Add(model);

                wrapper.CollectionChanged += (sender, e) =>
                {
                    if (e.OldItems != null)
                    {
                        itemsRemoved = true;
                    }

                    if (e.Action == NotifyCollectionChangedAction.Reset)
                    {
                        itemsReset = true;
                    }

                    if (e.NewItems != null)
                    {
                        itemsAdded = true;
                    }
                };

                using (collection.SuspendChangeNotifications())
                {
                    collection.ReplaceRange(new [] { new TestModel() });
                }

                Assert.IsFalse(itemsAdded);
                Assert.IsFalse(itemsRemoved);
                Assert.IsTrue(itemsReset);
            }
Example #9
0
        /// <summary>
        /// Handles the object events subscription. This means that the old value will be removed from the event subscriptions, and
        /// the new value will be subscribed to.
        /// </summary>
        /// <param name="propertyName">Name of the property.</param>
        /// <param name="propertyValue">The property value.</param>
        private void HandleObjectEventsSubscription(string propertyName, object propertyValue)
        {
            if (DisableEventSubscriptionsOfChildValues)
            {
                return;
            }

            lock (_propertyValuesLock)
            {
                if (_propertyValueChangeNotificationWrappers.ContainsKey(propertyName))
                {
                    var oldWrapper = _propertyValueChangeNotificationWrappers[propertyName];
                    if (oldWrapper != null)
                    {
                        oldWrapper.PropertyChanged -= OnPropertyObjectPropertyChanged;
                        oldWrapper.CollectionChanged -= OnPropertyObjectCollectionChanged;
                        oldWrapper.CollectionItemPropertyChanged -= OnPropertyObjectCollectionItemPropertyChanged;
                        oldWrapper.UnsubscribeFromAllEvents();
                    }
                }

                if (!ChangeNotificationWrapper.IsUsefulForObject(propertyValue))
                {
                    _propertyValueChangeNotificationWrappers[propertyName] = null;
                }
                else
                {
                    var wrapper = new ChangeNotificationWrapper(propertyValue);
                    wrapper.PropertyChanged += OnPropertyObjectPropertyChanged;
                    wrapper.CollectionChanged += OnPropertyObjectCollectionChanged;
                    wrapper.CollectionItemPropertyChanged += OnPropertyObjectCollectionItemPropertyChanged;
                    _propertyValueChangeNotificationWrappers[propertyName] = wrapper;
                }
            }
        }
            public void UnsubscribesFromCollectionChangedEvents()
            {
                var collection = new ObservableCollection<TestModel>();
                var wrapper = new ChangeNotificationWrapper(collection);

                wrapper.UnsubscribeFromAllEvents();

                bool eventRaised = false;
                wrapper.CollectionChanged += (sender, e) => eventRaised = true;

                collection.Add(new TestModel());

                Assert.IsFalse(eventRaised);
            }
            public void UnsubscribesFromPropertyChangedEvents()
            {
                var testModel = new TestModel();

                var wrapper = new ChangeNotificationWrapper(testModel);

                wrapper.UnsubscribeFromAllEvents();

                bool eventRaised = false;
                wrapper.PropertyChanged += (sender, e) => eventRaised = true;

                testModel.FirstName = "Geert";

                Assert.IsFalse(eventRaised);
            }
            public void DoesNotLeakForPropertyChanged()
            {
                var model = new TestModel();
                var wrapper = new ChangeNotificationWrapper(model);

                Assert.IsTrue(wrapper.IsObjectAlive);

                model = null;
                GC.Collect();

                Assert.IsFalse(wrapper.IsObjectAlive);
            }
            public void DoesNotLeakForCollectionChanged()
            {
                var model = new TestModel();
                var collectionModel = new ObservableCollection<TestModel>(new[] {model});
                var wrapper = new ChangeNotificationWrapper(collectionModel);

                Assert.IsTrue(wrapper.IsObjectAlive);

                collectionModel = null;
                GC.Collect();

                Assert.IsFalse(wrapper.IsObjectAlive);
            }
            public void HandlesCollectionResetsCorrectly()
            {
                var collection = new ObservableCollection<TestModel>();
                TestModel model = null;

                for (int i = 0; i < 10; i++)
                {
                    var randomModel = new TestModel();
                    collection.Add(randomModel);
                }

                model = collection[0];

                var wrapper = new ChangeNotificationWrapper(collection);

                bool collectionItemPropertyChanged = false;

                wrapper.CollectionItemPropertyChanged += (sender, e) => collectionItemPropertyChanged = true;

                collection.Clear();
                
                model.FirstName = "Geert";

                Assert.IsFalse(collectionItemPropertyChanged);
            }
            public void HandlesChangesOfSuspendedFastObservableCollectionCorrectly()
            {
                var collection = new FastObservableCollection<TestModel>();
                TestModel model = null;

                for (int i = 0; i < 10; i++)
                {
                    var randomModel = new TestModel();
                    collection.Add(randomModel);
                }

                var wrapper = new ChangeNotificationWrapper(collection);

                var collectionItemPropertyChanged = false;
                wrapper.CollectionItemPropertyChanged += (sender, e) => collectionItemPropertyChanged = true;

                var newModel = new TestModel();

                using (collection.SuspendChangeNotifications())
                {
                    collection.Clear();
                    collection.Add(newModel);
                }

                newModel.FirstName = "Geert";

                Assert.IsTrue(collectionItemPropertyChanged);
            }
            public void HandlesCollectionChangesCorrectly()
            {
                var collection = new ObservableCollection<TestModel>();
                var wrapper = new ChangeNotificationWrapper(collection);

                bool itemsAdded = false;
                bool itemsRemoved = false;

                wrapper.CollectionChanged += (sender, e) =>
                {
                    if (e.OldItems != null)
                    {
                        itemsRemoved = true;
                    }

                    if (e.NewItems != null)
                    {
                        itemsAdded = true;
                    }
                };

                var model = new TestModel();
                collection.Add(model);
                Assert.IsTrue(itemsAdded);
                Assert.IsFalse(itemsRemoved);

                collection.Remove(model);
                Assert.IsTrue(itemsRemoved);
            }
            public void HandlesPropertyChangesCorrectly()
            {
                var model = new TestModel();
                var wrapper = new ChangeNotificationWrapper(model);

                bool propertyChanged = false;

                wrapper.PropertyChanged += (sender, e) => propertyChanged = true;

                model.FirstName = "Geert";

                Assert.IsTrue(propertyChanged);
            }
            public void UnsubscribesFromCollectionItemPropertyChangedEvents()
            {
                var testModel = new TestModel();
                var collection = new ObservableCollection<TestModel>(new[] { testModel });

                var wrapper = new ChangeNotificationWrapper(collection);

                wrapper.UnsubscribeFromAllEvents();

                bool eventRaised = false;
                wrapper.CollectionItemPropertyChanged += (sender, e) => eventRaised = true;

                testModel.FirstName = "Geert";

                Assert.IsFalse(eventRaised);
            }