protected override async Task InitializeCoreAsync(CancellationToken cancellationToken) { _contextAccessor = await _workspaceProjectContextProvider.CreateProjectContextAsync(_project); if (_contextAccessor == null) { return; } _activeWorkspaceProjectContextTracker.RegisterContext(_contextAccessor.ContextId); _disposables = new DisposableBag(CancellationToken.None); _applyChangesToWorkspaceContext = _applyChangesToWorkspaceContextFactory.CreateExport(); _applyChangesToWorkspaceContext.Value.Initialize(_contextAccessor.Context); _disposables.AddDisposable(_applyChangesToWorkspaceContext); _evaluationProgressRegistration = _dataProgressTrackerService.RegisterForIntelliSense(_project, nameof(WorkspaceProjectContextHostInstance) + ".Evaluation"); _disposables.AddDisposable(_evaluationProgressRegistration); _projectBuildProgressRegistration = _dataProgressTrackerService.RegisterForIntelliSense(_project, nameof(WorkspaceProjectContextHostInstance) + ".ProjectBuild"); _disposables.AddDisposable(_projectBuildProgressRegistration); // We avoid suppressing version updates, so that progress tracker doesn't // think we're still "in progress" in the case of an empty change _disposables.AddDisposable(_projectSubscriptionService.ProjectRuleSource.SourceBlock.LinkToAsyncAction( target: e => OnProjectChangedAsync(e, evaluation: true), suppressVersionOnlyUpdates: false, ruleNames: _applyChangesToWorkspaceContext.Value.GetProjectEvaluationRules())); _disposables.AddDisposable(_projectSubscriptionService.ProjectBuildRuleSource.SourceBlock.LinkToAsyncAction( target: e => OnProjectChangedAsync(e, evaluation: false), suppressVersionOnlyUpdates: false, ruleNames: _applyChangesToWorkspaceContext.Value.GetProjectBuildRules())); }
internal Task OnProjectChangedAsync <T>( IDataProgressTrackerServiceRegistration registration, ConfiguredProject activeConfiguredProject, IProjectVersionedValue <T> update, Func <IProjectVersionedValue <T>, bool> hasChange, Action <IProjectVersionedValue <T>, IApplyChangesToWorkspaceContext, ContextState, CancellationToken> applyFunc) { return(ExecuteUnderLockAsync(ApplyProjectChangesUnderLockAsync, _tasksService.UnloadCancellationToken)); Task ApplyProjectChangesUnderLockAsync(CancellationToken cancellationToken) { // NOTE we cannot call CheckForInitialized here, as this method may be invoked during initialization Assumes.NotNull(_contextAccessor); Assumes.NotNull(_applyChangesToWorkspaceContext); if (!hasChange(update)) { // No change since the last update. We must still update operation progress, but can skip creating a batch. UpdateProgressRegistration(); return(Task.CompletedTask); } return(ApplyInBatchAsync()); async Task ApplyInBatchAsync() { ContextState contextState = new( isActiveEditorContext : _activeWorkspaceProjectContextTracker.IsActiveEditorContext(_contextAccessor.ContextId), isActiveConfiguration : activeConfiguredProject == _project); IWorkspaceProjectContext context = _contextAccessor.Context; context.StartBatch(); try { applyFunc(update, _applyChangesToWorkspaceContext.Value, contextState, cancellationToken); } finally { await context.EndBatchAsync(); UpdateProgressRegistration(); } } void UpdateProgressRegistration() { // Notify operation progress that we've now processed these versions of our input, if they are // up-to-date with the latest version that produced, then we no longer considered "in progress". registration.NotifyOutputDataCalculated(update.DataSourceVersions); } } }