可以在Word或Excel中创建撤消事务吗? (VSTO) [英] Can I create an undo transaction in Word or Excel? (VSTO)

查看:220
本文介绍了可以在Word或Excel中创建撤消事务吗? (VSTO)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我注意到Project 2007具有允许可以撤销的操作被放置在单个堆栈项中的功能,或者撤消事务。 例如:

  Application.OpenUndoTransaction创建6个任务
Dim i As Integer
对于i = 1至6
ActiveProject.Tasks.AddUndoMe &安培; i
下一个
Application.CloseUndoTransaction

这意味着用户可以在单个撤消操作中撤消所有操作,而不是6次。



这将是非常好的在Word和/或Excel中实现,因为我正在做一些VSTO中的一切可以一次进行多次更改,如果用户在出现错误时必须单击撤消多次,那么这对用户来说有点恼人。虽然这些具体功能似乎不存在,但有人知道/如何/如何以某种方式完成?

解决方案

您可以通过覆盖VBA中的Undo和Redo命令例程来模拟Word中的事务行为(尽管如此,我不认为使用VSTO可以覆盖内置的Word命令)。交易的开始标记为添加书签,结束标记为删除书签。



当调用undo时,我们检查交易标记书签是否存在,重复撤消,直到标记消失。重做工作方式相同。该机制支持对文档内容进行的所有修改的事务性撤销/重做。但是,为了允许撤消/重做对文档属性的修改,需要使用SetCustomProp宏来实现特殊的机制。文档属性不应该直接设置,而只能通过这个宏。



更新:我忘了清楚地提到这种方法只适用于键盘快捷键和菜单命令,点击工具栏按钮仍然执行单步撤消。因此,我们决定将工具栏按钮替换为自定义按钮。该代码一直在使用Word 2003(它没有用Word 2007进行测试,所以准备好惊喜);

  Option Explicit 

'Undo机制的字符串常量
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_

'---- -------------------------------------------------- -----------------------------
'过程:EditUndo
'用途:宏的原子消除
'注意:此宏只捕获菜单命令和键盘快捷键
'不是工具栏命令
'------------------- -------------------------------------------------- --------------
Public Sub EditUndo()'catchches Ctrl-Z

'On Error Resume Next
Dim bRefresh As Boolean
bRefresh = Application.ScreenUpdating
Application.ScreenUpdating = False

Do
如果ActiveDocument.Bookmarks.Exists(BM_DOC_PROP_CHANGE)然后
Dim strPropName As String
Dim strOldValue As String

strPropName = ActiveDocument.Bookmarks(BM_DOC_PROP_NAME).Range。文本
strOldValue = ActiveDocument.Bookmarks(BM_DOC_PROP_OLD_VALUE).Range.Text
ActiveDocument.CustomDocumentProperties(strPropName).Value = strOldValue
如果

循环While(ActiveDocument。 Undo = True)_
和ActiveDocument.Bookmarks.Exists(BM_IN_MACRO)

Application.ScreenUpdating = bRefresh
End Sub

'---- -------------------------------------------------- -----------------------------
'过程:EditRedo
'目的:宏的原子重做
注意:此宏只捕获菜单命令和键盘快捷键
'不是工具栏命令
'---------------------- -------------------------------------------------- -----------
Public Sub EditRedo()'捕获Ctrl-Y

Dim bRefresh As Boolean
bRefresh = Application.ScreenUpdating
Application.ScreenUpdating = False

Do
如果ActiveDocument.Bookmarks.Exists(BM_DOC_PROP_CHANGE)然后
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

循环while(ActiveDocument.Redo = True)_
和ActiveDocument.Bookmarks.Exists(BM_IN_MACRO)

Application.ScreenUpdating = bRefresh

End Sub

'----------------------- -------------------------------------------------- ----------
'过程:SetCustomProp
'目的:设置自定义文档属性
'--------------- -------------------------------------------------- ------------------
公共函数SetCustomProp(oDoc As Document,strName As String,strValue As String)

Dim strOldValue As String

错误GoTo existsAlready
strOldValue =
oDoc.CustomDocumentProperties.Add _
名称:= strName,LinkToContent:= False,Value:= Trim(strValue ),_
类型:= msoPropertyTypeString
GoTo exitHere

existsAlready:
strOldValue = oDoc.CustomDocumentProperties(strName).Value
oDoc.CustomDocumentProperties(strName ).Value = strValue

exitHere:
'支持撤消/重做文档属性的更改
'开错误Resume Next
Dim bCalledWithoutUndoSupport As Boolean

如果不是ActiveDocument.Bookmarks.Exists(BM_IN_MACRO)然后
ActiveDocument.Range.Bookmarks.Add BM_IN_MACRO,ActiveDocument.Range
bCalledWithoutUndoSupport = True
End If

Dim oRange As Range
设置oRange = ActiveDocument.Range

oRange.Collapse wdCollapseEnd
oRange.Text =
oRange.Bookmarks.AddDocPropDummy_,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) 。删除

设置oRange = ActiveDocument.Bookmarks(BM_DOC_PROP_NEW_VALUE).Range
ActiveDocument.Bookmarks(BM_DOC_PROP_NEW_VALUE).Delete
如果Len(oRange.Text)> 0然后oRange.Delete

设置oRange = ActiveDocument.Bookmarks(BM_DOC_PROP_OLD_VALUE).Range
ActiveDocument.Bookmarks(BM_DOC_PROP_OLD_VALUE)。删除
如果Len(oRange.Text)> 0然后oRange.Delete

设置oRange = ActiveDocument.Bookmarks(BM_DOC_PROP_NAME).Range
ActiveDocument.Bookmarks(BM_DOC_PROP_NAME).Delete
如果Len(oRange.Text)> 0然后oRange.Delete

设置oRange = ActiveDocument.Bookmarks(DocPropDummy _)。范围
ActiveDocument.Bookmarks(DocPropDummy _)。删除
如果Len(oRange.Text )> 0然后oRange.Delete

如果bCalledWithoutUndoSupport和ActiveDocument.Bookmarks.Exists(BM_IN_MACRO)然后
ActiveDocument.Bookmarks(BM_IN_MACRO).Delete
End If

结束功能

'-------------------------------------- ---------------------------------------------
'过程:SampleUsage
'目的:演示一个交易
'-------------------------------- -------------------------------------------------- -
Private Sub SampleUsage()

错误恢复下一步

'标记开始的事务
ActiveDocument.Range.Bookmarks.Add BM_IN_MACRO

Selection.Text =Hello World
'做其他东西

'标记结束
ActiveDocument.Bookmarks(BM_IN_MACRO).Delete

End Sub


I notice that Project 2007 has the functions that allow operations that can be undone to be placed in a single stack item, or "undo transaction". For example:

Application.OpenUndoTransaction "Create 6 tasks"
Dim i As Integer
For i = 1 To 6
    ActiveProject.Tasks.Add "UndoMe " & i
Next
Application.CloseUndoTransaction 

What this means is that the user can undo all of the actions in a single undo action, rather than 6 times.

This would be great to implement in Word and/or Excel, as I'm doing some things in VSTO that make multiple changes at once, and it'll be a bit annoying for the user if they have to click on Undo several times if they make a mistake. Although those specific functions don't appear to exist, does anyone know if / how this can be done in some way?

解决方案

You can simulate transactional behavior in Word by overwriting the Undo and Redo command routines in VBA (I don't think that overwriting built-in Word commands is possible using VSTO alone, though). The start of a transaction is marked by adding a bookmark, the end is marked by removing the bookmark.

When calling undo, we check whether the transaction mark bookmark is present and repeat the undo until the marker is gone. Redo is working the same way. This mechanism supports transactional undo/redo of all modifications done to the document content. However, to allow undo/redo of modifications to the document properties a special mechanism needs to be implemented using the SetCustomProp macro. Document properties should not be set directly but via this macro only.

Update: I forgot to clearly mention that this approach only works with the keyboard shortcuts and the menu commands, clicking the toolbar button still does a single-step undo. We therefore decided to replace the toolbar buttons with custom ones. The code has been in use for quite a while With Word 2003 (it's not tested with Word 2007, so be prepared for surprise ;)

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

这篇关于可以在Word或Excel中创建撤消事务吗? (VSTO)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆