internal async Task BeginGetGraphDataAsync(IGraphContext context) { try { await InitializeAsync().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(); } }
internal async Task BeginGetGraphDataAsync(IGraphContext context) { try { await InitializeAsync(); IEnumerable <Lazy <IDependenciesGraphActionHandler, IOrderPrecedenceMetadataView> > actionHandlers = GraphActionHandlers.Where(x => x.Value.CanHandleRequest(context)); bool shouldTrackChanges = actionHandlers.Aggregate( false, (previousTrackFlag, handler) => previousTrackFlag || handler.Value.HandleRequest(context)); if (!shouldTrackChanges) { return; } lock (_expandedGraphContextsLock) { if (!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(); } }
/// <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); } } } }
/// <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); } } } }