internal async Task BeginGetGraphDataAsync(IGraphContext context)
        {
            try
            {
                await EnsureInitializedAsync().ConfigureAwait(false);

                var actionHandlers     = GraphActionHandlers.Where(x => x.Value.CanHandleRequest(context));
                var shouldTrackChanges = actionHandlers.Aggregate(
                    false, (previousTrackFlag, handler) => previousTrackFlag || handler.Value.HandleRequest(context));

                lock (_ExpandedGraphContextsLock)
                {
                    if (shouldTrackChanges && !ExpandedGraphContexts.Contains(context))
                    {
                        // Remember this graph context in order to track changes.
                        // When references change, we will adjust children of this graph as necessary
                        ExpandedGraphContexts.Add(context);
                    }
                }
            }
            finally
            {
                // OnCompleted must be called to display changes
                context.OnCompleted();
            }
        }
Exemple #2
0
 /// <summary>
 /// Property ExpandedGraphContexts remembers graph expanded so far.
 /// Each context represents one level in the graph, i.e. a node and its first level dependencies
 /// Tracking changes over all expanded contexts ensures that all levels are processed
 /// and updated when there are any changes in nodes data.
 /// </summary>
 internal async Task TrackChangesAsync(IDependenciesGraphProjectContext updatedProjectContext)
 {
     foreach (var graphContext in ExpandedGraphContexts.ToList())
     {
         try
         {
             await TrackChangesOnGraphContextAsync(graphContext, updatedProjectContext).ConfigureAwait(false);
         }
         finally
         {
             // Calling OnCompleted ensures that the changes are reflected in UI
             graphContext.OnCompleted();
         }
     }
 }
        /// <summary>
        /// Property ExpandedGraphContexts remembers graph expanded or checked so far.
        /// Each context represents one level in the graph, i.e. a node and its first level dependencies
        /// Tracking changes over all expanded contexts ensures that all levels are processed
        /// and updated when there are any changes in nodes data.
        /// </summary>
        private void TrackChanges(SnapshotChangedEventArgs updatedProjectContext)
        {
            IList <IGraphContext> expandedContexts;

            lock (_expandedGraphContextsLock)
            {
                expandedContexts = ExpandedGraphContexts.ToList();
            }

            if (expandedContexts.Count == 0)
            {
                return;
            }

            var actionHandlers = GraphActionHandlers.Select(x => x.Value).Where(x => x.CanHandleChanges()).ToList();

            if (actionHandlers.Count == 0)
            {
                return;
            }

            foreach (IGraphContext graphContext in expandedContexts)
            {
                try
                {
                    foreach (IDependenciesGraphActionHandler actionHandler in actionHandlers)
                    {
                        actionHandler.HandleChanges(graphContext, updatedProjectContext);
                    }
                }
                finally
                {
                    // Calling OnCompleted ensures that the changes are reflected in UI
                    graphContext.OnCompleted();
                }
            }
        }
Exemple #4
0
        /// <summary>
        /// Property ExpandedGraphContexts remembers graph expanded or checked so far.
        /// Each context represents one level in the graph, i.e. a node and its first level dependencies
        /// Tracking changes over all expanded contexts ensures that all levels are processed
        /// and updated when there are any changes in nodes data.
        /// </summary>
        internal Task TrackChangesAsync(SnapshotChangedEventArgs updatedProjectContext)
        {
            IList <IGraphContext> expandedContexts;

            lock (_expandedGraphContextsLock)
            {
                expandedContexts = ExpandedGraphContexts.ToList();
            }

            if (expandedContexts.Count == 0)
            {
                return(Task.CompletedTask);
            }

            var actionHandlers = GraphActionHandlers.Where(x => x.Value.CanHandleChanges());

            if (!actionHandlers.Any())
            {
                return(Task.CompletedTask);
            }

            foreach (var graphContext in expandedContexts.ToList())
            {
                try
                {
                    actionHandlers.ForEach(x => x.Value.HandleChanges(graphContext, updatedProjectContext));
                }
                finally
                {
                    // Calling OnCompleted ensures that the changes are reflected in UI
                    graphContext.OnCompleted();
                }
            }

            return(Task.CompletedTask);
        }
Exemple #5
0
        /// <summary>
        /// Fills node with children when it is opened in Solution Explorer
        /// </summary>
        private async Task GetChildrenAsync(IGraphContext graphContext)
        {
            var trackChanges = false;

            foreach (var inputGraphNode in graphContext.InputNodes)
            {
                if (graphContext.CancelToken.IsCancellationRequested)
                {
                    return;
                }

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

                var(node, subTreeProvider) = await GetDependencyNodeInfoAsync(graphContext, inputGraphNode, projectPath)
                                             .ConfigureAwait(false);

                if (node == null || subTreeProvider == null)
                {
                    continue;
                }

                if (!node.Flags.Contains(DependencyNode.PreFilledFolderNode))
                {
                    // Refresh reference, projectContext may have been changed since the last time CheckChildren was called
                    node = subTreeProvider.GetDependencyNode(node.Id);
                    if (node == null)
                    {
                        continue;
                    }
                }

                var nodeChildren = node.Children.ToArray();

                if (!string.IsNullOrEmpty(node.Id.ContextProject))
                {
                    projectPath = node.Id.ContextProject;
                }

                // get specific providers for child nodes outside of GraphTransactionScope since it does not support
                // await and switch to other thread (exception "scope must be completed by the same thread it is created".
                var childrenSubTreeProviders = new List <IProjectDependenciesSubTreeProvider>();
                foreach (var childNodeToAdd in nodeChildren)
                {
                    var childSubTreeProvider = await GetSubTreeProviderAsync(graphContext,
                                                                             null /* inputGraphNode */,
                                                                             projectPath,
                                                                             childNodeToAdd.Id).ConfigureAwait(false);

                    childrenSubTreeProviders.Add(childSubTreeProvider);
                }

                using (var scope = new GraphTransactionScope())
                {
                    for (int i = 0; i < nodeChildren.Length; ++i)
                    {
                        var childNodeToAdd       = nodeChildren[i];
                        var childSubTreeProvider = childrenSubTreeProviders?[i] ?? subTreeProvider;

                        // start tracking changes if needed
                        if (graphContext.TrackChanges)
                        {
                            trackChanges = true;
                        }

                        inputGraphNode.SetValue(DependenciesGraphSchema.DependencyNodeProperty, node);
                        var newGraphNode = AddGraphNode(graphContext, projectPath,
                                                        childSubTreeProvider, inputGraphNode, childNodeToAdd);

                        if (childNodeToAdd.Flags.Contains(DependencyNode.PreFilledFolderNode))
                        {
                            newGraphNode.SetValue(DgmlNodeProperties.ContainsChildren, true);
                        }
                    }

                    scope.Complete();
                }

                lock (_ExpandedGraphContextsLock)
                {
                    if (trackChanges && !ExpandedGraphContexts.Contains(graphContext))
                    {
                        // Remember this graph context in order to track changes.
                        // When references change, we will adjust children of this graph as necessary
                        ExpandedGraphContexts.Add(graphContext);
                    }
                }
            }
        }
Exemple #6
0
        /// <summary>
        /// Fills node with children when it is opened in Solution Explorer
        /// </summary>
        private async Task GetChildrenAsync(IGraphContext graphContext)
        {
            var trackChanges = false;

            foreach (var inputGraphNode in graphContext.InputNodes)
            {
                if (graphContext.CancelToken.IsCancellationRequested)
                {
                    return;
                }

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

                var nodeInfo = inputGraphNode.GetValue <IDependencyNode>(
                    DependenciesGraphSchema.DependencyNodeProperty);
                if (nodeInfo == null)
                {
                    continue;
                }

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

                if (subTreeProvider == null)
                {
                    continue;
                }

                if (!nodeInfo.Flags.Contains(DependencyNode.PreFilledFolderNode))
                {
                    // Refresh reference, projectContext may have been changed since the last time CheckChildren was called
                    nodeInfo = subTreeProvider.GetDependencyNode(nodeInfo.Id);
                    if (nodeInfo == null)
                    {
                        continue;
                    }
                }

                using (var scope = new GraphTransactionScope())
                {
                    var nodeChildren = nodeInfo.Children;
                    foreach (var childNodeToAdd in nodeChildren)
                    {
                        // start tracking changes if needed
                        if (graphContext.TrackChanges)
                        {
                            trackChanges = true;
                        }

                        inputGraphNode.SetValue(DependenciesGraphSchema.DependencyNodeProperty, nodeInfo);

                        var newGraphNode = AddGraphNode(graphContext, projectPath,
                                                        subTreeProvider, inputGraphNode, childNodeToAdd);

                        if (childNodeToAdd.Flags.Contains(DependencyNode.PreFilledFolderNode))
                        {
                            newGraphNode.SetValue(DgmlNodeProperties.ContainsChildren, true);
                        }
                    }

                    scope.Complete();
                }

                lock (_ExpandedGraphContextsLock)
                {
                    if (trackChanges && !ExpandedGraphContexts.Contains(graphContext))
                    {
                        // Remember this graph context in order to track changes.
                        // When references change, we will adjust children of this graph as necessary
                        ExpandedGraphContexts.Add(graphContext);
                    }
                }
            }
        }
        /// <summary>
        /// Checks if given node has children and adds corresponding IDependencyDescription to the node.
        /// </summary>
        private async Task CheckChildrenAsync(IGraphContext graphContext)
        {
            foreach (var inputGraphNode in graphContext.InputNodes)
            {
                if (graphContext.CancelToken.IsCancellationRequested)
                {
                    return;
                }

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

                var(node, subTreeProvider) = await GetDependencyNodeInfoAsync(graphContext, inputGraphNode, projectPath)
                                             .ConfigureAwait(false);

                if (node == null || subTreeProvider == null)
                {
                    continue;
                }

                // refresh node
                node = subTreeProvider.GetDependencyNode(node.Id);
                if (node == null)
                {
                    continue;
                }

                var trackChanges = false;
                using (var scope = new GraphTransactionScope())
                {
                    if (node.Flags.Contains(DependencyNode.DependsOnOtherProviders) ||
                        subTreeProvider.ProviderType.Equals(SdkDependenciesSubTreeProvider.ProviderTypeString, StringComparison.OrdinalIgnoreCase))
                    {
                        trackChanges = true;
                    }

                    inputGraphNode.SetValue(DependenciesGraphSchema.ProviderProperty, subTreeProvider);
                    inputGraphNode.SetValue(DependenciesGraphSchema.DependencyNodeProperty, node);

                    if (node.HasChildren)
                    {
                        inputGraphNode.SetValue(DgmlNodeProperties.ContainsChildren, true);
                    }

                    scope.Complete();
                }

                lock (_ExpandedGraphContextsLock)
                {
                    if (trackChanges && !ExpandedGraphContexts.Contains(graphContext))
                    {
                        // Remember this graph context in order to track changes.
                        // When references change, we will adjust children of this graph as necessary
                        ExpandedGraphContexts.Add(graphContext);
                    }
                }
            }
        }