Tôi đã nhai cái này một lúc. Đây là nỗ lực của tôi khi sử dụng một tài liệu ẩn, sau đó lấy WordOpenXML từ tài liệu ẩn và đặt nó vào tài liệu thực khi cần thiết để thực hiện bất kỳ số lượng hành động VSTO nào một lần hoàn tác.
//Usage from ThisDocument VSTO Document level project
public partial class ThisDocument
{
//Used to buffer writing text & 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();
}
}
Đây là lớp DocBuffer:
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();
}
Wow! Tôi nghĩ tôi sẽ trả lời "có, nhưng nó không đẹp"! Tôi nghĩ rằng tôi sẽ xây dựng mà chỉ khi tôi cần, không muốn mess về quá nhiều cho bây giờ. Thú vị thứ mặc dù. – Gavin
Có ai nhận được điều này để làm việc trong Word 2007 không? Tôi chỉ đang cố bắt đầu đơn giản; Tôi thử thêm: "Sub EditUndo()/MsgBox (" Hello ")/ActiveDocument.Undo/End Sub" vào một trong hai tài liệu đang mở (tôi đã thử lưu nó dưới dạng docm, quá) hoặc Normal.dotm.Không có nỗ lực nào trong số những lần thử này dường như gọi macro khi tôi nhấn control-z trong tài liệu từ. Cứu giúp? –
@DGGenuine: Ghi đè lệnh 'EditUndo' cũng sẽ hoạt động trong Word 2007 và 2010. Macro cần nằm trong mô-đun trong tài liệu hiện tại hoặc trong mẫu được đính kèm. Bạn có chắc chắn rằng bạn chưa cấu hình lại phím tắt của mình? Có bất kỳ add-in khác hoạt động lộn xộn xung quanh với các lệnh Word tích hợp không? –