Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>I've been chewing on this one for a while. Here's my attempt at using a hidden document, then grabbing the WordOpenXML from the hidden document and placing it in the real document when needed to make any amount of VSTO actions a single undo.</p> <pre><code>//Usage from ThisDocument VSTO Document level project public partial class ThisDocument { //Used to buffer writing text &amp; formatting to document (to save undo stack) public static DocBuffer buffer; //Attached Template public static Word.Template template; private void ThisDocument_Startup(object sender, System.EventArgs e) { //Ignore changes to template (removes prompt to save changes to template) template = (Word.Template)this.Application.ActiveDocument.get_AttachedTemplate(); template.Saved = true; //Document buffer buffer = new DocBuffer(); //Start buffer ThisDocument.buffer.Start(); //This becomes one "undo" Word.Selection curSel = Globals.ThisDocument.Application.Selection; curSel.TypeText(" "); curSel.TypeBackspace(); curSel.Font.Bold = 1; curSel.TypeText("Hello, world!"); curSel.Font.Bold = 0; curSel.TypeText(" "); //end buffer, print out text ThisDocument.buffer.End(); } void Application_DocumentBeforeClose(Microsoft.Office.Interop.Word.Document Doc, ref bool Cancel) { buffer.Close(); } private void ThisDocument_Shutdown(object sender, System.EventArgs e) { buffer.Close(); } } </code></pre> <p>Here is the DocBuffer Class:</p> <pre><code>public class DocBuffer { //Word API Objects Word._Document HiddenDoc; Word.Selection curSel; Word.Template template; //ref parameters object missing = System.Type.Missing; object FalseObj = false; //flip this for docbuffer troubleshooting object templateObj; //Is docbuffer running? public Boolean started{ get; private set; } //Open document on new object public DocBuffer() { //Clear out unused buffer bookmarks Word.Bookmarks bookmarks = Globals.ThisDocument.Application.ActiveDocument.Bookmarks; bookmarks.ShowHidden = true; foreach (Word.Bookmark mark in bookmarks) { if (mark.Name.Contains("_buf")) { mark.Delete(); } } //Remove trail of undo's for clearing out the bookmarks Globals.ThisDocument.UndoClear(); //Set up template template = ThisDocument.template; templateObj = template; //Open Blank document, then attach styles *and update HiddenDoc = Globals.ThisDocument.Application.Documents.Add(ref missing, ref missing, ref missing, ref FalseObj); HiddenDoc.set_AttachedTemplate(ref templateObj); HiddenDoc.UpdateStyles(); //Tell hidden document it has been saved to remove rare prompt to save document HiddenDoc.Saved = true; //Make primary document active Globals.ThisDocument.Activate(); } ~DocBuffer() { try { HiddenDoc.Close(ref FalseObj, ref missing, ref missing); } catch { } } public void Close() { try { HiddenDoc.Close(ref FalseObj, ref missing, ref missing); } catch { } } public void Start() { try { //Make hidden document active to receive selection HiddenDoc.Activate(); //results in a slight application focus loss } catch (System.Runtime.InteropServices.COMException ex) { if (ex.Message == "Object has been deleted.") { //Open Blank document, then attach styles *and update HiddenDoc = Globals.ThisDocument.Application.Documents.Add(ref missing, ref missing, ref missing, ref FalseObj); HiddenDoc.set_AttachedTemplate(ref templateObj); HiddenDoc.UpdateStyles(); HiddenDoc.Activate(); } else throw; } //Remove Continue Bookmark, if exists Word.Bookmarks hiddenDocBookmarks = Globals.ThisDocument.Application.ActiveDocument.Bookmarks; if (hiddenDocBookmarks.Exists("Continue")) { object deleteMarkObj = "Continue"; Word.Bookmark deleteMark = hiddenDocBookmarks.get_Item(ref deleteMarkObj); deleteMark.Select(); deleteMark.Delete(); } //Tell hidden document it has been saved to remove rare prompt to save document HiddenDoc.Saved = true; //Keep track when started started = true; } //Used for non-modal dialogs to bring active document back up between text insertion public void Continue() { //Exit quietly if buffer hasn't started if (!started) return; //Verify hidden document is active if ((HiddenDoc as Word.Document) != Globals.ThisDocument.Application.ActiveDocument) { HiddenDoc.Activate(); } //Hidden doc selection curSel = Globals.ThisDocument.Application.Selection; //Hidden doc range Word.Range bufDocRange; //Select entire doc, save range curSel.WholeStory(); bufDocRange = curSel.Range; //Find end, put a bookmark there bufDocRange.SetRange(curSel.End, curSel.End); object bookmarkObj = bufDocRange; //Generate "Continue" hidden bookmark Word.Bookmark mark = Globals.ThisDocument.Application.ActiveDocument.Bookmarks.Add("Continue", ref bookmarkObj); mark.Select(); //Tell hidden document it has been saved to remove rare prompt to save document HiddenDoc.Saved = true; //Make primary document active Globals.ThisDocument.Activate(); } public void End() { //Exit quietly if buffer hasn't started if (!started) return; //Turn off buffer started flag started = false; //Verify hidden document is active if ((HiddenDoc as Word.Document) != Globals.ThisDocument.Application.ActiveDocument) { HiddenDoc.Activate(); } //Remove Continue Bookmark, if exists Word.Bookmarks hiddenDocBookmarks = Globals.ThisDocument.Application.ActiveDocument.Bookmarks; hiddenDocBookmarks.ShowHidden = true; if (hiddenDocBookmarks.Exists("Continue")) { object deleteMarkObj = "Continue"; Word.Bookmark deleteMark = hiddenDocBookmarks.get_Item(ref deleteMarkObj); deleteMark.Delete(); } //Hidden doc selection curSel = Globals.ThisDocument.Application.Selection; //Hidden doc range Word.Range hiddenDocRange; Word.Range bufDocRange; //Select entire doc, save range curSel.WholeStory(); bufDocRange = curSel.Range; //If cursor bookmark placed in, move there, else find end of text, put a bookmark there Boolean cursorFound = false; if (hiddenDocBookmarks.Exists("_cursor")) { object cursorBookmarkObj = "_cursor"; Word.Bookmark cursorBookmark = hiddenDocBookmarks.get_Item(ref cursorBookmarkObj); bufDocRange.SetRange(cursorBookmark.Range.End, cursorBookmark.Range.End); cursorBookmark.Delete(); cursorFound = true; } else { //The -2 is done because [range object].WordOpenXML likes to drop bookmarks at the end of the range bufDocRange.SetRange(curSel.End - 2, curSel.End - 2); } object bookmarkObj = bufDocRange; //Generate GUID for hidden bookmark System.Guid guid = System.Guid.NewGuid(); String id = "_buf" + guid.ToString().Replace("-", string.Empty); Word.Bookmark mark = Globals.ThisDocument.Application.ActiveDocument.Bookmarks.Add(id, ref bookmarkObj); //Get OpenXML Text (Text with formatting) curSel.WholeStory(); hiddenDocRange = curSel.Range; string XMLText = hiddenDocRange.WordOpenXML; //Clear out contents of buffer hiddenDocRange.Delete(ref missing, ref missing); //comment this for docbuffer troubleshooting //Tell hidden document it has been saved to remove rare prompt to save document HiddenDoc.Saved = true; //Make primary document active Globals.ThisDocument.Activate(); //Get selection from new active document curSel = Globals.ThisDocument.Application.Selection; //insert buffered formatted text into main document curSel.InsertXML(XMLText, ref missing); //Place cursor at bookmark+1 (this is done due to WordOpenXML ignoring bookmarks at the end of the selection) Word.Bookmarks bookmarks = Globals.ThisDocument.Application.ActiveDocument.Bookmarks; bookmarks.ShowHidden = true; object stringObj = id; Word.Bookmark get_mark = bookmarks.get_Item(ref stringObj); bufDocRange = get_mark.Range; if (cursorFound) //Canned language actively placed cursor bufDocRange.SetRange(get_mark.Range.End, get_mark.Range.End); else //default cursor at the end of text bufDocRange.SetRange(get_mark.Range.End + 1, get_mark.Range.End + 1); bufDocRange.Select(); } </code></pre>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload