TL;DR: 2010-es Excelnél újabb verzióban soha ne használd a Workbook_SheetBeforeRightClick()
event handlert arra, hogy saját CommandBart hozz létre – helyette ott a Custom UI editor for Microsoft Office, amivel ugyan csak bedrótozott hierarchiát tudsz csinálni, viszont cserébe nem fagy majd random szénné alatta a host környezet.
A dolog úgy indult, hogy egy Office update után elkezdett furán viselkedni a VBA kód pár táblában. Jó szokás szerint a hibajelenségnek semmi köze nem volt a hiba okához, a Microsoftos alkalmazásnak pedig esze ágában sem volt bármiféle notificationt küldeni, hogy neki XY kóddarabbal lenne baja, sokkal inkább a számukra már sokszor bevált utat választba, nemes egyszerűséggel vagy rommá fagyasztotta a futtató környezetet, vagy a teljes Excel UI elfelejtett a végfelhasználóval kommunikálni. Mutatom:
Excel 2010+ event handler madness from Gabor Penoff on Vimeo.
A videóban jól látszik, hogy a testData tábla kiválasztása után az megnyílik, majd az Excel előbb mintha elfelejtené a screent update-elni, később viszont teljesen meggárgyul és a saját UI elemei is megszűnnek működni. Nézzük végig, mi történik belül. A 2. kattintásra a standard context menünek kellene előbújnia, azonban én ezt elkapom és a saját cuccaimat pakolom a gyári menü helyére. Mindez úgy történik, hogy aWorkbook_SheetBeforeRightClick()
event handlert használom:
Private Sub Workbook_SheetBeforeRightClick(ByVal Sh As Object, ByVal Target As Excel.Range, Cancel As Boolean) rightClickMenuShow (rightClickMenuTitle) Cancel = RightClickCancel End Sub
rightClikMenuShow()
törli az előző custom menüt, majd újra létrehozza és megjeleníti:
Sub rightClickMenuShow(rightClickMenuName As String) RightClickCancel = True Call rightClickMenuDelete(rightClickMenuName) Call rightClickMenuCreate(ActiveSheet) CommandBars(rightClickMenuTitle).ShowPopup End Sub
Sub rightClickMenuDelete(rightClickMenuName As String) Dim bar As CommandBar For Each bar In CommandBars If UCase(Trim(bar.Name)) = UCase(Trim(rightClickMenuTitle)) Then bar.Delete Next bar End Sub
Sub rightClickMenuCreate(S_Caller As Worksheet) Dim rightClickMenuName As String Dim rightClickMenuIndex As Long rightClickMenuName = rightClickMenuTitle Call rightClickMenuDelete(rightClickMenuName) Application.CommandBars.Add Name:=rightClickMenuName, Position:=msoBarPopup rightClickMenuIndex = 0 rightClickMenuIndex = rightClickMenuIndex + 1 CommandBars(rightClickMenuName).Controls.Add Type:=msoControlButton, Before:=rightClickMenuIndex With CommandBars(rightClickMenuName).Controls(rightClickMenuIndex) .FaceId = 263 .Style = msoButtonIconAndCaption .Caption = "Excel's &Default Shortcut Menu" .OnAction = "ShowDefaultRightClickMenu" End With rightClickMenuIndex = rightClickMenuIndex + 1 CommandBars(rightClickMenuName).Controls.Add Type:=msoControlButton, Before:=rightClickMenuIndex With CommandBars(rightClickMenuName).Controls(rightClickMenuIndex) .Style = msoButtonCaption .Caption = "Freeze me please" .OnAction = "myTestSub" .BeginGroup = True End With End Sub
myTestSub()
makrót elindító event handler mechanizmus. Miután ebben hozzá nem nyúlok a képernyő frissítését szabályozó Application.ScreenUpdating
metódushoz, nézzük meg, mit csinál a myTestSub()
:
Sub myTestSub() Dim f As Variant f = Application.GetOpenFilename If f = False Then MsgBox "No file selected." Else Workbooks.Open Filename:=f, ReadOnly:=True End If End Sub
Workbook_SheetBeforeRightClick()
event handlerben egy CommandBars(rightClickMenuTitle).ShowPopup()
hívással. A helyes megoldás ilyenkor az, hogy ezt a popup generátort úgy ahogy van kidobod és létrehozol egy XML-t, ami a fenti két eljárás meghívásához legyártja majd az UI eleme(ke)t a jobb klikkre megjelenő context menüben:
<customUI xmlns="http://schemas.microsoft.com/office/2009/07/customui"> <contextMenus> <contextMenu idMso="ContextMenuCell"> <menu id="appMenu" label="engine" insertBeforeMso="Cut"> <button id="item_id1" label="(Do not) freeze me please" onAction="myTestSub"/> </menu> </contextMenu> </contextMenus> </customUI>
Sub myTestSub(control As IRibbonControl)