vba - 关闭文档并重新打开后自定义 UI 编辑器功能区未加载
问题描述
我需要一些有关 Word 中功能区的自定义 UI 编辑器代码的帮助。我在 Word 2010 中使用的相同代码在 Word 2019 中不再适用。当我根据模板创建文档时,功能区就在那里并且可以工作。我保存文档并关闭它。当我重新打开功能区时,就像“死了”。它没有被激活,代码不再运行。
Word 2019 发生了什么变化?我需要做什么来纠正这个问题?
这是自定义 UI 代码:
<customUI xmlns="http://schemas.microsoft.com/office/2009/07/customui">
<!--This is the Expense Template-->
<ribbon>
<tabs>
<tab id="customTab3" label="Expense">
<group id="customGroup110" label="Expense/Disbursement Calculate">
<button id="customButton110" size="large" label="Expense/Disbursement Calculate" imageMso="CreateReport" onAction="ExpenseCalculate" />
</group>
</tab>
</tabs>
</ribbon>
</customUI>
这是模板中的代码:
Sub ExpenseCalculate(control As IRibbonControl)
' Edited Code On: 2/6/2012
' Edited Code By: Sheila Shines
' Code Change: Added code to test to see what Template a user is in before running code
Dim rowz As Integer
Dim theRow As Integer
Dim rT As Integer
Dim myTemplate As Template
Set myTemplate = ActiveDocument.AttachedTemplate
If UCase(myTemplate.Name) = "EXPENSE.DOTM" Or UCase(myTemplate.Name) = "EXPENSE.DOT" Then
'MOVES TO BEGINNING OF DOCUMENT
Selection.HomeKey unit:=wdStory, Extend:=wdMove
'LINE DOWN
Selection.MoveDown unit:=wdLine, Count:=1, Extend:=wdMove
'LINE DOWN UNTIL INTO A TABLE
While Selection.Information(wdWithInTable) = 0
Selection.MoveDown unit:=wdLine, Count:=1, Extend:=wdMove
Wend
'MOVE TO START OF ROW OF THE TABLE
Selection.StartOf unit:=wdRow, Extend:=wdMove
'SELECTING TABLE
ActiveDocument.Tables(1).Select
'NUMBER OF ROWS IN THE TABLE
rowz = Selection.Information(wdMaximumNumberOfRows)
'MOVING LEFT ONE PLACE
Selection.MoveLeft unit:=wdCharacter, Count:=1, Extend:=wdMove
'ROW CONTAINING THE BEGINNING OF THE SELECTION
theRow = Selection.Information(wdStartOfRangeRowNumber)
'MOVING DOWN ONE LINE AT A TIME THROUGH TABLE
While theRow < rowz
Selection.MoveDown unit:=wdLine, Count:=1, Extend:=wdMove
theRow = Selection.Information(wdStartOfRangeRowNumber)
Wend
'MOVING OVER TWO CELLS
Selection.Move unit:=wdCell, Count:=2
'DELETING INFORMATION OUT OF CELL IF ANY
Selection.Range.Delete
rowz = rowz - 1
rT = Right$(Str$(rowz), Len(Str$(rowz)) - 1)
'INSERTING FIELD INTO TABLE
Selection.InsertFormula Formula:="=sum(c2:c" & CInt(rT) & ")", NumberFormat:="$#,##0.00;($#,##0.00)"
'PRINTING DOCUMENT
ActiveDocument.PrintOut
Else
MsgBox "You need to be in an Expense template in order to use this macro", vbCritical, "In wrong template"
End
End If
End Sub
Here is the solution that I have tried
What happens to the Word session ribbon after closing and reopening a document with a custom ribbon?
https://stackoverflow.com/questions/57841404/what-happens-to-the-word-session-ribbon-after-closing-and-reopening-a-document-w
解决方案
您尝试的解决方案看起来是一个真正的组合,绝对不是我推荐的东西。但由于它部分地为您工作,它证实了我第一次阅读您的问题时的直觉,即您的功能区需要失效(刷新)。
这里有一个答案可以提供您需要的代码,尽管我有一些问题。
在这一点上,我必须解释我没有在文档模板中放置功能区或代码(我将所有代码放在全局模板中,然后使用功能区回调来确定哪些控件应该可见/启用)所以我不是确定这是否适合您。
要完成这项工作,您需要在加载时获得指向功能区的指针。为此,您需要一个 onLoad 回调和相应的功能区 xml:
<customUI xmlns="http://schemas.microsoft.com/office/2009/07/customui" onLoad="ribbonOnLoad">
回调模块(顺便说一句,我冒昧地重写了您的代码):
Option Explicit
'CopyMemory for ribbon retrieval
#If Win64 Then
Declare PtrSafe Sub CopyMemory Lib "kernel32" _
Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As LongPtr)
#Else
Public Declare Sub CopyMemory Lib "kernel32" _
Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)
#End If
Private rbnUI As IRibbonUI
Public Property Get RibbonUI() As IRibbonUI
#If Win64 Then
Dim lngRbnPtr As LongPtr
#Else
Dim lngRbnPtr As Long
#End If
Dim objRibbon As Object
If rbnUI Is Nothing Then
'the pointer is lost so retrieve it from the registry
lngRbnPtr = GetSetting("Templates", "Ribbon", "Ribbon Pointer WD")
CopyMemory objRibbon, lngRbnPtr, 4
Set rbnUI = objRibbon
' clean up invalid object
CopyMemory objRibbon, 0&, 4
Set objRibbon = Nothing
End If
Set RibbonUI = rbnUI
End Property
Public Property Set RibbonUI(ribbon As IRibbonUI)
#If Win64 Then
Dim lngRbnPtr As LongPtr
#Else
Dim lngRbnPtr As Long
#End If
Set rbnUI = ribbon
lngRbnPtr = ObjPtr(ribbon)
'save pointer to registry for safe keeping
SaveSetting "Templates", "Ribbon", "Ribbon Pointer WD", lngRbnPtr
End Property
Private Sub ribbonOnLoad(ribbon As IRibbonUI)
' Store pointer to IRibbonUI
Set RibbonUI = ribbon
End Sub
Public Sub ribbonInvalidate()
On Error GoTo ProcError
RibbonUI.Invalidate
ProcExit:
'Clean up
On Error Resume Next
Exit Sub
ProcError:
If Err.Number = 91 Then
MsgBox "Unrecoverable Ribbon Error" & vbCrLf & "" & vbCrLf & _
"Unable to refresh the ribbon. Please save and reopen " & Application.name & _
".", vbOKOnly + vbExclamation, "Ribbon Error"
Else
'add your own
End If
End Sub
Sub ExpenseCalculate(control As IRibbonControl)
Dim myTemplate As Template
Set myTemplate = ActiveDocument.AttachedTemplate
If UCase(myTemplate.name) = "EXPENSE.DOTM" Or UCase(myTemplate.name) = "EXPENSE.DOT" Then
'INSERTING FIELD INTO TABLE
With ActiveDocument.Tables(1).Rows.Last.Cells(3)
.Range.Delete
.Formula Formula:="=sum(above)", NumFormat:="$#,##0.00;($#,##0.00)"
End With
'PRINTING DOCUMENT
ActiveDocument.PrintOut
Else
MsgBox "You need to be in an Expense template in order to use this macro", vbCritical, "In wrong template"
End
End If
Set myTemplate = Nothing
End Sub
接下来,您需要一种使功能区无效的方法。为此,我使用了一个与 Word 的应用程序事件挂钩的类模块。这使我能够在每次ActiveDocument
更改时使功能区无效,即创建或打开文档,在打开的文档之间切换。
Option Explicit
Public WithEvents appWord As Word.Application
Private Sub appWord_DocumentChange()
InvalidateRibbon
End Sub
加载模板时需要初始化类模块。这可以使用 AutoExec 例程来完成。我喜欢将实际初始化保存在一个单独的例程中,以便我可以从全局错误处理例程中调用它。
Public wordEvents As clsWordEvents
Public Sub AutoExec()
instantiateEventHandler
End Sub
Public Sub instantiateEventHandler()
If wordEvents Is Nothing Then
Set wordEvents = New clsWordEvents
Set wordEvents.appWord = Word.Application
End If
End Sub
推荐阅读
- ruby-on-rails - 如何获取数组中的下一个和上一个元素,Ruby
- swift - 编译器错误:无效的库文件 - CoreLocation
- spring - 如何从控制器发送 JSON 响应?
- javascript - 在 mongodb 中使用 where
- arrays - 简单的阵列操作 MIPS 组装
- php - 我应该如何在 Laravel 中为新类别创建第三个表
- android - 谷歌放置自动完成不提供一些有效字符串的建议
- wpf - 动画用户控件
- javascript - React 中的 Konva 无限网格
- ruby-on-rails - 更新 Amazon RDS SSL/TLS 证书 - Elastic Beanstalk