1
votes

Note: Although my question is in the same ballpark as VSTO Word post save event, the aims and goals (and resultant required code) are different. The OP in VSTO Word post save event states:

after the document is save to disk, I need to capture that event, close the file, do what I need to do and reopen it.

My needs are different. See my OP.

end of Note

I have a VSTO add-in for Word that is is designed to manipulate various elements of RTF files (and only RTF files). The add-in is invoked by a ribbon button. If the user opens an RTF document, and then does a save-as, I want to capture an event so I can examine the file name chosen for the save-as and disable the button that invokes my add-in if the extension is not .RTF.

In my ribbon class ribbon load method (The event handling method asserted in my ribbon class's designer file: this.Load += new Microsoft.Office.Tools.Ribbon.RibbonUIEventHandler(this.Ribbon1_Load)), I've coded up various available events (e.g., Globals.ThisAddIn.Application.DocumentChange += Application_DocumentChange; and Globals.ThisAddIn.Application.DocumentOpen += Application_DocumentOpen;) but all the events available are fired before the save-as happens, not after. I've also put a breakpoint in this ribbon load method. It is not executed again after the save-as (I'm not surprised)

Am I missing something? For my VSTO Word add-in, is there an event fired after the save-as event that is capturable in my ribbon class that will provide the name of the file chosen for the save-as?

Update to my code reflecting Cindy Meister's answer

Credit to Joseph Fox on the Microsoft Developer's Network. My code derived from Document Save Event

Note: my VSTO ribbon class is named ClsLesCaveat. It is a new group with two buttons that sits in the existing Insert table. It was created using only the VSTO designer in VS Pro 2017.

For me, my ribbon buttons need to be disabled in two scenarios:

1) If someone opens a file using Word that does not have an .RTF extension, my ribbon buttons should be disabled

2) If someone opens an .RTF file using Word (my buttons are enabled), but if they do a save-as to a non-.RTF file, my ribbon buttons should be disabled for that non-.RTF document

Note: Don't care about save because my ribbon buttons are enabled/disabled at open or save-as otherwise

using System;
using System.IO;

namespace LesCaveatAddIn
{
    public partial class ThisAddIn
    {
        private bool allowSave = false;

        private void ThisAddIn_Startup(object sender, System.EventArgs e)
        {

            this.Application.DocumentBeforeSave += Application_DocumentBeforeSave;
            this.Application.DocumentOpen += Application_DocumentOpen;
        }

        # On open, disable buttons, enable buttons only if file extension is .RTF
        private void Application_DocumentOpen(Microsoft.Office.Interop.Word.Document Doc)
        {
            string extension = (Path.GetExtension(Doc.FullName)).ToUpper();

            Type type = typeof(ClsLesCaveat);
            ClsLesCaveat ribbon = Globals.Ribbons.GetRibbon(type) as ClsLesCaveat;

            ribbon.objButtonAddFouoCaveat.Enabled = false;
            ribbon.objButtonAddLesCaveat.Enabled = false;

            if (extension.Equals(".RTF"))
            {
                ribbon.objButtonAddFouoCaveat.Enabled = true;
                ribbon.objButtonAddLesCaveat.Enabled = true;
            }
        }

        # On save-as, handle the save-as myself. Cancel the save-as (since I just handled it). Then, disable buttons, enable buttons only if the save-as file extension is .RTF.
        private void Application_DocumentBeforeSave(Microsoft.Office.Interop.Word.Document Doc, ref bool SaveAsUI, ref bool Cancel)
        {
            if (!allowSave)
            {
                allowSave = true;

                if (SaveAsUI)
                {
                    // Display Save As dialog
                    Microsoft.Office.Interop.Word.Dialog d = Globals.ThisAddIn.Application.Dialogs[Microsoft.Office.Interop.Word.WdWordDialog.wdDialogFileSaveAs];
                    object timeOut = 0;
                    d.Show(ref timeOut);
                }
                else
                {
                    // Save without dialog
                    Doc.Save();
                }

                allowSave = false;
                Cancel = true;

                string extension = (Path.GetExtension(Doc.FullName)).ToUpper();

                Type type = typeof(ClsLesCaveat);
                ClsLesCaveat ribbon = Globals.Ribbons.GetRibbon(type) as ClsLesCaveat;

                ribbon.objButtonAddFouoCaveat.Enabled = false;
                ribbon.objButtonAddLesCaveat.Enabled = false;

                if (extension.Equals(".RTF"))
                {
                    ribbon.objButtonAddFouoCaveat.Enabled = true;
                    ribbon.objButtonAddLesCaveat.Enabled = true;
                }
            }
        }

        private void ThisAddIn_Shutdown(object sender, System.EventArgs e)
        {
        }

        #region VSTO generated code

        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InternalStartup()
        {
            this.Startup += new System.EventHandler(ThisAddIn_Startup);
            this.Shutdown += new System.EventHandler(ThisAddIn_Shutdown);
        }

        #endregion
    }
}
1
Possible duplicate of VSTO Word post save eventChris

1 Answers

2
votes

No, there is no event to capture any Save or save after actions. The only one related to saving is DocumentBeforeSave.

DocumentBeforeSave does provide arguments that let the developer suppress the built-in UI (SaveAs dialog box) as well as cancel the action that triggered the event. This allows developers to provide their own interface for saving (as) which will enable determining when the document is saved (as) and taking any actions desired, depending on the file name, extension or whatever the criteria are.

It's also possible to work with Word's built-in SaveAs dialog box, rather than creating one's own, although this is a bit round-about in C# as it requires using PInvoke. Here's an example to give you an idea how this could work (not tested as I'm on a mobile device):

    private void ThisDocument_BeforeSave(object sender, object e)
    {
        //Suppress the built-in SaveAs interface (dialog box)
        e.SaveAsUi = false;
        //Cancel the default action
        e.Cancel = true;
        Word.Dialog dlg = wdApplication.Dialogs[Microsoft.Office.Interop.Word.WdWordDialog.wdDialogFileSaveAs];
        //Word dialog box parameters have to be accessed via Late-Binding (PInvoke) 
        //To get the path, use the Name property
        object oDlg = (object)dlg;
        object[] oArgs = new object[1];
        oArgs[0] = (object)@"";
        dlg.Show(ref missing);
        object fileName = oDlg.GetType().InvokeMember("Name", BindingFlags.GetProperty, null, oDlg, oArgs);
    }

The available dialog box arguments that can be used are listed here.