Сообщения запроса обычно читают данные из моделей представлений, созданных прослушивателями событий. Прослушиватели событий обычно выполняют логику на основе решений, которые были приняты моделью команд. Обычно это включает обновление моделей представления или пересылку обновлений другим компонентам.
Таким образом, механизм создания и получения представлений полностью зависит от вас. (jpa, данные весны, mybatis, jdbc и т. д.) Хорошим примером проекта аксонов является https://github.com/idugalic/digital-restaurant
Можно моделировать транзактное поведение в Word путем перезаписи стандартных программ команды Undo и Redo в VBA (я не думаю, что перезапись встроенных команд Word является возможным использованием один только VSTO, хотя). Запуск транзакции отмечен путем добавления закладки, конец отмечен путем удаления закладки.
При вызове отмены мы проверяем, присутствует ли закладка метки транзакции и является повторением отмена, пока маркера не не стало. Восстановление работает тот же путь. Этот механизм поддерживает транзакционную отмену/восстановление всех модификаций, сделанных к содержанию документа. Однако для разрешения отмены/восстановления модификаций к свойствам документа специальный механизм должен быть реализован с помощью макроса SetCustomProp. Свойства документа не должны быть установлены непосредственно, но через этот макрос только.
Обновление: Я забыл ясно упоминать, что этот подход только работает с сочетаниями клавиш и командами меню, нажимание кнопки на панели инструментов все еще делает одноэтапную отмену. Мы поэтому решили заменить кнопки на панели инструментов пользовательскими. Код использовался долгое время С Word 2003 (он не тестируется с Word 2007, так быть подготовленным к удивлению ;)
Option Explicit
' string constants for Undo mechanism
Public Const BM_IN_MACRO As String = "_InMacro_"
Public Const BM_DOC_PROP_CHANGE As String = "_DocPropChange_"
Public Const BM_DOC_PROP_NAME As String = "_DocPropName_"
Public Const BM_DOC_PROP_OLD_VALUE As String = "_DocPropOldValue_"
Public Const BM_DOC_PROP_NEW_VALUE As String = "_DocPropNewValue_"
'-----------------------------------------------------------------------------------
' Procedure : EditUndo
' Purpose : Atomic undo of macros
' Note: This macro only catches the menu command and the keyboard shortcut,
' not the toolbar command
'-----------------------------------------------------------------------------------
Public Sub EditUndo() ' Catches Ctrl-Z
'On Error Resume Next
Dim bRefresh As Boolean
bRefresh = Application.ScreenUpdating
Application.ScreenUpdating = False
Do
If ActiveDocument.Bookmarks.Exists(BM_DOC_PROP_CHANGE) Then
Dim strPropName As String
Dim strOldValue As String
strPropName = ActiveDocument.Bookmarks(BM_DOC_PROP_NAME).Range.Text
strOldValue = ActiveDocument.Bookmarks(BM_DOC_PROP_OLD_VALUE).Range.Text
ActiveDocument.CustomDocumentProperties(strPropName).Value = strOldValue
End If
Loop While (ActiveDocument.Undo = True) _
And ActiveDocument.Bookmarks.Exists(BM_IN_MACRO)
Application.ScreenUpdating = bRefresh
End Sub
'-----------------------------------------------------------------------------------
' Procedure : EditRedo
' Purpose : Atomic redo of macros
' Note: This macro only catches the menu command and the keyboard shortcut,
' not the toolbar command
'-----------------------------------------------------------------------------------
Public Sub EditRedo() ' Catches Ctrl-Y
Dim bRefresh As Boolean
bRefresh = Application.ScreenUpdating
Application.ScreenUpdating = False
Do
If ActiveDocument.Bookmarks.Exists(BM_DOC_PROP_CHANGE) Then
Dim strPropName As String
Dim strNewValue As String
strPropName = ActiveDocument.Bookmarks(BM_DOC_PROP_NAME).Range.Text
strNewValue = ActiveDocument.Bookmarks(BM_DOC_PROP_NEW_VALUE).Range.Text
ActiveDocument.CustomDocumentProperties(strPropName).Value = strNewValue
End If
Loop While (ActiveDocument.Redo = True) _
And ActiveDocument.Bookmarks.Exists(BM_IN_MACRO)
Application.ScreenUpdating = bRefresh
End Sub
'-----------------------------------------------------------------------------------
' Procedure : SetCustomProp
' Purpose : Sets a custom document property
'-----------------------------------------------------------------------------------
Public Function SetCustomProp(oDoc As Document, strName As String, strValue As String)
Dim strOldValue As String
On Error GoTo existsAlready
strOldValue = ""
oDoc.CustomDocumentProperties.Add _
Name:=strName, LinkToContent:=False, Value:=Trim(strValue), _
Type:=msoPropertyTypeString
GoTo exitHere
existsAlready:
strOldValue = oDoc.CustomDocumentProperties(strName).Value
oDoc.CustomDocumentProperties(strName).Value = strValue
exitHere:
' support undo / redo of changes to the document properties
'On Error Resume Next
Dim bCalledWithoutUndoSupport As Boolean
If Not ActiveDocument.Bookmarks.Exists(BM_IN_MACRO) Then
ActiveDocument.Range.Bookmarks.Add BM_IN_MACRO, ActiveDocument.Range
bCalledWithoutUndoSupport = True
End If
Dim oRange As Range
Set oRange = ActiveDocument.Range
oRange.Collapse wdCollapseEnd
oRange.Text = " "
oRange.Bookmarks.Add "DocPropDummy_", oRange
oRange.Collapse wdCollapseEnd
oRange.Text = strName
oRange.Bookmarks.Add BM_DOC_PROP_NAME, oRange
oRange.Collapse wdCollapseEnd
oRange.Text = strOldValue
oRange.Bookmarks.Add BM_DOC_PROP_OLD_VALUE, oRange
oRange.Collapse wdCollapseEnd
oRange.Text = strValue
oRange.Bookmarks.Add BM_DOC_PROP_NEW_VALUE, oRange
oRange.Bookmarks.Add BM_DOC_PROP_CHANGE
ActiveDocument.Bookmarks(BM_DOC_PROP_CHANGE).Delete
Set oRange = ActiveDocument.Bookmarks(BM_DOC_PROP_NEW_VALUE).Range
ActiveDocument.Bookmarks(BM_DOC_PROP_NEW_VALUE).Delete
If Len(oRange.Text) > 0 Then oRange.Delete
Set oRange = ActiveDocument.Bookmarks(BM_DOC_PROP_OLD_VALUE).Range
ActiveDocument.Bookmarks(BM_DOC_PROP_OLD_VALUE).Delete
If Len(oRange.Text) > 0 Then oRange.Delete
Set oRange = ActiveDocument.Bookmarks(BM_DOC_PROP_NAME).Range
ActiveDocument.Bookmarks(BM_DOC_PROP_NAME).Delete
If Len(oRange.Text) > 0 Then oRange.Delete
Set oRange = ActiveDocument.Bookmarks("DocPropDummy_").Range
ActiveDocument.Bookmarks("DocPropDummy_").Delete
If Len(oRange.Text) > 0 Then oRange.Delete
If bCalledWithoutUndoSupport And ActiveDocument.Bookmarks.Exists(BM_IN_MACRO) Then
ActiveDocument.Bookmarks(BM_IN_MACRO).Delete
End If
End Function
'-----------------------------------------------------------------------------------
' Procedure : SampleUsage
' Purpose : Demonstrates a transaction
'-----------------------------------------------------------------------------------
Private Sub SampleUsage()
On Error Resume Next
' mark begin of transaction
ActiveDocument.Range.Bookmarks.Add BM_IN_MACRO
Selection.Text = "Hello World"
' do other stuff
' mark end of transaction
ActiveDocument.Bookmarks(BM_IN_MACRO).Delete
End Sub
Excel имеет некоторую (ограниченную) встроенную поддержку отмены и восстановления как часть его архитектуры VBA.
Я не знаком с vsto, таким образом, я не знаю, выручит ли это Вас, но можно смотреть на это ТАК вопрос для получения дополнительной информации.
Я долго пережевывал это. Вот моя попытка использовать скрытый документ, а затем захватить WordOpenXML из скрытого документа и поместить его в настоящий документ, когда это необходимо для выполнения любого количества действий VSTO за одну отмену.
//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();
}
}
Вот класс 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();
}