Similar to the question Run a Python Script when opening an MXD, I'm looking for a way to run a Python script that is triggered when the "Save" command/button is pressed.

I've read the Creating a Python add-in application extension help for building a Python Add-In, but I don't see an interface in the Extension class that triggers upon Save, only close.

Is there something I might be overlooking? Otherwise, what are my alternative options other than ArcObjects, which is a road I am not willing to explore for this idea?


I found something in ArcObjects that will do the job. Thanks to This Post by Kirk Kuykendall as implemented on This Post by Rebecca Zeckoski. This is very counter-intuitive, the interface to find button clicks is ICustomizationFilter, which detects when a command is about to run (any command that implements ICommand I think).

Using Visual Studio I created an ArcMap addin and selected Extension and AutoLoad, then added a class alongside which implements ICustomizationFilter, using the LockCustomization method of the application the class is linked to the event then call the python script by (in this case) shell() other methods are discussed in this post; I'm not sure if you can make an ICommandItem from a python add-in but that would be how I would execute custom ArcObjects code.

Public Class Extension1 
    Inherits ESRI.ArcGIS.Desktop.AddIns.Extension
    'I am not using this event'
    Public Sub New()
    End Sub

    Protected Overrides Sub OnStartup()
        WireDocumentEvents() ' uncomment this, it is here by default'
    End Sub

    Protected Overrides Sub OnShutdown()
    End Sub

    Private Sub WireDocumentEvents()
        AddHandler My.ArcMap.Events.NewDocument, AddressOf ArcMapNewDocument ' this is a default event'
        AddHandler My.ArcMap.Events.OpenDocument, AddressOf ArcMapDocumentOpen ' add this event'
    End Sub

    Private Sub ArcMapNewDocument()
        ' Wire the event here in case the user starts with a blank'
        ' map and saves... this event does not survive a file::open'
        Dim pCustFlt As ESRI.ArcGIS.Framework.ICustomizationFilter = New CustFlt
        My.ArcMap.Application.LockCustomization("myLock", pCustFlt)
    End Sub
    Private Sub ArcMapDocumentOpen()
        ' When the document is opened wire the events to it'
        ' otherwise they dissapear after a new MXD is opened.'
        Dim pCustFlt As ESRI.ArcGIS.Framework.ICustomizationFilter = New CustFlt
        My.ArcMap.Application.LockCustomization("myLock", pCustFlt)
    End Sub
End Class
Class CustFlt   ' new class to implement the filter'
    Implements ESRI.ArcGIS.Framework.ICustomizationFilter

    Public Function OnCustomizationEvent(custEventType As ESRI.ArcGIS.Framework.esriCustomizationEvent, eventCtx As Object) As Boolean Implements ESRI.ArcGIS.Framework.ICustomizationFilter.OnCustomizationEvent
        ' modified from Rebecca Zeckoskis' post http://rzeckoskiengineering.blogspot.com.au/2012/06/capturing-button-clicks-in-arcobjects.html
        ' inspired by Kirk Kuykendalls' post https://gis.stackexchange.com/questions/8149/can-i-listen-to-the-icommandbar-or-icommand-onclick-event

        If custEventType = ESRI.ArcGIS.Framework.esriCustomizationEvent.esriCEInvokeCommand Then
            ' if it is a call to invoke a command then find the command
            ' that is being invoked (executed)
            Dim cmd As ESRI.ArcGIS.Framework.ICommandItem
            cmd = TryCast(eventCtx, ESRI.ArcGIS.Framework.ICommandItem)

            ' find the name of the command, there's a whole bunch of them
            ' at http://resources.arcgis.com/en/help/arcobjects-net/conceptualhelp/index.html#//00010000029s000000
            ' search by tool caption to find others, you can use either the name or GUID/CLSID
            If cmd.Name = "File_Save" Then
                MsgBox("Customization Save") ' run your python here
                ' if you have a custom ArcObjects tool here you could make a new
                ' ICommandItem and execute, not sure if that works for python
                ' addins. You can call the shell with the path like this:
                Shell("c:\path\to\your\script.py", AppWinStyle.Hide, False) ' returns an integer
                ' see https://stackoverflow.com/questions/13807860/execute-python-script-from-vb-net
            End If
        End If

        Return False

    End Function
End Class
|improve this answer|||||

I think your best bet will be to create a custom button that saves your map document - mxd.save() - as well as whatever operations you wish.

|improve this answer|||||
  • Like a 'save with benefits' button.. that would work but I can see what he's trying to do; the best way to ensure a script is run is to not give the operator the option... with a 'special save' button, how can you ensure that the user has clicked that one and not just closed the window and hit yes on the save dialog? – Michael Stimson Mar 4 '15 at 23:17
  • That's a good suggestion if there are no other options. But as @MichaelMiles-Stimson mentioned, the whole point is to provide a "pain free" experience that just happens behind the scenes. – RyanKDalton Mar 11 '15 at 21:05

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.