private IProjectItemTree CreateProjectItemTreeNode(IProjectTree providerRootTreeNode,
                                                           IDependencyNode nodeInfo,
                                                           IProjectCatalogSnapshot catalogs)
        {
            var isGenericNodeType = nodeInfo.Flags.Contains(DependencyNode.GenericDependencyFlags);
            var properties        = nodeInfo.Properties ??
                                    ImmutableDictionary <string, string> .Empty
                                    .Add(Folder.IdentityProperty, nodeInfo.Caption)
                                    .Add(Folder.FullPathProperty, string.Empty);

            // For generic node types we do set correct, known item types, however for custom nodes
            // provided by third party extensions we can not guarantee that item type will be known.
            // Thus always set predefined itemType for all custom nodes.
            // TODO: generate specific xaml rule for generic Dependency nodes
            // tracking issue: https://github.com/dotnet/roslyn-project-system/issues/1102
            var itemType = isGenericNodeType ? nodeInfo.Id.ItemType : Folder.SchemaName;

            // when itemSpec is not in valid absolute path format, property page does not show
            // item name correctly. Use real Name for the node here instead of caption, since caption
            // can have other info like version in it.
            var itemSpec = nodeInfo.Flags.Contains(DependencyNode.CustomItemSpec)
                    ? DependencyNode.GetName(nodeInfo)
                    : nodeInfo.Id.ItemSpec;
            var itemContext = ProjectPropertiesContext.GetContext(UnconfiguredProject, itemType, itemSpec);
            var configuredProjectExports = GetActiveConfiguredProjectExports(ActiveConfiguredProject);

            IRule rule = null;

            if (nodeInfo.Resolved || !isGenericNodeType)
            {
                rule = GetRuleForResolvableReference(
                    itemContext,
                    new KeyValuePair <string, IImmutableDictionary <string, string> >(
                        itemSpec, properties),
                    catalogs,
                    configuredProjectExports,
                    isGenericNodeType);
            }
            else
            {
                rule = GetRuleForUnresolvableReference(
                    itemContext,
                    catalogs,
                    configuredProjectExports);
            }

            // Notify about tree changes to customization context
            var customTreePropertyContext = GetCustomPropertyContext(providerRootTreeNode);
            var customTreePropertyValues  = new ReferencesProjectTreeCustomizablePropertyValues
            {
                Caption = nodeInfo.Caption,
                Flags   = nodeInfo.Flags,
                Icon    = nodeInfo.Icon.ToProjectSystemType()
            };

            ApplyProjectTreePropertiesCustomization(customTreePropertyContext, customTreePropertyValues);

            var treeItemNode = NewTree(caption: nodeInfo.Caption,
                                       item: itemContext,
                                       propertySheet: null,
                                       visible: true,
                                       browseObjectProperties: rule,
                                       flags: nodeInfo.Flags,
                                       icon: nodeInfo.Icon.ToProjectSystemType(),
                                       expandedIcon: nodeInfo.ExpandedIcon.ToProjectSystemType());

            return(treeItemNode);
        }
        /// <summary>
        /// Tries to apply changes to corresponding node in given GraphContext for given changes
        /// </summary>
        private async Task TrackChangesOnGraphContextAsync(IGraphContext graphContext,
                                                           ProjectContextEventArgs changes)
        {
            var updatedProjectContext = changes.Context;

            foreach (var inputGraphNode in graphContext.InputNodes.ToList())
            {
                var existingNodeInfo = inputGraphNode.GetValue <IDependencyNode>(
                    DependenciesGraphSchema.DependencyNodeProperty);
                if (existingNodeInfo == null)
                {
                    continue;
                }

                var projectPath = GetPartialValueFromGraphNodeId(inputGraphNode.Id, CodeGraphNodeIdName.Assembly);
                if (string.IsNullOrEmpty(projectPath))
                {
                    continue;
                }

                if (!ShouldTrackChangesForNode(existingNodeInfo, projectPath, updatedProjectContext.ProjectFilePath))
                {
                    continue;
                }

                var subTreeProvider = await GetSubTreeProviderAsync(graphContext,
                                                                    inputGraphNode,
                                                                    projectPath,
                                                                    existingNodeInfo.Id).ConfigureAwait(false);

                if (subTreeProvider == null)
                {
                    continue;
                }

                var updatedNode = subTreeProvider.GetDependencyNode(existingNodeInfo.Id);
                if (updatedNode == null)
                {
                    continue;
                }

                var  newNode    = DependencyNode.Clone(existingNodeInfo);
                bool anyChanges = AnyChangesToTrack(newNode,
                                                    updatedNode,
                                                    changes.Diff,
                                                    out IEnumerable <IDependencyNode> nodesToAdd,
                                                    out IEnumerable <IDependencyNode> nodesToRemove);
                if (!anyChanges)
                {
                    continue;
                }

                // register providers for new nodes outside of scope using (it can not have await there)
                await RegisterProviders(graphContext, projectPath, nodesToAdd).ConfigureAwait(false);

                using (var scope = new GraphTransactionScope())
                {
                    foreach (var nodeToRemove in nodesToRemove)
                    {
                        RemoveGraphNode(graphContext, projectPath, nodeToRemove, inputGraphNode);
                        newNode.RemoveChild(nodeToRemove);
                    }

                    foreach (var nodeToAdd in nodesToAdd)
                    {
                        AddGraphNode(graphContext, projectPath, null, inputGraphNode, nodeToAdd);
                        newNode.AddChild(nodeToAdd);
                    }

                    // Update the node info saved on the 'inputNode'
                    inputGraphNode.SetValue(DependenciesGraphSchema.DependencyNodeProperty, newNode);

                    scope.Complete();
                }
            }
        }