Vba Microsoft Word:如何侦听文档级事件(保护/取消保护)以更新功能区切换按钮?

Vba Microsoft Word:如何侦听文档级事件(保护/取消保护)以更新功能区切换按钮?,vba,ms-word,ribbon,ribbonx,Vba,Ms Word,Ribbon,Ribbonx,PHB希望我为Microsoft Word创建一个功能区切换按钮: 按下时,将编辑限制为填写表单,并在没有密码的情况下保护文档 未按下时,取消对文档的保护(无密码) 我有以下customUI.xml: <customUI xmlns="http://schemas.microsoft.com/office/2006/01/customui" onLoad="RibbonOnLoad"> <commands> <command idMso=

PHB希望我为Microsoft Word创建一个功能区切换按钮:

  • 按下时,将编辑限制为填写表单,并在没有密码的情况下保护文档
  • 未按下时,取消对文档的保护(无密码)
我有以下customUI.xml:

<customUI xmlns="http://schemas.microsoft.com/office/2006/01/customui" onLoad="RibbonOnLoad">
    <commands>
        <command idMso="ProtectOrUnprotectDocument" onAction="ProtectOrUnprotectDocumentOnAction"/>
    </commands>
    <ribbon>
        <tabs>
            <tab id="LawTab" label="Law">
                <group id="ProtectGroup" label="Protect">
                    <toggleButton id="ToggleProtectionButton" imageMso="GreenBall" label="Protection" getPressed="ToggleProtectionButtonGetPressed" onAction="ToggleProtectionButtonOnAction"/>
                    <button id="InvalidateRibbonButton" imageMso="Refresh" label="Invalidate Ribbon" onAction="InvalidateRibbonButtonOnAction"/>
                </group>
            </tab>
        </tabs>
    </ribbon>
</customUI>

以及以下VBA代码:

Private ribbon As IRibbonUI

Sub InvalidateRibbonButtonOnAction(control As IRibbonControl)
    ribbon.Invalidate
End Sub

Sub ProtectOrUnprotectDocumentOnAction(control As IRibbonControl, ByRef cancelDefault)
    ribbon.Invalidate
    cancelDefault = False
End Sub

Sub RibbonOnLoad(ActiveRibbon As IRibbonUI)
    Set ribbon = ActiveRibbon
End Sub

Sub ToggleProtectionButtonGetPressed(control As IRibbonControl, ByRef returnValue)
    returnValue = ActiveDocument.ProtectionType <> wdNoProtection
End Sub

Sub ToggleProtectionButtonOnAction(control As IRibbonControl, ByVal pressed As Boolean)
    If pressed Then
        ActiveDocument.Protect wdAllowOnlyFormFields
    Else
        ActiveDocument.Unprotect
    End If
End Sub
作为IRibbonUI的专用功能区
子无效BBONButtonNoAction(控件作为IRIBONControl)
功能区。无效
端接头
子保护程序UnprotectDocumentOnAction(控件作为IRIBOnControl,ByRef cancelDefault)
功能区。无效
取消默认值=False
端接头
子RibbonLoad(ActiveRibbon作为IRibbonUI)
设置ribbon=ActiveRibbon
端接头
子切换保护按钮按下(控件作为IRIBONCONTROL,ByRef returnValue)
returnValue=ActiveDocument.ProtectionType wdNoProtection
端接头
Sub-ToggleProtectionButtonAction(控件为IRIBOnControl,ByVal按为Boolean)
如果按下,则
ActiveDocument.Protect wdAllowOnlyFormFields
其他的
ActiveDocument.Unprotect
如果结束
端接头
我可以重新调整内置Protector unprotect命令的用途,以便相应的内置按钮使功能区无效,并因此更新我的自定义按钮,但是如果我使用内置任务窗格(查看>限制编辑)或以编程方式(ActiveDocument.protect/unprotect)保护/取消保护,我的自定义按钮将不知道更改。如何侦听文档级事件以保护/取消保护,以便更新切换按钮的状态?

如何

总而言之,通过向功能区XML中添加以下内容(有关详细信息,请参见链接),可以覆盖内置的“图纸保护”按钮以使用代码(这可能会导致按钮切换):


我认为Blackhawk的答案是正确的:覆盖内置命令的
onAction
过程。但是,他的XML示例是针对MS Excel的,在MS Word中不起作用。这很容易调整,但不幸的是,我不知道如何解决这个特殊问题:

但是如果我使用内置的ProtectOrUnprotectDocument按钮来保护/取消保护,我的自定义按钮将不知道更改。如何侦听文档级事件以保护/取消保护,以便更新切换按钮的状态

没有文档级事件,即使使用
with events
应用程序类,它也会响应文档的
保护类型的更改(理论上,您应该可以使用ribbon
.InvalidateControl
方法)

因此,问题(以及可能的解决方案)是,当您可以简单地使用内置按钮并通过自己的过程劫持其功能以根据需要保护/取消保护时,为什么需要一个切换按钮。您甚至可以在自定义菜单中放置内置按钮

然而,这看起来很有希望:

修订版

经过一些讨论和尝试和错误(你自己做了很多这件事,并且发现我做不到的),让我们试试这个对我有用的方法

这是XML(如果使用的是旧版本,则可能需要修改模式)

限制

如果我使用内置任务窗格(查看>限制编辑)或以编程方式(ActiveDocument.protect/unprotect)保护/取消保护,我的自定义按钮将不知道更改


这对于以编程方式应用的保护不起作用。至于Review>Restrict Editing,我认为您只需要像上面我们所做的那样劫持该命令的
onAction
过程,向XML中添加另一个
command
,并将其引用到相同的
onAction
过程。

+1问个好问题。用于功能区操作的资源不多。如果我有几分钟的空闲时间,我会看看是否能找到答案……请在
ToggleProtectionButtonGetPressed
功能中插入一个消息框。您是否能够通过Word中的用户操作调用此函数?我不能这样做。如果你是,请让我知道你是如何做到的,我会继续努力。否则,您的解决方案可能需要一个类似于PowerPoint()所需的加载项,如果它甚至可以响应此特定事件(可能不是)…我创建了一个“失效”功能区按钮。要测试它,请使用内置任务窗格(查看>限制编辑)启动/停止保护。“我的自定义”按钮将忽略实际的保护状态,直到您按下“使功能区无效”按钮。重新调整Protector UnprotectDocument命令的用途将起作用。但只是为了那个命令。如果我使用内置任务窗格(查看>限制编辑)或以编程方式(ActiveDocument.protect/unprotect)保护/取消保护,我的自定义按钮将不知道更改情况。@Homer和David,感谢您的帮助,我想我在查看链接的Excel示例时弄糊涂了。为了子孙后代的利益,我正在更新答案以使用“ProtectOrUnprotectDocument”id。@荷马,为“ReviewForecrictFormat”添加一个额外的命令行怎么样?似乎有一个相当完整的按钮ID列表。我在VBA:'中看不到任何直接可用的事件(仍然没有以编程方式进行保护/取消保护(ActiveDocument.Protect/Unprotect))。我可以将观察者模式拼凑在一起,告诉每个人始终使用一个在幕后调用内置保护/取消保护的层,并且永远不要直接使用内置保护/取消保护…但是没有。@Homer“…但是没有”-同意:PI在引用后更新了我的回调。对于这种特殊情况(ProtectOrUnprotectDocument),重新调整用途
<commands>
    <command idMso="ProtectOrUnprotectDocument" onAction="ToggleProtectionButtonOnAction"/>
</commands>
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
   <customUI onLoad="RibbonOnLoad" xmlns="http://schemas.microsoft.com/office/2009/07/customui">
    <commands>
        <command idMso="ProtectOrUnprotectDocument" onAction="ToggleProtectionButtonOnAction" />
    </commands>
    <ribbon>
        <tabs>
            <tab id="LawTab" label="Law">
                <group id="ProtectGroup" label="Protect">
                    <toggleButton id="ToggleProtectionButton" imageMso="GreenBall" label="Protection" getPressed="ToggleProtectionButtonGetPressed" onAction="ToggleProtectionButtonOnAction"/>
                    <button id="InvalidateButton" imageMso="Refresh" label="Invalidate" onAction="InvalidateButtonOnAction"/>
                </group>
            </tab>
        </tabs>
    </ribbon>
</customUI>
Option Explicit
Dim ribbon As IRibbonUI
Dim protectButton As IRibbonControl
Dim IsProtected As Boolean

Sub InvalidateRibbonButtonOnAction(control As IRibbonControl)
'MsgBox "Invalidate"
    ribbon.Invalidate
End Sub

Sub RibbonOnLoad(ActiveRibbon As IRibbonUI)
'MsgBox "onLoad"
    Set ribbon = ActiveRibbon
    IsThisDocumentProtected
End Sub

Sub ToggleProtectionButtonGetPressed(control As IRibbonControl, ByRef returnValue)
'MsgBox "GetPressed"
    IsThisDocumentProtected
    returnValue = IsProtected
End Sub

Sub ToggleProtectionButtonOnAction(control As IRibbonControl, ByVal pressed As Boolean)
    IsThisDocumentProtected
    If pressed Then
        If Not IsProtected Then
            ActiveDocument.Protect wdAllowOnlyFormFields
        Else
            ActiveDocument.Unprotect
        End If
    Else
        If IsProtected Then
            ActiveDocument.Unprotect
        End If

    End If
    If control.Id = "ProtectOrUnprotectDocument" Then
    '    MsgBox "Got here!"
    '   This will force ribbon invalidate only for the native command
        ProtectOrUnprotectDocumentOnAction control, False
    End If
End Sub


''''' This procedure is NOT a callback, but is called from the callbacks:

Private Sub IsThisDocumentProtected()
'''' Assigns value to module-level boolean variable for use throughout the module
    IsProtected = ActiveDocument.ProtectionType <> wdNoProtection
End Sub

''''' This is NOT a callback, either, but is invoked only for particular control press:
Private Sub ProtectOrUnprotectDocumentOnAction(control As IRibbonControl, ByRef cancelDefault)
    ribbon.Invalidate
    cancelDefault = False
End Sub