No need to mess around with ArcObjects and .NET. You can create your own edit stack. You can simply set a global variable that tracks the edits and is then accessible to other buttons.
For example, depending on the complexity of the edits performed by your add-in, you could have a global list to which you append information about the edits.
Here's an example of a simple edit button (it just buffers the selected features) with undo and redo buttons. Note that these are not the built-in undo/redo buttons, but Add-In buttons that you create. The edits here will be in a separate stack from the built-in edits.
import arcpy
import pythonaddins
MXD = arcpy.mapping.MapDocument('CURRENT')
FN_SHAPE = 'SHAPE@'
undo_stack = list()
redo_stack = list()
class MakeEdits(object):
def __init__(self):
self.enabled = True
self.checked = False
def onClick(self):
lyr = pythonaddins.GetSelectedTOCLayerOrDataFrame()
fid_set = arcpy.Describe(lyr).FIDSet
if fid_set == '':
count = 0
else:
count = len(fid_set.split(';'))
if count > 0:
global undo_stack
fn_oid = arcpy.Describe(lyr).OIDFieldName
with arcpy.da.UpdateCursor(lyr, [fn_oid, FN_SHAPE]) as cur:
for row in cur:
undo_stack.append((lyr, fn_oid, row[0], row[1]))
row[1] = row[1].buffer(500)
cur.updateRow(row)
arcpy.RefreshActiveView()
class RedoEdits(object):
def __init__(self):
self.enabled = True
self.checked = False
def onClick(self):
global undo_stack
global redo_stack
if len(redo_stack) > 0:
edit = redo_stack.pop()
arcpy.SelectLayerByAttribute_management(edit[0], 'CLEAR_SELECTION')
wc = '{} = {}'.format(edit[1], edit[2])
with arcpy.da.UpdateCursor(edit[0], FN_SHAPE, wc) as cur:
for row in cur:
edit_out = list(edit[:-1])
edit_out.append(row[0])
undo_stack.append(edit_out)
row[0] = edit[3]
cur.updateRow(row)
break
arcpy.RefreshActiveView()
class UndoEdits(object):
def __init__(self):
self.enabled = True
self.checked = False
def onClick(self):
global undo_stack
global redo_stack
if len(undo_stack) > 0:
edit = undo_stack.pop()
arcpy.SelectLayerByAttribute_management(edit[0], 'CLEAR_SELECTION')
wc = '{} = {}'.format(edit[1], edit[2])
with arcpy.da.UpdateCursor(edit[0], FN_SHAPE, wc) as cur:
for row in cur:
edit_out = list(edit[:-1])
edit_out.append(row[0])
redo_stack.append(edit_out)
row[0] = edit[3]
cur.updateRow(row)
break
arcpy.RefreshActiveView()
return