none
Word07: Hinzugefügter SaveEventHandler funktioniert nach Schließung eines Dokuments nicht mehr bei neuen Files RRS feed

  • Frage

  • Hallo!

    Ich programmiere gerade ein AddIn mit VS2010 Beta2 für Word 2007.
    Das AddIn dient der Automatisierung von Vorlangen für die Verwaltung wie Dienstverträgen und anderem.

    Wenn ein solch erstelltes Dokument gespeichert wird, soll ein Eintrag in deiner SQL Datenbank gemacht werden. Dazu habe ich einen eigenen SaveEventHandler geschrieben und dieser wird beim Laden des Addins dem Event .BeforeSave des aktuellen Dokuments hinzugefügt. Dieser SaveEventHandler führt seine Tätigkeit nur aus, wenn in den Dokumenteigentschaften des Files, welches gespeichert werden soll, im Feld Kategorie ein bestimmter Eintrag vorhanden ist.

    Weiters will ich natürlich auch, dass alle neu erstellten oder geöffneten Dokumente auch diesen neuen SaveEventHandler mitbekommen. Deshalb habe ich auch zu den Events .DocumentOpen und .NewDocument der Word-Applikation neue EventHandler hinzugefügt, welche dem Dokument gleich den neuen EventHandler mitgeben. Das Event WindowActivate wird verwendet, damit das AddIn immer weiß, welches Dokument gerade aktiv ist, damit es die richtigen DocumentProperties ausliest.

    Der Code sieht folgendermaßen aus:

    public partial class ThisAddIn
      {
        private Word.Document ActDoc = null;
        private Microsoft.Office.Tools.Word.Document ExtendedActDoc = null;
    
        QueriesTableAdapter QTableAdapter = new QueriesTableAdapter();
    
        #region EventHandler
        private void ThisAddIn_Startup(object sender, System.EventArgs e)
        {
          ActDoc = Globals.ThisAddIn.Application.ActiveDocument;
          ExtendedActDoc = Globals.Factory.GetVstoObject(ActDoc);
          
          ExtendedActDoc.BeforeSave += new SaveEventHandler(ThisAddIn_Save);
          
          Word.Application myApplication;
          myApplication = Application;
          Word.ApplicationEvents4_Event appEvents = myApplication as Word.ApplicationEvents4_Event;
          appEvents.DocumentOpen += new Word.ApplicationEvents4_DocumentOpenEventHandler(Application_DocumentOpen);
          appEvents.NewDocument += new Word.ApplicationEvents4_NewDocumentEventHandler(Application_NewDocument);
          appEvents.WindowActivate += new Word.ApplicationEvents4_WindowActivateEventHandler(Application_WindowActivate);
        }
    
        void Application_WindowActivate(Word.Document Doc, Word.Window Wn)
        {
          ExtendedActDoc = Globals.Factory.GetVstoObject(Doc);
        }
    
        void Application_NewDocument(Word.Document Doc)
        {
          ExtendedActDoc = Globals.Factory.GetVstoObject(Doc);
          ExtendedActDoc.BeforeSave += new SaveEventHandler(ThisAddIn_Save);
        } 
    
        void Application_DocumentOpen(Word.Document Doc)
        {
          ExtendedActDoc = Globals.Factory.GetVstoObject(Doc);
          ExtendedActDoc.BeforeSave += new SaveEventHandler(ThisAddIn_Save);
        }
    
        private void ThisAddIn_Shutdown(object sender, System.EventArgs e)
        {
        }
        #endregion
    
        private void ThisAddIn_Save(object sender, Microsoft.Office.Tools.Word.SaveEventArgs e)
        {
          DocumentProperties docProps = (DocumentProperties)ExtendedActDoc.BuiltInDocumentProperties;
          string docCategory = null;
          if (docProps["Category"].Value != null) docCategory = docProps["Category"].Value.ToString();
    
          if (Globals.Ribbons.Ribbon1.menu1.Tag != null && docCategory == "s3kVorlage")
          {
            e.Cancel = true;
            Microsoft.Office.Core.FileDialog fdSaveDocument;
            fdSaveDocument = Globals.ThisAddIn.Application.get_FileDialog(MsoFileDialogType.msoFileDialogSaveAs);
            fdSaveDocument.AllowMultiSelect = false;
            fdSaveDocument.InitialFileName = Globals.Ribbons.Ribbon1.menu1.Label.Replace(".", "").Replace(" ", "_");
            if (fdSaveDocument.Show() == -1)
            {
              int? uniqueID = null;
              QTableAdapter.AddPersonHistory((int?)Globals.Ribbons.Ribbon1.menu1.Tag, 3,
                System.Environment.UserName, DateTime.Now, fdSaveDocument.SelectedItems.Item(1),
                DateTime.Now, System.Environment.UserName, true, "", ref uniqueID);
    
              docProps["Author"].Value = System.Environment.UserName;
              docProps["Subject"].Value = Globals.Ribbons.Ribbon1.menu1.Label.Replace(".", "").Replace(" ", "_");
              docProps["Category"].Value = "s3kDokument";
              docProps["Keywords"].Value = uniqueID;
    
              fdSaveDocument.Execute();
            }
          }
          else if (docCategory == "s3kDokument")
          {
            e.Cancel = true;
            int HistoryID = Convert.ToInt32(docProps["Keywords"].Value, 10);
            DialogResult saveResult = MessageBox.Show("Bestehende Datei ersetzen?", "Achtung",
              MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1);
            if (saveResult == DialogResult.No)
            {
              Microsoft.Office.Core.FileDialog fdSaveDocument;
              fdSaveDocument = Globals.ThisAddIn.Application.get_FileDialog(MsoFileDialogType.msoFileDialogSaveAs);
              fdSaveDocument.AllowMultiSelect = false;
              if (fdSaveDocument.Show() == -1)
              {
                QTableAdapter.UpdatePersonHistory(DateTime.Now, fdSaveDocument.SelectedItems.Item(1),
                  System.Environment.UserName, "", HistoryID, true);
                fdSaveDocument.Execute();
              }
            }
            else if (saveResult == DialogResult.Yes)
            {
              QTableAdapter.UpdatePersonHistory(DateTime.Now, ExtendedActDoc.FullName,
                System.Environment.UserName, "", HistoryID, true);
              Globals.ThisAddIn.Application.ActiveDocument.Save();
            }
          }
        }
      }

    Solange man nur immer ein File öffnet, daran arbeitet, dieses speichert und dann schließt, bevor man ein neues Dokument öffnet, funktionert es einwandfrei. Man kann auch beliebig viele Dokumente öffnen, solange keines geschlossen wird, alles kein Problem. Sobald man aber eines der Dokumente schließt (zum Beispiel wenn man ein neues Dokument erstellt und gleich darauf wieder schließt), funktioniert ab diesem Zeitpunkt in allen neu erstellten oder geöffneten Dokumenten der von mir geschrieben SaveEventHandler nicht mehr und es wird immer nur der Standard-SaveEventHandler von Word ausgeführt. Die Frage ist also, was beim Schließen eines Dokumentes passiert, so dass alle danach erstellten oder geöffneten Dokumente nicht mehr auf den hinzugefügten SaveEventHandler zurückgreifen.

    Ich habe bereits getestet, ob das NewDocument und das DocumentOpen Event weiterhin richtig ausgelöst wird und auch diese Events immer dem richtigen File den SaveEventHandler zufügen. All das funktioniert einwandfrei, ich habe es mir in einem .txt File protokollieren lassen. Die Dokumente bekommen den SaveEventHandler mit... sie greifen nur entweder nicht darauf zurück oder die Funktion wird nicht richtig übergeben?

    Vielleicht weiß dazu jemand eine Lösung oder hatte bereits ein ähnliches Problem... zumindest hoffe ich darauf, um dieses Verhalten beseitigen zu können. ;)

    Abschließend sollte ich vielleicht noch dazu sagen, dass ich das erste Mal in VS2010 und mit VSTO arbeite, also bitte ich darum, mögliche Code-technische Fehler zu entschuldigen. ;)

     

    Danke im Voraus!
    Christoph Planeta

     

    • Bearbeitet Christoph Planeta Dienstag, 20. April 2010 15:22 Formattierung des Codes
    Dienstag, 20. April 2010 14:55

Antworten

  • Hallo Christoph,

    ohne versucht zu haben Dein Problem zu reproduzieren, nur meine Vermutung: Es gibt im nativen Word Objektmodell kein BeforeClose Event auf Document Ebene, sondern nur das DocumentBeforeClose Event des Application Objekts. Du verwendest auch nicht das Interop Document, sondern das spezialisierte Word.Tools Document, was meiner Ansicht eher für dokumentbasierte  Add-Ins mit VSTO vorgesehen ist. Bei einem globalen Add-In für Word verwendet man doch eher das Interop Document. Weiter meine Vermutung, dass hier beim Tools Document.BeforeClose Event getrickst wird und hier eigentlich der Eventhandler Application.DocumentBeforeClose verwendet wird und von diesen Tools beim Schließen des ersten Dokuments abgehängt wird. Daher würde ich Dir empfehlen Application.DocumentBeforeClose zu verwenden. Dessen EventHandler musst Du auch nur einmal initialisieren und bekommst über die Parameter das betroffene Dokument.


    Thorsten Dörfler
    Microsoft MVP Visual Basic
    Dienstag, 20. April 2010 18:40
  • Hallo Christoph,

    entschuldige, mein Fehler, ich meite das (Document)BeforeSave Ereignis.


    Thorsten Dörfler
    Microsoft MVP Visual Basic
    Freitag, 23. April 2010 08:38

Alle Antworten

  • Hallo Christoph,

    ohne versucht zu haben Dein Problem zu reproduzieren, nur meine Vermutung: Es gibt im nativen Word Objektmodell kein BeforeClose Event auf Document Ebene, sondern nur das DocumentBeforeClose Event des Application Objekts. Du verwendest auch nicht das Interop Document, sondern das spezialisierte Word.Tools Document, was meiner Ansicht eher für dokumentbasierte  Add-Ins mit VSTO vorgesehen ist. Bei einem globalen Add-In für Word verwendet man doch eher das Interop Document. Weiter meine Vermutung, dass hier beim Tools Document.BeforeClose Event getrickst wird und hier eigentlich der Eventhandler Application.DocumentBeforeClose verwendet wird und von diesen Tools beim Schließen des ersten Dokuments abgehängt wird. Daher würde ich Dir empfehlen Application.DocumentBeforeClose zu verwenden. Dessen EventHandler musst Du auch nur einmal initialisieren und bekommst über die Parameter das betroffene Dokument.


    Thorsten Dörfler
    Microsoft MVP Visual Basic
    Dienstag, 20. April 2010 18:40
  • Hallo Thorsten,

    danke für deine schnelle Antwort. Jedoch verwirrt sie mich ein wenig und ich hab diesbezüglich eine Verständnisfragen. ;-)


    Das mit dem Interop Objekt werde ich gleich mal ausprobieren, jedoch verstehe ich nicht ganz, was es mit dem BeforeClose Event auf sich hat. Du rätst mir eher den Application.DocumentBeforeClose Eventhandler zu nutzen, obwohl ich bisher gar keinen Close Eventhandler verwenden. Insofern weiß ich nicht, wie mir dieser nun nützlich sein soll. Mein Problem ist ja, dass mein Save Eventhandler irgendwie durch den Default Close Eventhandler ausgeschalten wird.

    Aber ich teste nun mal die Variante per Interop Objekt, vielleicht behebt diese das Problem. Das wäre dann wieder ein Beweis dafür, dass Codebeispiele aus dem Internet nicht immer 1:1 verwendet werden sollten. :)

    Freitag, 23. April 2010 07:22
  • Hallo Christoph,

    entschuldige, mein Fehler, ich meite das (Document)BeforeSave Ereignis.


    Thorsten Dörfler
    Microsoft MVP Visual Basic
    Freitag, 23. April 2010 08:38
  • Hallo Thorsten,

    das habe ich mir schon fast gedacht. ;-)

    Habe durch deine Anregung jetzt an das Microsoft.Office.Interop.Word.ApplicationEvents4_Event appEvents Objekt den DocumentBeforeSave EventHandler angehängt. Dabei stellt sich mir die Frage, warum ich das nicht von Anfang an gemacht habe, denn dort hatte ich ja auch die 3 anderen EventHandler. Ich glaub mein Problem anfangs war, dass ich nicht wusste, wie ich an das DocumentBeforeSave Event der Applikation heran komme, das appEvents Objekt hab ich erst wesentlich später aufgrund des NewDocument und des DocumentOpen Events eingefügt.

    Jedenfalls funktioniert es nach einer kleinen Anpassung der Klasse nun einwandfrei. Der Code ist um gut 50 Zeilen kürzer und hat einiges an Komplexität verloren. :-)

    Danke vielmals für deine Hilfe!

    LG
    Christoph Planeta

    Freitag, 23. April 2010 10:06