Editor.Command from palette

This widget could not be displayed.

Editor.Command from palette

Anonymous
Not applicable

Hey all,

 

My question is very similar to this question: https://forums.autodesk.com/t5/net/editor-command-from-palette/td-p/6376430 

Q: Can I run a Editor.Command from a Palette, without using the construction of creating a CommandMethod and using SendStringToExecute()?

 

In our scenario, it's not possible to use the CommandMethod/SendStringToExecute construction, because it's not synchronously executed.

 

 

The problem we're trying to solve is the following:

Scenario
Via a palette we insert a component, this insert component will do all kinds of things in acad (via the acad API).

We surround this logic with an undo group, to create this undo group we use "Autodesk.AutoCAD.Internal.Utils.SetUndoMark( ... );".

 

Then at the end of everything, if the insert failed, we want to rollback all our changes.

To do this we just need to do "Undo 1", due to the undo group.

To do the "Undo 1" we use "SendStringToExecute" since there is no ACAD API to do the undo synchronously (as far as we know). 

 

Problem

When you scroll in acad during the insert.

When the insert fails

Then ACaD will first handle the scroll
And then ACaD will handle the undo 1

 

Result -> Only the scroll is undone
Expected -> The complete insert changes (which are grouped) are undone

 

Why creating a new command won't work

We want to keep our application decoupled from ACAD, we don't want to write all our insert component logic in an ACAD command. 
We merely use ACAD as a visualizer, all our application logic doesn't know it's executed in ACAD. 

 

There is also another post about this scroll issue interacting with the SendString: 

https://forums.autodesk.com/t5/net/problem-with-execute-sendstringtoexecute/td-p/5186201 

 

0 Likes
Reply
688 Views
8 Replies
Replies (8)

_gile
Mentor
Mentor

Hi,

Editor.Command can only run in document context this is why it cannot be directly called from a palette (modeless UI) which is application context.

You do not show the code you run in AutoCAD, but typically, undoing actions is managed with a Transaction by commiting or aborting it.



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Anonymous
Not applicable

Is there any way to execute an undo synchronously while not in document context? 

0 Likes

_gile
Mentor
Mentor

As said upper, aborting a transaction (i.e., not commiting it) rolls back all the changes made within this transaction.



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

0 Likes

Anonymous
Not applicable

Thanks for the reply Gile!

I created a small code snippet which represents a simplification of our code.

 

...
var success = true;
using ( var undoGroup = new HandleUndoGroup( "InsertComponent" ) )
{
	success = InsertComponent(Component);
	
	// The call below will update the model in the Acad word.
    // To do this we draw geomerty/connections which depend on the component added.
	// This is done by performing multiple transactions.
	// Here we don't know which transactions will be performed to do this. 
	success &= SyncAcadModel(_system);
	...
}
   
if ( !success )
{
     UndoLastActions( 1, true );
}
...

 

 

 

As you can see here it's, sadly, not easy for us to perform the undo-action by aborting the transaction, since the insert component exists of a dynamic set of transactions (depending on the component which is added).

 

When, during the insert, the user performs a scroll in acad the undo 1 will undo the scroll i.o. the insert component group. 

Is there a way to solve this?

0 Likes

Anonymous
Not applicable

For completeness here you have the UndoLastActions code:

public void UndoLastActions( int rollbackCount, bool clearRedoStack )
{
	if ( rollbackCount > 0 )
	{
		var command = $"_.UNDO {rollbackCount}";
		Document.SendStringToExecute( $"{command} ", true, false, false );
	}
}
0 Likes

_gile
Mentor
Mentor

Hi,

did you try something like this:

using (var topTr = eb.TransactionManager.StartTransaction())
using ( var undoGroup = new HandleUndoGroup( "InsertComponent" ) )
{
	success = InsertComponent(Component);
	
	// The call below will update the model in the Acad word.
    // To do this we draw geomerty/connections which depend on the component added.
	// This is done by performing multiple transactions.
	// Here we don't know which transactions will be performed to do this. 
	success &= SyncAcadModel(_system);
	...
        if (success)
            topTr.Commit();
}


Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Anonymous
Not applicable

Thanks for the response, Gilles!
My response is quite late, some other activities were raised in priority. 

We were not aware it was possible to create a top-level transaction like this.
To add this to our application was still quite a challenge since we have a custom undo mechanism in place (to connect our application to the undo of Acad). But we succeeded to add this. 

0 Likes

Anonymous
Not applicable

I do have 1 more question related to this solution.
I also wrapped my transaction with a document lock, see code below:

 

            using ( Document.LockDocument( DocumentLockMode.Write, actionName, actionName, false ) )
            {
                using ( var transaction = Document.Database.TransactionManager.StartTransaction() )
                {
                    var success = action();
                    if ( success )
                    {
                        transaction.Commit();
                    }
                    else
                    {
                        // Make sure this action is not in the undo stack
                    }

                    return success;
                }
            }

 



When I don't commit my transaction I still see the action is the undo stack.
Q: Is it possible to remove this action from the undo stack when the action failed? 

0 Likes