Search code examples
c#visual-studiovs-extensibilityvspackage

How do you cancel a ToolWindowPane or Visual Studio IDE close operation via a VSPackage?


I have a VSPackage with a dockable tool window containing form data. If there are unsaved changes in this form, I would like to cancel a close to either the tool window and the visual studio IDE if the user clicks cancel on saving changes before closing. I can perform the save test on close, but I don't see any event handler methods or other options to actually cancel the close.

Here is some blurb from the package:

    private DTE2 _applicationObject = null;
    ///--------------------------------------------------------------------------------
    /// <summary>This property gets the visual studio IDE application object.</summary>
    ///--------------------------------------------------------------------------------
    public DTE2 ApplicationObject
    {
        get
        {
            if (_applicationObject == null)
            {
                // Get an instance of the currently running Visual Studio IDE
                DTE dte = (DTE)GetService(typeof(DTE));
                _applicationObject = dte as DTE2;
            }
            return _applicationObject;
        }
    }
    ///--------------------------------------------------------------------------------
    /// <summary>
    /// Initialization of the package; this method is called right after the package is sited, so this is the place
    /// where you can put all the initilaization code that rely on services provided by VisualStudio.
    /// </summary>
    ///--------------------------------------------------------------------------------
    protected override void Initialize()
    {
        Trace.WriteLine(string.Format(CultureInfo.CurrentCulture, "Entering Initialize() of: {0}", this.ToString()));
        base.Initialize();

        // add the event handlers
        if (ApplicationObject != null)
        {
            // wire up window events
            PackageWindowEvents = (WindowEvents)ApplicationObject.Events.get_WindowEvents(null);
            PackageWindowEvents.WindowClosing += new _dispWindowEvents_WindowClosingEventHandler(PackageWindowEvents_WindowClosing);

            // wire up solution events
            PackageSolutionEvents = ApplicationObject.Events.SolutionEvents;
            PackageSolutionEvents.Opened += new _dispSolutionEvents_OpenedEventHandler(CheckOpenCurrentSolution);

            // wire up DTE events
            PackageDTEEvents = ApplicationObject.Events.DTEEvents;
            PackageDTEEvents.OnBeginShutdown += new _dispDTEEvents_OnBeginShutdownEventHandler(HandleVisualStudioShutdown);
        }
    }

    void PackageWindowEvents_WindowClosing(Window window)
    {
        // handle save/cancel scenarios
    }

And some blurb from the ToolWindowPane that implements IVsWindowFrameNotify3:

    protected override void OnClose()
    {
        base.OnClose();
    }
    public int OnClose(ref uint pgrfSaveOptions)
    {
        return (int)__FRAMECLOSE.FRAMECLOSE_PromptSave;
    }

The OnClose and WindowClosing methods fire when expected, but I'm not finding a way to cancel the close. What am I missing? Are there different events required to cancel a close?


Solution

  • For completeness, there IS a useful way to cancel a close with a tool window (provided by user Chicobo on the msdn forum and repeated here).

    1. In your ToolWindowPane class, implement the IVsWindowFrameNotify2 interface, which provides a method OnClose.

    2. To cancel the window closing, consider using :

      public int OnClose(ref uint pgrfSaveOptions)
      {
          // Check if your content is dirty here, then
      
          // Prompt a dialog
          MessageBoxResult res = MessageBox.Show("This Document has been modified. Do you want to save the changes ?",
                        "Unsaved changes", MessageBoxButton.YesNoCancel, MessageBoxImage.Warning);
          // If the users wants to save
          if (res == MessageBoxResult.Yes)
          {
              // Handle with your "save method here"
          }
      
          if (res == MessageBoxResult.Cancel)
          {
              // If "cancel" is clicked, abort the close
              return VSConstants.E_ABORT;
          }
      
          // Else, exit
          return VSConstants.S_OK;
      }