how to get the object associated with a context menu in an office add-in - vb.net

I have a simple COM add-in for office that I am developing (for access specifically).
I have added a custom commandbarbutton item to the context menu that pops up when you right click on an object in the navigation pane.
This works fine. The debug code I added runs (currently just a msgbox command). The one thing I cannot figure out how to do though is get an object for the object bound to the context menu.
I would like this to happen; I right click on a module in the navigation pane, select my new menu option, and then a message box appears with the name of the module that is currently highlighted. How would I go about this?
This is how I am currently handling the event:
Public Sub myEventHandler(ByVal ctrl As CommandBarButton, ByRef CancelDefault As Boolean) Handles contextMenu_navPaneObject.Click, contextMenu_navPaneList.Click
MsgBox(Microsoft.VisualBasic.Information.TypeName(ctrl) & vbCrLf & _
Microsoft.VisualBasic.Information.TypeName(ctrl.Parent) & vbCrLf & _
Microsoft.VisualBasic.Information.TypeName(ctrl.Parent.Parent))
End Sub
contextMenu_navPaneObject and contextMenu_navPaneList are private objects declared using "withevents" and having an object type of commandbarbutton.
Is this the correct way to do what I want, or is there an alternative method I should be using?

Turns out to do what I wanted, I needed to run the following method:
Access.Application.CurrentObjectName()
This returned the name of the item I currently had highlighted.
I hope this helps others!

Related

Access Navigation Subform, recordsource

I am working with MS Access and I am currently trying out the navigation sub-forms. However I am finding it difficult to understand how to simply change the recordsource of a sub form. One of the tabs within my "NavigationSubform" is called "nbCustomerList", which has the target navigation name "CustomerList". Within the CustomerList form, there is a button which when clicked opens a popup which allows you to filter the query on CustomerList. How do I achieve a change to recordsource from an event like this?
Private Sub btnSearch_Click()
On Error GoTo HandleError
If CurrentProject.AllForms("MainMenu").IsLoaded Then
[Forms]![CustomerList].RecordSource = CustomerListFilter()
[Forms]![MainMenu]![NavigationSubform].Requery
End If
''ErrorHandling'''''''''''''''''''''''''''''''''''''''''''''''''''''''
HandleExit:
Exit Sub
HandleError:
MsgBox (Err.Number & ": " & Err.Description)
Resume HandleExit
End Sub
The following test worked for me:
Forms![Navigation Form].NavigationSubform.Form.RecordSource = "SELECT * FROM Rates WHERE ID=2"
Assuming your form design has the default names of [Navigation Form] and NavigationSubform assigned by Access, in your db try:
[Forms]![Navigation Form].NavigationSubform.Form.RecordSource = CustomerListFilter()
Requery command was not necessary.
I don't use Navigation Form design. Keep in mind that no matter how many tabs are set up, only one subform is available at any time. Nature of Navigation Form is that it loads and unloads subforms as called by click on tabs.

CommandBars("Text").Controls not deleted when exiting the document - VBA word add-in

I'm trying to create a add in for MS Word with VBA.
It has a "AutoExec" procedure that creates a new item in the CommandBar("Text") collection (right click menu) and a "AutoExit" that deletes this created item.
As an example, I tried the code below that create an item "How Many Pages?", which executes a macro displaying the number of pages in the active document.
This is the AutoExec Code:
Public Sub AutoExec()
Dim objcommandbutton As CommandBarButton
Call MsgBox("AutoExec")
Set objcommandbutton = Application.CommandBars("Text").Controls.Add _
(Type:=msoControlButton, Before:=1)
objcommandbutton.Caption = "How Many Pages?"
objcommandbutton.OnAction = "HowManyPages"
End Sub
This is the AutoExit Code:
Public Sub AutoExit()
Dim objcommandbutton As CommandBarControl
Call MsgBox("AutoExit")
For Each objcommandbutton In Application.CommandBars("Text").Controls
If objcommandbutton.Caption = "How Many Pages?" Then
objcommandbutton.Delete
End If
Next objcommandbutton
End Sub
This is the Main Macro Code:
Public Sub HowManyPages()
If Documents.Count > 0 Then
Call MsgBox(ActiveDocument.BuiltInDocumentProperties("Number of Pages"))
Else
Call MsgBox("No document is currently active.")
End If
End Sub
When exiting the document, the Button previously added in CommandBars("Text") collection is not deleted. I see this when I open a new blank Word document and the button remains in the right click menu.
I know that the routine is performed correctly because there is a MsgBox instruction to verify it.
This only happen with the AutoExit subroutine of a add-in, that is, loaded as a add-in: running the code in a macro with vba module works fine.
Any help?
When working with the CommandBars object model in Word it's necessary to always specify the Application.CustomizationContext.
Word can save keyboard layouts and CommandBar customizations in various places: the Normal.dotm template, the current template or the current document. The default when you create a CommandBar addition may not be the3 same as the default when trying to delete something.
Since this is an add-in, I assume you want the change for the entire Word environment (any open document). In that case, use the context NormalTemplate. Use this before any calls to CommandBar:
Application.CustomizationContext = NormalTemplate
Note: for saving a customization in the current document: = ActiveDocument; for saving in the template attached to the current document: = ActiveDocument.AttachedTemplate.
I solved my problem with a workaround:
I was trying to "add" a template (.dotm) as a add-in (in the "Templates and Add-ins" window) to use my VBA project in a new document. That's why I was using the AutoExec() and AutoExit() procedures.
But only now I figure out that just "attaching" the .dotm template to the active document (in the same "Templates and Add-ins" window, as show in the figure below) makes the functions Private Sub Document_Open() and Private Sub Document_Close() to run normally. Which solves my problem.
Even so, I think there is a certain "issue" with the AutoExit() procedure when trying to change the CommandBars itens. But that's ok for now.
enter image description here

Context-menu and keyboard shortcut return different results on the same method

I have a vba sub ("sub") in excel 2013, which opens another workbook, reads some data out of it, return this data and close the newopened workbook. It is possible to run this sub via keyboard shortcut and a entry in the context menu.
This call (the "UTILS.sub" this is) works perfectly fine:
' Add the sub-call to a new context menu entry
Call UTILS.addContextMenuEntry("Caption", 2556, "UTILS.sub")
But this call doesn't:
' Add the sub-call to a new keyboard shortcut
App.OnKey "+^{M}", "UTILS.sub"
If i call sub with the keyboard shortcut it breaks without an error. I've managed to work out the specific code line, at which it breakes via debugging:
'[...]
Application.ScreenUpdating = False
' Open the external Workbook
Set wbHandle = Workbooks.Open("wb.xls", ReadOnly:=True)
MsgBox "Debug"
'[...]
wb.xls opens (and displays), but the MsgBox "Debug" does not. Nothing after the "Open"-line does run and no breakpoint after this line will be hit. Another strange thing: If i debug a call of sub with a breakpoint before that line, it all works perfectly.
How to get the sub to run correctly, not regarding wether it was called by a context menu entry or keyboard shortcut?
I'm not exactly sure what the cause of this behavior is, but I suspect that macros called via keyboard shortcuts or context menus are actually passed through Application.Run or something else that can reset the execution state internally.
The simple work-around seems to be to pass execution through a "wrapper" sub:
Public Sub bar()
foo
End Sub
Public Sub foo()
Dim bar As Workbook
Set bar = Workbooks.Open("C:\Book1.xls", ReadOnly:=True)
MsgBox "foo"
End Sub
Launching foo by a keyboard shortcut will not display the message box, but calling bar will.
I've found the answer to my problem by myself: stackoverflow.com/questions/17409524/
Apparently, excel can't handle the "Workbooks.Open()"-method if the sub is called through a keyboard shortcut, which includes the [SHIFT]-key. Solution: Use "Workbooks.Add()" instead.

Using VB .net to click command button in Access

I'm trying to click a button in a form in MS Access with VB .net. However, there isn't much I can find in this area and have a bit of a long way of getting the button. Then I'm stuck - there seems to be no way to activate the click event.
Using :
Imports Microsoft.Office.Interop
I have the following to get the button:
Dim acc As New Access.Application
acc.OpenCurrentDatabase("C:\path\to\db\aDatabase.accdb")
acc.Visible = True
For i = 0 To acc.Forms.Count - 1
If acc.Forms.Item(i).Name = "formName" Then
For j = 0 To acc.Forms.Item(i).Controls.Count - 1
If acc.Forms.Item(i).Controls.Item(j).name = "btnEnter" Then
Dim btn As Access.CommandButton = acc.Forms.Item(i).Controls.Item(j)
'
' click on button??
'
End If
Next
End If
Next
I've had a guess at trying the following:
acc.Application.Run(btn.OnClickMacro)
acc.Application.Run(btn.OnClick)
btn.OnClickMacro
btn.OnClick
btn.performclick()
none of which work.
By default, the click event handler is declared in VBA as
Private Sub Command0_Click()
' do something
End Sub
You won't be able to programmatically click the button outside of Access' VBA code if it's private (unless the developer intentionally declared it public). Best practice is to make a function which is called by the handler, which can be called elsewhere as well, instead of clicking buttons through code.
Private Sub Command0_Click()
DoSomething
End Sub
' you would have a better chance calling this from .NET
Public Sub DoSomething()
' do something
End Sub
If you don't have access to the Access VBA code, outside of .NET you could use something to automate mouse clicks like this: https://autohotkey.com/
I mean, if you have to have Access intslled, open and running, then why is such code not being run from Access? So it does not make a whole lot of sense to call such code from .net.
However, simply make the private sub click as public, and then you can use this form:
MyAccessApp.Forms("main").command44_click
So you don’t have to create any external functions etc., but if you wish to call that code directly then the form MUST be opened, and with a running instance of that application from .net, then the above syntax will work.
I would suggest you just use Access here, and it nots clear why .net is involved.

How to Set Focus in Access Continuous Form (VBA)

Right now it's being ignored. Here's the code at it's most basic, it causes an inescapable scenario currently, but I plan to condition these out. Just need to get the basic setFocus working.
Private Sub fieldbox_LostFocus()
Me.fieldbox.SetFocus
End Sub
In a regular form, it works as expected. When fieldbox loses focus, the focus is set back onto fieldbox.
In a continuous form, it does not work, and the set focus does not happen. This is possibly due to multiple instances of fieldbox existing for each record.
What I'd like is if fieldbox1, 2 and 3 exist on the continuous form, and you click out of fieldbox2, how do I set focus back to fieldbox2?
You need to use the form's BeforeUpdate() event instead of focus:
Private Sub Form_BeforeUpdate(Cancel as Integer)
If RecordOK = False Then
Dim response, strMsg as String
strMsg = "There is data missing from the record. " _
& vbCrLf & "Press Yes to continue, editing. " _
& vbCrLf & "Press No to discard all changes."
Cancel = True
response = MsgBox(strMsg, vbYesNo)
If response <> vbYes
Me.Undo
End If
End If
Code above is not tested, may need some tweaks, paste and see. My recent update provides cleaner handling of the user's response to the dialog box. (You do have Option Explicit set, don't you?!)
A good explanation of this method at the control level is found here. But you may want to use the form event, as above. Sometimes I just temporarily insert Msgbox cues in the events so I can see what is firing when.
Note the dialog box should provide clues on how to avoid wiping the work done so far by a user.