Search code examples
xmlvbams-accessms-access-2010ms-access-2013

where to write callback functions for custom ribbon


I have a custom ribbon which has only 1 button as a test, when i use a macro in the onAction attribute it works just fine but when i add a normal callback function i wrote it just can't find it. so the question is where to write these callbacks (in my case i made a module and made my callback function a public sub in that module).

here is the xml code:

    <Relationship Id="customUIRelID" Type="http://schemas.microsoft.com/office/2006/relationships/ui/extensibility" Target="customUI/customUI.xml"/>
    <ribbon startFromScratch="true">
        <tabs>
            <tab id="CustomTab" label="My Tab">
                <group id="SimpleControls" label="My Group">
                    <button id="Button1" imageMso="HappyFace" size="large" label="Large Button" onAction="ribbonOpenForm"/>
                </group>
            </tab>
        </tabs>
    </ribbon>
</customUI> 

and the callback function is :

Public Sub ribbonOpenForm(control As IRibbonControl)
    Dim formName As String
    formName = control.Tag
    If formName = "" Then
        MsgBox "No Name"
        Exit Sub
    End If
    DoCmd.OpenForm formName
End Sub

when i add a smale edit in the xml code which is : onAction="ribbonOpenForm" i get a new error.

the first error:

enter image description here

the error after the edit:

enter image description here


Solution

  • Well, the first and best answer? Don't use call backs. The BIG downfall of using callbacks is of course the code you write HAS to be in a standard global code module. Such code can NOT be the forms code module. Given that buttons, and even custom menu bars (in the past) in MOST cases will and do run code in the form? Then the stands to reason that you want to do the same for a custom ribbon - especially one for a given form.

    So, a call back function in the ribbon is defined this way:

     onAction="MyDelete"
    

    You THEN need a Public sub (note I said Public Sub) in a standard code module. Such code CAN NOT be placed in the forms code module (where as I noted in most cases it belongs and is needed).

    But, when you place a button, custom menu bar, or even macro code (not VBA), you can have that "thing" execute code IN THE FORMS code module!!!

    The way you do this is to use a expression like this:

    onAction="=MyDelete()"
    

    Note the use of the "=" sign, and the (). now?

    You don't need a callback function - you just place this code in the CURRENT fomrs code module:

    Public Function MyDelete()
    
      dim lngID as Long
      lngID = me!id
      bla bla bla.
    

    but, it gets better. the OTHER great feature is that you can pass values to the function.

    So, you could say do this:

    <button id="MyDelete" label="Delete Record"
        imageMso="Delete" size="large"
        onAction="=MyDelete('Staff','tblStaff')"
        supertip="Delete this record"
     />
    

    And our public function the form could be this:

    Public Function MyDelete(strPrompt As String, strTable As String)
      Dim strSql        As String
      Dim f             As Form
      Set f = Screen.ActiveForm
      If MsgBox("Delete this " & strPrompt & " record?", _
                    vbQuestion + vbYesNoCancel, "Delete?") = vbYes Then
    
          currentdb.Execute "DELETE * from " & strTable & " WHERE ID = " & me!id
    

    So in above, we passed the "prompt text" and the table name. Now above is a bit lame, since if the code is ALREADY in the current form, then you could of course delete the current record - but it shows the idea of how we can pass values from the Ribbon to a function.

    BONUS PART!!!!

    If the pubic function DOES NOT exist in the form, then a global public function with the same name in a standard (non forms) code module is run. So, in effect, you could have 5 forms - the delete code could be a global function, but one form with special needs simply has a public function with the same name IN THE FORMS code module - it will run if found in the form.

    It is ALSO very interesting to note that using =MyPublicFunctionNameGoesHere()

    is ALSO the exact SAME format used by right click and custom menu bars. So, if you were converting existing menu bar code to a ribbon? You use the SAME function and syntax - and all of your code stays in that given form. And like menu bars, if the function does not exist in the form, the the global function of same name is used. Thus once again, you can build a menu (or ribbon) that uses "mostly" all the same functions such as delete, or add reocrds, but for speical forms with differnt needs, then you can put those functiosn in the form - that way a ribbon can work on many different forms with the same "options" in the ribbon - but VERY differing code will run based on the form that is currently open and has focus.

    So, if you use the format "=MyPublicFunction()", then you don't need nor are using a call back, and better yet, the function name can now be placed in the form.

    As noted, if you use a call back, then such code (a sub) can NOT be placed in the current forms code module - it has to go in a standard code module. Not so with function calls - they can be freely be placed in the forms code module, or in a global one.