/// <summary>
/// Reloads a nested project node by deleting it and readding it.
/// </summary>
/// <param name="node">The node to reload.</param>
protected virtual void ReloadNestedProjectNode(NestedProjectNode node)
{
if (node == null)
{
throw new ArgumentNullException("node");
}
IVsSolution solution = this.GetService(typeof(IVsSolution)) as IVsSolution;
if (solution == null)
{
throw new InvalidOperationException();
}
NestedProjectNode newNode = null;
try
{
// (VS 2005 UPDATE) When deleting and re-adding the nested project,
// we do not want SCC to see this as a delete and add operation.
this.EventTriggeringFlag = SuppressEvents.Tracker;
// notify SolutionEvents listeners that we are about to add children
IVsFireSolutionEvents fireSolutionEvents = solution as IVsFireSolutionEvents;
if (fireSolutionEvents == null)
{
throw new InvalidOperationException();
}
ErrorHandler.ThrowOnFailure(fireSolutionEvents.FireOnBeforeUnloadProject(node.NestedHierarchy));
int isDirtyAsInt = 0;
this.IsDirty(out isDirtyAsInt);
bool isDirty = (isDirtyAsInt == 0) ? false : true;
ProjectElement element = node.ItemNode;
node.CloseNestedProjectNode();
// Remove from the solution
this.RemoveChild(node);
// Now readd it
try
{
__VSCREATEPROJFLAGS flags = __VSCREATEPROJFLAGS.CPF_NOTINSLNEXPLR | __VSCREATEPROJFLAGS.CPF_SILENT | __VSCREATEPROJFLAGS.CPF_OPENFILE;
newNode = this.AddExistingNestedProject(element, flags);
newNode.AddVirtualProject();
}
catch (Exception e)
{
// We get a System.Exception if anything failed, thus we have no choice but catch it.
// Exceptions are digested by VS. Show the error if not in automation.
if (!Utilities.IsInAutomationFunction(this.Site))
{
string message = (String.IsNullOrEmpty(e.Message)) ? SR.GetString(SR.NestedProjectFailedToReload, CultureInfo.CurrentUICulture) : e.Message;
string title = string.Empty;
OLEMSGICON icon = OLEMSGICON.OLEMSGICON_CRITICAL;
OLEMSGBUTTON buttons = OLEMSGBUTTON.OLEMSGBUTTON_OK;
OLEMSGDEFBUTTON defaultButton = OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST;
VsShellUtilities.ShowMessageBox(this.Site, title, message, icon, buttons, defaultButton);
}
// Do not digest exception. let the caller handle it. If in a later stage this exception is not digested then the above messagebox is not needed.
throw;
}
#if DEBUG
IVsHierarchy nestedHierarchy;
ErrorHandler.ThrowOnFailure(solution.GetProjectOfUniqueName(newNode.GetMKDocument(), out nestedHierarchy));
Debug.Assert(nestedHierarchy != null && Utilities.IsSameComObject(nestedHierarchy, newNode.NestedHierarchy), "The nested hierrachy was not reloaded correctly.");
#endif
this.SetProjectFileDirty(isDirty);
ErrorHandler.ThrowOnFailure(fireSolutionEvents.FireOnAfterLoadProject(newNode.NestedHierarchy));
}
finally
{
// In this scenario the nested project failed to unload or reload the nested project. We will unload the whole project, otherwise the nested project is lost.
// This is similar to the scenario when one wants to open a project and the nested project cannot be loaded because for example the project file has xml errors.
// We should note that we rely here that if the unload fails then exceptions are not digested and are shown to the user.
if (newNode == null || newNode.NestedHierarchy == null)
{
ErrorHandler.ThrowOnFailure(solution.CloseSolutionElement((uint)__VSSLNCLOSEOPTIONS.SLNCLOSEOPT_UnloadProject | (uint)__VSSLNSAVEOPTIONS.SLNSAVEOPT_ForceSave, this.InteropSafeIVsHierarchy, 0));
}
else
{
this.EventTriggeringFlag = SuppressEvents.None;
}
}
}