/// <summary>
        /// Creates the or update array map.
        /// </summary>
        protected virtual void CreateOrUpdateArrayMap(object viewModel, PropertyInfo parentProperty, ref ViewModelMapNode map)
        {
            if (map == null)
            {
                map = new ViewModelMapArrayNode();
            }
            if (map is ViewModelMapArrayNode)
            {
                var itemValues = ((IEnumerable)viewModel).OfType<object>().ToList();
                var typedMap = (ViewModelMapArrayNode)map;

                // if the collection can be compared and updated by some property key, do it, otherwise replace the collection contents;
                // the synchronization can only occur when there is a key map or when the collection is empty
                var keyName = ResolveCollectionKeyName(parentProperty);
                if (!string.IsNullOrEmpty(keyName) && typedMap.Items.Count == typedMap.KeyMap.Count)
                {
                    SynchronizeCollections(typedMap, itemValues, keyName);
                }
                else
                {
                    // replace collection contents
                    typedMap.Items.Clear();
                    typedMap.Items.AddRange(itemValues.Select(i => CreateMap(i, null)));
                    typedMap.KeyMap.Clear();
                }
            }
            else
            {
                throw new Exception(string.Format("The viewModel is a collection or array but the {0} was expected.", map.GetType()));
            }
        }
        /// <summary>
        /// Synchronizes the collections using specified key property.
        /// </summary>
        private void SynchronizeCollections(ViewModelMapArrayNode targetArray, IEnumerable<object> sourceItems, string keyName)
        {
            var sourceKeyMap = sourceItems.ToDictionary(i => i.GetType().GetProperty(keyName).GetValue(i).ToString());
            var targetKeyMap = targetArray.KeyMap;

            // detect changes
            var newItems = sourceKeyMap.Keys.Except(targetKeyMap.Keys).ToList();
            var updatedItems = targetKeyMap.Keys.Intersect(sourceKeyMap.Keys).ToList();
            var removedItems = targetKeyMap.Keys.Except(sourceKeyMap.Keys).ToList();

            // add items
            foreach (var newItem in newItems)
            {
                var item = CreateMap(sourceKeyMap[newItem], null);
                targetArray.Items.Add(item);
                targetKeyMap[newItem] = item;
            }

            // update items
            foreach (var updatedItem in updatedItems)
            {
                var sourceItem = sourceKeyMap[updatedItem];
                var targetItem = targetKeyMap[updatedItem];
                CreateOrUpdateMap(sourceItem, null, ref targetItem);
            }

            // remove items
            foreach (var removedItem in removedItems)
            {
                var item = targetKeyMap[removedItem];
                targetArray.Items.Remove(item);
                targetKeyMap.Remove(removedItem);
            }
        }