public override int OnAfterOpenProject(IVsHierarchy hierarchy, int added) { // If this is a new project and our project. We use here that it is only our project that will implemnet the "internal" IBuildDependencyOnProjectContainer. if (added != 0 && hierarchy is IBuildDependencyUpdate) { IVsUIHierarchy uiHierarchy = hierarchy as IVsUIHierarchy; Debug.Assert(uiHierarchy != null, "The ProjectNode should implement IVsUIHierarchy"); // Expand and select project node IVsUIHierarchyWindow uiWindow = UIHierarchyUtilities.GetUIHierarchyWindow(this.ServiceProvider, HierarchyNode.SolutionExplorer); if (uiWindow != null) { __VSHIERARCHYITEMSTATE state; uint stateAsInt; if (uiWindow.GetItemState(uiHierarchy, VSConstants.VSITEMID_ROOT, (uint)__VSHIERARCHYITEMSTATE.HIS_Expanded, out stateAsInt) == VSConstants.S_OK) { state = (__VSHIERARCHYITEMSTATE)stateAsInt; if (state != __VSHIERARCHYITEMSTATE.HIS_Expanded) { int hr; hr = uiWindow.ExpandItem(uiHierarchy, VSConstants.VSITEMID_ROOT, EXPANDFLAGS.EXPF_ExpandParentsToShowItem); if (ErrorHandler.Failed(hr)) { Trace.WriteLine("Failed to expand project node"); } hr = uiWindow.ExpandItem(uiHierarchy, VSConstants.VSITEMID_ROOT, EXPANDFLAGS.EXPF_SelectItem); if (ErrorHandler.Failed(hr)) { Trace.WriteLine("Failed to select project node"); } return(hr); } } } } return(VSConstants.S_OK); }
/// <summary> /// Renames the file in the hierarchy by removing old node and adding a new node in the hierarchy. /// </summary> /// <param name="oldFileName">The old file name.</param> /// <param name="newFileName">The new file name</param> /// <param name="newParentId">The new parent id of the item.</param> /// <returns>The newly added FileNode.</returns> /// <remarks>While a new node will be used to represent the item, the underlying MSBuild item will be the same and as a result file properties saved in the project file will not be lost.</remarks> public virtual FileNode RenameFileNode(string oldFileName, string newFileName, uint newParentId) { if (string.Compare(oldFileName, newFileName, StringComparison.Ordinal) == 0) { // We do not want to rename the same file return(null); } string[] file = new string[1]; file[0] = newFileName; VSADDRESULT[] result = new VSADDRESULT[1]; Guid emptyGuid = Guid.Empty; FileNode childAdded = null; string originalInclude = this.ItemNode.Item.UnevaluatedInclude; return(Transactional.Try( // Action () => { // It's unfortunate that MPF implements rename in terms of AddItemWithSpecific. Since this // is the case, we have to pass false to prevent AddITemWithSpecific to fire Add events on // the IVsTrackProjectDocuments2 tracker. Otherwise, clients listening to this event // (SCCI, for example) will be really confused. using (this.ProjectMgr.ExtensibilityEventsHelper.SuspendEvents()) { var currentId = this.ID; // actual deletion is delayed until all checks are passed Func <uint> getIdOfExistingItem = () => { this.OnItemDeleted(); this.Parent.RemoveChild(this); return currentId; }; // raises OnItemAdded inside ErrorHandler.ThrowOnFailure(this.ProjectMgr.AddItemWithSpecific(newParentId, VSADDITEMOPERATION.VSADDITEMOP_OPENFILE, null, 0, file, IntPtr.Zero, 0, ref emptyGuid, null, ref emptyGuid, result, false, getIdOfExistingItem)); childAdded = this.ProjectMgr.FindChild(newFileName) as FileNode; Debug.Assert(childAdded != null, "Could not find the renamed item in the hierarchy"); } }, // Compensation () => { // it failed, but 'this' is dead and 'childAdded' is here to stay, so fix the latter back using (this.ProjectMgr.ExtensibilityEventsHelper.SuspendEvents()) { childAdded.ItemNode.Rename(originalInclude); childAdded.ItemNode.RefreshProperties(); } }, // Continuation () => { // Since this node has been removed all of its state is zombied at this point // Do not call virtual methods after this point since the object is in a deleted state. // Remove the item created by the add item. We need to do this otherwise we will have two items. // Please be aware that we have not removed the ItemNode associated to the removed file node from the hierrachy. // What we want to achieve here is to reuse the existing build item. // We want to link to the newly created node to the existing item node and addd the new include. //temporarily keep properties from new itemnode since we are going to overwrite it string newInclude = childAdded.ItemNode.Item.UnevaluatedInclude; string dependentOf = childAdded.ItemNode.GetMetadata(ProjectFileConstants.DependentUpon); childAdded.ItemNode.RemoveFromProjectFile(); // Assign existing msbuild item to the new childnode childAdded.ItemNode = this.ItemNode; childAdded.ItemNode.Item.ItemType = this.ItemNode.ItemName; childAdded.ItemNode.Item.Xml.Include = newInclude; if (!string.IsNullOrEmpty(dependentOf)) { childAdded.ItemNode.SetMetadata(ProjectFileConstants.DependentUpon, dependentOf); } childAdded.ItemNode.RefreshProperties(); // Extensibilty events has rename this.ProjectMgr.ExtensibilityEventsHelper.FireItemRenamed(childAdded, Path.GetFileName(originalInclude)); //Update the new document in the RDT. try { DocumentManager.RenameDocument(this.ProjectMgr.Site, oldFileName, newFileName, childAdded.ID); // The current automation node is renamed, but the hierarchy ID is now pointing to the old item, which // is invalid. Update it. this.ID = childAdded.ID; //Update FirstChild childAdded.FirstChild = this.FirstChild; //Update ChildNodes SetNewParentOnChildNodes(childAdded); RenameChildNodes(childAdded); return childAdded; } finally { //Select the new node in the hierarchy IVsUIHierarchyWindow uiWindow = UIHierarchyUtilities.GetUIHierarchyWindow(this.ProjectMgr.Site, SolutionExplorer); uiWindow.ExpandItem(this.ProjectMgr.InteropSafeIVsUIHierarchy, childAdded.ID, EXPANDFLAGS.EXPF_SelectItem); } })); }