/// <summary> /// Creates the loading References folder node. /// </summary> /// <returns>a new "Dependencies" tree node.</returns> private IProjectTree CreateDependenciesFolder(IProjectTree oldNode) { if (oldNode == null) { var values = new ReferencesProjectTreeCustomizablePropertyValues { Caption = VSResources.DependenciesNodeName, Icon = ManagedImageMonikers.ReferenceGroup.ToProjectSystemType(), ExpandedIcon = ManagedImageMonikers.ReferenceGroup.ToProjectSystemType(), Flags = DependencyTreeFlags.DependenciesRootNodeFlags }; ApplyProjectTreePropertiesCustomization(null, values); // Note that all the parameters are specified so we can force this call to an // overload of NewTree available prior to 15.5 versions of CPS. Once a 15.5 build // is publicly available we can move this to an overload with default values for // most of the parameters, and we'll only need to pass the interesting ones. return(NewTree( caption: values.Caption, filePath: null, browseObjectProperties: null, icon: values.Icon, expandedIcon: values.ExpandedIcon, visible: true, flags: values.Flags)); } else { return(oldNode); } }
/// <summary> /// Creates the loading References folder node. /// </summary> /// <returns>a new "Dependencies" tree node.</returns> private IProjectTree CreateDependenciesFolder(IProjectTree oldNode) { if (oldNode == null) { var values = new ReferencesProjectTreeCustomizablePropertyValues { Caption = VSResources.DependenciesNodeName, Icon = KnownMonikers.Reference.ToProjectSystemType(), ExpandedIcon = KnownMonikers.Reference.ToProjectSystemType(), Flags = DependenciesRootNodeFlags }; ApplyProjectTreePropertiesCustomization(null, values); return(NewTree( values.Caption, icon: values.Icon, expandedIcon: values.ExpandedIcon, flags: values.Flags)); } else { return(oldNode); } }
private void ApplyProjectTreePropertiesCustomization( IProjectTreeCustomizablePropertyContext context, ReferencesProjectTreeCustomizablePropertyValues values) { foreach (var provider in ProjectTreePropertiesProviders.ExtensionValues()) { provider.CalculatePropertyValues(context, values); } }
private IProjectTree UpdateTreeNode( IProjectTree node, IDependencyViewModel viewModel, IRule rule) { ProjectTreeCustomizablePropertyContext updatedNodeParentContext = GetCustomPropertyContext(node.Parent); var updatedValues = new ReferencesProjectTreeCustomizablePropertyValues { Caption = viewModel.Caption, Flags = viewModel.Flags, Icon = viewModel.Icon.ToProjectSystemType(), ExpandedIcon = viewModel.ExpandedIcon.ToProjectSystemType() }; ApplyProjectTreePropertiesCustomization(updatedNodeParentContext, updatedValues); return(node.SetProperties( caption: viewModel.Caption, browseObjectProperties: rule, icon: viewModel.Icon.ToProjectSystemType(), expandedIcon: viewModel.ExpandedIcon.ToProjectSystemType())); }
protected override void Initialize() { #pragma warning disable RS0030 // symbol LoadedProject is banned using (UnconfiguredProjectAsynchronousTasksService.LoadedProject()) { base.Initialize(); // this.IsApplicable may take a project lock, so we can't do it inline with this method // which is holding a private lock. It turns out that doing it asynchronously isn't a problem anyway, // so long as we guard against races with the Dispose method. UnconfiguredProjectAsynchronousTasksService.LoadedProjectAsync( async delegate { await TaskScheduler.Default.SwitchTo(alwaysYield: true); UnconfiguredProjectAsynchronousTasksService .UnloadCancellationToken.ThrowIfCancellationRequested(); lock (SyncObject) { Verify.NotDisposed(this); // Issue this token before hooking the SnapshotChanged event to prevent a race // where a snapshot tree is replaced by the initial, empty tree created below. // The handler will cancel this token before submitting its update. CancellationToken initialTreeCancellationToken = _treeUpdateCancellationSeries.CreateNext(); _ = SubmitTreeUpdateAsync( delegate { IProjectTree dependenciesNode = CreateDependenciesFolder(); return(Task.FromResult(new TreeUpdateResult(dependenciesNode))); }, initialTreeCancellationToken); ITargetBlock <SnapshotChangedEventArgs> actionBlock = DataflowBlockSlim.CreateActionBlock <SnapshotChangedEventArgs>( e => OnDependenciesSnapshotChanged(_dependenciesSnapshotProvider, e), "DependenciesProjectTreeProviderSource {1}", skipIntermediateInputData: true); _snapshotEventListener = _dependenciesSnapshotProvider.SnapshotChangedSource.LinkTo(actionBlock, new DataflowLinkOptions() { PropagateCompletion = true }); } }, registerFaultHandler: true); } #pragma warning restore RS0030 // symbol LoadedProject is banned IProjectTree CreateDependenciesFolder() { var values = new ReferencesProjectTreeCustomizablePropertyValues { Caption = Resources.DependenciesNodeName, Icon = ManagedImageMonikers.ReferenceGroup.ToProjectSystemType(), ExpandedIcon = ManagedImageMonikers.ReferenceGroup.ToProjectSystemType(), Flags = DependencyTreeFlags.DependenciesRootNodeFlags }; // Allow property providers to perform customization. // These are ordered from lowest priority to highest, allowing higher priority // providers to override lower priority providers. foreach (IProjectTreePropertiesProvider provider in _projectTreePropertiesProviders.ExtensionValues()) { provider.CalculatePropertyValues(null, values); } // Note that all the parameters are specified so we can force this call to an // overload of NewTree available prior to 15.5 versions of CPS. Once a 15.5 build // is publicly available we can move this to an overload with default values for // most of the parameters, and we'll only need to pass the interesting ones. return(NewTree( caption: values.Caption, filePath: null, browseObjectProperties: null, icon: values.Icon, expandedIcon: values.ExpandedIcon, visible: true, flags: values.Flags)); } }
/// <summary> /// Creates or updates a project tree for a given IProjectDependenciesSubTreeProvider /// </summary> /// <param name="dependenciesNode"></param> /// <param name="subTreeProvider"></param> /// <param name="changes"></param> /// <param name="catalogs">Can be null if sub tree provider does not use design time build</param> /// <param name="cancellationToken"></param> /// <returns>IProjectTree for root Dependencies node</returns> private IProjectTree CreateOrUpdateSubTreeProviderNode(IProjectTree dependenciesNode, IProjectDependenciesSubTreeProvider subTreeProvider, IDependenciesChangeDiff changes, IProjectCatalogSnapshot catalogs, CancellationToken cancellationToken) { Requires.NotNull(dependenciesNode, nameof(dependenciesNode)); Requires.NotNull(subTreeProvider, nameof(subTreeProvider)); Requires.NotNull(subTreeProvider.RootNode, nameof(subTreeProvider.RootNode)); Requires.NotNullOrEmpty(subTreeProvider.RootNode.Caption, nameof(subTreeProvider.RootNode.Caption)); Requires.NotNullOrEmpty(subTreeProvider.ProviderType, nameof(subTreeProvider.ProviderType)); var projectFolder = Path.GetDirectoryName(UnconfiguredProject.FullPath); var providerRootTreeNode = GetSubTreeRootNode(dependenciesNode, subTreeProvider.RootNode.Flags); if (subTreeProvider.RootNode.HasChildren || subTreeProvider.ShouldBeVisibleWhenEmpty) { bool newNode = false; if (providerRootTreeNode == null) { providerRootTreeNode = NewTree( caption: subTreeProvider.RootNode.Caption, visible: true, filePath: subTreeProvider.RootNode.Id.ToString(), browseObjectProperties: null, flags: subTreeProvider.RootNode.Flags, icon: subTreeProvider.RootNode.Icon.ToProjectSystemType(), expandedIcon: subTreeProvider.RootNode.ExpandedIcon.ToProjectSystemType()); newNode = true; } if (changes != null) { foreach (var removedItem in changes.RemovedNodes) { if (cancellationToken.IsCancellationRequested) { return(dependenciesNode); } var treeNode = FindProjectTreeNode(providerRootTreeNode, removedItem, projectFolder); if (treeNode != null) { providerRootTreeNode = treeNode.Remove(); } } foreach (var updatedItem in changes.UpdatedNodes) { if (cancellationToken.IsCancellationRequested) { return(dependenciesNode); } var treeNode = FindProjectTreeNode(providerRootTreeNode, updatedItem, projectFolder); if (treeNode != null) { var updatedNodeParentContext = GetCustomPropertyContext(treeNode.Parent); var updatedValues = new ReferencesProjectTreeCustomizablePropertyValues { Caption = updatedItem.Caption, Flags = updatedItem.Flags, Icon = updatedItem.Icon.ToProjectSystemType(), ExpandedIcon = updatedItem.ExpandedIcon.ToProjectSystemType() }; ApplyProjectTreePropertiesCustomization(updatedNodeParentContext, updatedValues); // update existing tree node properties treeNode = treeNode.SetProperties( caption: updatedItem.Caption, flags: updatedItem.Flags, icon: updatedItem.Icon.ToProjectSystemType(), expandedIcon: updatedItem.ExpandedIcon.ToProjectSystemType()); providerRootTreeNode = treeNode.Parent; } } foreach (var addedItem in changes.AddedNodes) { if (cancellationToken.IsCancellationRequested) { return(dependenciesNode); } var treeNode = FindProjectTreeNode(providerRootTreeNode, addedItem, projectFolder); if (treeNode == null) { treeNode = CreateProjectItemTreeNode(providerRootTreeNode, addedItem, catalogs); providerRootTreeNode = providerRootTreeNode.Add(treeNode).Parent; } } } if (newNode) { dependenciesNode = dependenciesNode.Add(providerRootTreeNode).Parent; } else { dependenciesNode = providerRootTreeNode.Parent; } } else { if (providerRootTreeNode != null) { dependenciesNode = dependenciesNode.Remove(providerRootTreeNode); } } return(dependenciesNode); }
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) ? nodeInfo.Name : 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); }
private IProjectTree CreateOrUpdateNode( IProjectTree?node, IDependencyViewModel viewModel, IRule?browseObjectProperties, bool isProjectItem, ProjectTreeFlags?additionalFlags = null, ProjectTreeFlags?excludedFlags = null) { if (node != null) { return(UpdateTreeNode()); } string?filePath = viewModel.OriginalModel != null && viewModel.OriginalModel.TopLevel && viewModel.OriginalModel.Resolved ? viewModel.OriginalModel.GetTopLevelId() : viewModel.FilePath; ProjectTreeFlags filteredFlags = FilterFlags(viewModel.Flags); return(isProjectItem ? CreateProjectItemTreeNode() : CreateProjectTreeNode()); IProjectTree CreateProjectTreeNode() { // For IProjectTree remove ProjectTreeFlags.Common.Reference flag, otherwise CPS would fail to // map this node to graph node and GraphProvider would be never called. // Only IProjectItemTree can have this flag filteredFlags = filteredFlags.Except(DependencyTreeFlags.BaseReferenceFlags); return(_treeServices.CreateTree( caption: viewModel.Caption, filePath, browseObjectProperties: browseObjectProperties, icon: viewModel.Icon.ToProjectSystemType(), expandedIcon: viewModel.ExpandedIcon.ToProjectSystemType(), visible: true, flags: filteredFlags)); } IProjectTree CreateProjectItemTreeNode() { Assumes.NotNull(filePath); var itemContext = ProjectPropertiesContext.GetContext( _commonServices.Project, file: filePath, itemType: viewModel.SchemaItemType, itemName: filePath); return(_treeServices.CreateTree( caption: viewModel.Caption, itemContext: itemContext, browseObjectProperties: browseObjectProperties, icon: viewModel.Icon.ToProjectSystemType(), expandedIcon: viewModel.ExpandedIcon.ToProjectSystemType(), visible: true, flags: filteredFlags)); } IProjectTree UpdateTreeNode() { var updatedNodeParentContext = new ProjectTreeCustomizablePropertyContext { ExistsOnDisk = false, ParentNodeFlags = node !.Parent?.Flags ?? default }; var updatedValues = new ReferencesProjectTreeCustomizablePropertyValues { Caption = viewModel.Caption, Flags = viewModel.Flags, Icon = viewModel.Icon.ToProjectSystemType(), ExpandedIcon = viewModel.ExpandedIcon.ToProjectSystemType() }; foreach (Lazy <IProjectTreePropertiesProvider, IOrderPrecedenceMetadataView> provider in _projectTreePropertiesProviders) { provider.Value.CalculatePropertyValues(updatedNodeParentContext, updatedValues); } return(node.SetProperties( caption: updatedValues.Caption, browseObjectProperties: browseObjectProperties, icon: updatedValues.Icon, expandedIcon: updatedValues.ExpandedIcon, flags: updatedValues.Flags)); } ProjectTreeFlags FilterFlags(ProjectTreeFlags flags) { if (additionalFlags.HasValue) { flags = flags.Union(additionalFlags.Value); } if (excludedFlags.HasValue) { flags = flags.Except(excludedFlags.Value); } return(flags); } }
/// <summary> /// Generates the original references directory tree. /// </summary> protected override void Initialize() { #pragma warning disable RS0030 // symbol LoadedProject is banned using (UnconfiguredProjectAsynchronousTasksService.LoadedProject()) #pragma warning restore RS0030 { #pragma warning disable RS0030 // https://github.com/dotnet/roslyn-analyzers/issues/3295 base.Initialize(); #pragma warning restore RS0030 // this.IsApplicable may take a project lock, so we can't do it inline with this method // which is holding a private lock. It turns out that doing it asynchronously isn't a problem anyway, // so long as we guard against races with the Dispose method. #pragma warning disable RS0030 // symbol LoadedProjectAsync is banned UnconfiguredProjectAsynchronousTasksService.LoadedProjectAsync( #pragma warning restore RS0030 async delegate { await TaskScheduler.Default.SwitchTo(alwaysYield: true); UnconfiguredProjectAsynchronousTasksService .UnloadCancellationToken.ThrowIfCancellationRequested(); lock (SyncObject) { Verify.NotDisposed(this); // Issue this token before hooking the SnapshotChanged event to prevent a race // where a snapshot tree is replaced by the initial, empty tree created below. // The handler will cancel this token before submitting its update. CancellationToken initialTreeCancellationToken = _treeUpdateCancellationSeries.CreateNext(); _ = SubmitTreeUpdateAsync( delegate { IProjectTree dependenciesNode = CreateDependenciesNode(); return(Task.FromResult(new TreeUpdateResult(dependenciesNode))); }, initialTreeCancellationToken); ITargetBlock <SnapshotChangedEventArgs> actionBlock = DataflowBlockFactory.CreateActionBlock <SnapshotChangedEventArgs>( OnDependenciesSnapshotChangedAsync, _project, nameFormat: "DependenciesProjectTreeProviderSource {1}", skipIntermediateInputData: true); _snapshotEventListener = _dependenciesSnapshotProvider.SnapshotChangedSource.LinkTo(actionBlock, DataflowOption.PropagateCompletion); } }, registerFaultHandler: true); } IProjectTree CreateDependenciesNode() { var values = new ReferencesProjectTreeCustomizablePropertyValues { Caption = Resources.DependenciesNodeName, Icon = KnownMonikers.ReferenceGroup.ToProjectSystemType(), ExpandedIcon = KnownMonikers.ReferenceGroup.ToProjectSystemType(), Flags = ProjectTreeFlags.Create(ProjectTreeFlags.Common.BubbleUp) + ProjectTreeFlags.Create(ProjectTreeFlags.Common.ReferencesFolder) + ProjectTreeFlags.Create(ProjectTreeFlags.Common.VirtualFolder) + DependencyTreeFlags.DependenciesRootNode }; // Allow property providers to perform customization. // These are ordered from lowest priority to highest, allowing higher priority // providers to override lower priority providers. foreach (IProjectTreePropertiesProvider provider in _projectTreePropertiesProviders.ExtensionValues()) { provider.CalculatePropertyValues(ProjectTreeCustomizablePropertyContext.Instance, values); } return(NewTree( caption: values.Caption, icon: values.Icon, expandedIcon: values.ExpandedIcon, flags: values.Flags)); } }
/// <summary> /// Creates or updates a project tree for a given IProjectDependenciesSubTreeProvider /// </summary> /// <param name="dependenciesNode"></param> /// <param name="subTreeProvider"></param> /// <param name="changes"></param> /// <param name="catalogs">Can be null if sub tree provider does not use design time build</param> /// <param name="cancellationToken"></param> /// <returns>IProjectTree for root Dependencies node</returns> private IProjectTree CreateOrUpdateSubTreeProviderNode(IProjectTree dependenciesNode, IProjectDependenciesSubTreeProvider subTreeProvider, IDependenciesChangeDiff changes, IProjectCatalogSnapshot catalogs, CancellationToken cancellationToken) { Requires.NotNull(dependenciesNode, nameof(dependenciesNode)); Requires.NotNull(subTreeProvider, nameof(subTreeProvider)); Requires.NotNull(subTreeProvider.RootNode, nameof(subTreeProvider.RootNode)); Requires.NotNullOrEmpty(subTreeProvider.RootNode.Caption, nameof(subTreeProvider.RootNode.Caption)); Requires.NotNullOrEmpty(subTreeProvider.ProviderType, nameof(subTreeProvider.ProviderType)); var providerRootTreeNode = GetSubTreeRootNode(dependenciesNode, subTreeProvider.RootNode.Flags); if (subTreeProvider.RootNode.HasChildren || subTreeProvider.ShouldBeVisibleWhenEmpty) { bool newNode = false; if (providerRootTreeNode == null) { providerRootTreeNode = NewTree( caption: subTreeProvider.RootNode.Caption, visible: true, filePath: subTreeProvider.RootNode.Id.ToString(), browseObjectProperties: null, flags: subTreeProvider.RootNode.Flags, icon: subTreeProvider.RootNode.Icon.ToProjectSystemType(), expandedIcon: subTreeProvider.RootNode.ExpandedIcon.ToProjectSystemType()); newNode = true; } if (changes != null) { foreach (var removedItem in changes.RemovedNodes) { if (cancellationToken.IsCancellationRequested) { return(dependenciesNode); } var treeNode = providerRootTreeNode.FindNodeByPath(removedItem.Id.ToString()); if (treeNode != null) { providerRootTreeNode = treeNode.Remove(); } } foreach (var updatedItem in changes.UpdatedNodes) { if (cancellationToken.IsCancellationRequested) { return(dependenciesNode); } var treeNode = providerRootTreeNode.FindNodeByPath(updatedItem.Id.ToString()); if (treeNode != null) { var updatedNodeParentContext = GetCustomPropertyContext(treeNode.Parent); var updatedValues = new ReferencesProjectTreeCustomizablePropertyValues { Caption = updatedItem.Caption, Flags = updatedItem.Flags, Icon = updatedItem.Icon.ToProjectSystemType(), ExpandedIcon = updatedItem.ExpandedIcon.ToProjectSystemType() }; ApplyProjectTreePropertiesCustomization(updatedNodeParentContext, updatedValues); // update existing tree node properties treeNode = treeNode.SetProperties( caption: updatedItem.Caption, flags: updatedItem.Flags, icon: updatedItem.Icon.ToProjectSystemType(), expandedIcon: updatedItem.ExpandedIcon.ToProjectSystemType()); providerRootTreeNode = treeNode.Parent; } } var configuredProjectExports = GetActiveConfiguredProjectExports(ActiveConfiguredProject); foreach (var addedItem in changes.AddedNodes) { if (cancellationToken.IsCancellationRequested) { return(dependenciesNode); } var treeNode = providerRootTreeNode.FindNodeByPath(addedItem.Id.ToString()); if (treeNode == null) { IRule rule = null; if (addedItem.Properties != null) { // when itemSpec is not in valid absolute path format, property page does not show // item name correctly. var itemSpec = addedItem.Flags.Contains(DependencyNode.CustomItemSpec) ? addedItem.Caption : addedItem.Id.ItemSpec; var itemContext = ProjectPropertiesContext.GetContext(UnconfiguredProject, addedItem.Id.ItemType, itemSpec); if (addedItem.Resolved) { rule = GetRuleForResolvableReference( itemContext, new KeyValuePair <string, IImmutableDictionary <string, string> >( addedItem.Id.ItemSpec, addedItem.Properties), catalogs, configuredProjectExports); } else { rule = GetRuleForUnresolvableReference( itemContext, catalogs, configuredProjectExports); } } // Notify about tree changes to customization context var customTreePropertyContext = GetCustomPropertyContext(providerRootTreeNode); var customTreePropertyValues = new ReferencesProjectTreeCustomizablePropertyValues { Caption = addedItem.Caption, Flags = addedItem.Flags, Icon = addedItem.Icon.ToProjectSystemType() }; ApplyProjectTreePropertiesCustomization(customTreePropertyContext, customTreePropertyValues); treeNode = NewTree(caption: addedItem.Caption, visible: true, filePath: addedItem.Id.ToString(), browseObjectProperties: rule, flags: addedItem.Flags, icon: addedItem.Icon.ToProjectSystemType(), expandedIcon: addedItem.ExpandedIcon.ToProjectSystemType()); providerRootTreeNode = providerRootTreeNode.Add(treeNode).Parent; } } } if (newNode) { dependenciesNode = dependenciesNode.Add(providerRootTreeNode).Parent; } else { dependenciesNode = providerRootTreeNode.Parent; } } else { if (providerRootTreeNode != null) { dependenciesNode = dependenciesNode.Remove(providerRootTreeNode); } } return(dependenciesNode); }
private IProjectTree CreateOrUpdateNode( IProjectTree?node, IDependencyViewModel viewModel, IRule?browseObjectProperties, bool isProjectItem, ProjectTreeFlags?additionalFlags = null, ProjectTreeFlags?excludedFlags = null) { if (node != null) { return(UpdateTreeNode()); } ProjectTreeFlags filteredFlags = FilterFlags(viewModel.Flags); return(isProjectItem ? CreateProjectItemTreeNode() : CreateProjectTreeNode()); IProjectTree CreateProjectTreeNode() { return(_treeServices.CreateTree( caption: viewModel.Caption, filePath: viewModel.FilePath, browseObjectProperties: browseObjectProperties, icon: viewModel.Icon.ToProjectSystemType(), expandedIcon: viewModel.ExpandedIcon.ToProjectSystemType(), visible: true, flags: filteredFlags)); } IProjectTree CreateProjectItemTreeNode() { var itemContext = ProjectPropertiesContext.GetContext( _commonServices.Project, file: viewModel.FilePath, itemType: viewModel.SchemaItemType, itemName: viewModel.FilePath); return(_treeServices.CreateTree( caption: viewModel.Caption, itemContext: itemContext, browseObjectProperties: browseObjectProperties, icon: viewModel.Icon.ToProjectSystemType(), expandedIcon: viewModel.ExpandedIcon.ToProjectSystemType(), visible: true, flags: filteredFlags)); } IProjectTree UpdateTreeNode() { var updatedNodeParentContext = new ProjectTreeCustomizablePropertyContext { ExistsOnDisk = false, ParentNodeFlags = node !.Parent?.Flags ?? default }; var updatedValues = new ReferencesProjectTreeCustomizablePropertyValues { Caption = viewModel.Caption, Flags = viewModel.Flags, Icon = viewModel.Icon.ToProjectSystemType(), ExpandedIcon = viewModel.ExpandedIcon.ToProjectSystemType() }; foreach (Lazy <IProjectTreePropertiesProvider, IOrderPrecedenceMetadataView> provider in _projectTreePropertiesProviders) { provider.Value.CalculatePropertyValues(updatedNodeParentContext, updatedValues); } return(node.SetProperties( caption: updatedValues.Caption, browseObjectProperties: browseObjectProperties, icon: updatedValues.Icon, expandedIcon: updatedValues.ExpandedIcon, flags: updatedValues.Flags)); } ProjectTreeFlags FilterFlags(ProjectTreeFlags flags) { if (additionalFlags.HasValue) { flags = flags.Union(additionalFlags.Value); } if (excludedFlags.HasValue) { flags = flags.Except(excludedFlags.Value); } return(flags); } }