/// <summary>
        /// Unsubscribe from model object changes
        /// </summary>
        /// <param name="model">Model object to unsubscribe from</param>
        private static void UnsubscribeFromModelObject(ModelObject model)
        {
            if (model == null)
            {
                return;
            }

            PropertyChangedEventHandler changeHandler = _propertyChangedHandlers[model];

            if (changeHandler == null)
            {
                // Already unregistered - don't bother to continue
                return;
            }
            model.PropertyChanged -= changeHandler;
            _propertyChangedHandlers.Remove(model);

            bool unregisterPropertyChanging = false;

            foreach (PropertyInfo property in model.GetType().GetProperties())
            {
                object value = property.GetValue(model);
                if (property.PropertyType.IsSubclassOf(typeof(ModelObject)))
                {
                    if (value != null)
                    {
                        UnsubscribeFromModelObject((ModelObject)value);
                    }
                    unregisterPropertyChanging |= (property.SetMethod != null);
                }
                else if (ModelCollection.GetItemType(property.PropertyType, out Type itemType))
                {
                    if (ModelGrowingCollection.TypeMatches(property.PropertyType))
                    {
                        UnsubscribeFromGrowingModelCollection(value);
                    }
                    else
                    {
                        UnsubscribeFromModelCollection(value, property.PropertyType.GetGenericArguments()[0]);
                    }
                }
                else if (property.PropertyType.IsGenericType && typeof(ModelDictionary <>) == property.PropertyType.GetGenericTypeDefinition())
                {
                    UnsubscribeFromModelDictionary(value);
                }
            }

            if (unregisterPropertyChanging)
            {
                // Same here - unregister the event handler only where required
                model.PropertyChanging -= VariableModelObjectChanging;
            }
        }
        /// <summary>
        /// Subscribe to changes of the given model object
        /// </summary>
        /// <param name="model">Object to subscribe to</param>
        /// <param name="path">Collection path</param>
        private static void SubscribeToModelObject(ModelObject model, object[] path)
        {
            if (model == null)
            {
                return;
            }

            bool hasVariableModelObjects = false;

            foreach (PropertyInfo property in model.GetType().GetProperties())
            {
                string propertyName = JsonNamingPolicy.CamelCase.ConvertName(property.Name);
                object value        = property.GetValue(model);
                if (property.PropertyType.IsSubclassOf(typeof(ModelObject)))
                {
                    if (value != null)
                    {
                        SubscribeToModelObject((ModelObject)value, AddToPath(path, propertyName));
                    }
                    hasVariableModelObjects |= (property.SetMethod != null);
                }
                else if (ModelCollection.GetItemType(property.PropertyType, out Type itemType))
                {
                    if (ModelGrowingCollection.TypeMatches(property.PropertyType))
                    {
                        SubscribeToGrowingModelCollection(value, propertyName, path);
                    }
                    else
                    {
                        SubscribeToModelCollection(value, itemType, propertyName, path);
                    }
                }
                else if (property.PropertyType.IsGenericType && typeof(ModelDictionary <>) == property.PropertyType.GetGenericTypeDefinition())
                {
                    SubscribeToModelDictionary(value, AddToPath(path, propertyName));
                }
            }

            PropertyChangedEventHandler changeHandler = PropertyChanged(hasVariableModelObjects, path);

            model.PropertyChanged          += changeHandler;
            _propertyChangedHandlers[model] = changeHandler;

            if (hasVariableModelObjects)
            {
                // This is barely needed so only register it where it is actually required.
                // It makes sure that events are removed again when a ModelObject instance is replaced
                model.PropertyChanging += VariableModelObjectChanging;
            }
        }