0

As I discovered in a previous question:

AutoCad Command Rejected "Undo" when using Application.Invoke()

it appears sending commands such c:wd_insym2 (ACad Electrical command) cannot be called synchronously as it calls additional commands such as Undo, causing it to fail.

However, I need to store the EntityID of the entity I have just created with the command, using either the Lisp (entlast) or Autodesk.AutoCad.Internal.Utils.EntLast(). Obviously if I send my command asynchronously this will not give me the correct result.

Maxence suggested using the doc.CommandEnded handler, however I cannot imagine how this will fit in my program flow, as I need to execute each command individually and then store the new EntityID in a .NET variable.

Is there ANY way for me to either send such commands synchronously without running into reentrancy issues, or alternatively send commands asynchronously and wait for them to execute before continuing?

1 Answer 1

1

Have you tried Editor.CommandAsync (AutoCAD 2015 and +):

[CommandMethod("CMD1")]
public async void Command1()
{
  Document doc = Application.DocumentManager.MdiActiveDocument;
  Editor ed = doc.Editor;

  await ed.CommandAsync("_CMD2");

  ed.WriteMessage("Last entity handle: {0}", Utils.EntLast().Handle);
}

[CommandMethod("CMD2")]
public void Command2()
{
  Document doc = Application.DocumentManager.MdiActiveDocument;
  Database db = doc.Database;
  using (Transaction tr = db.TransactionManager.StartTransaction())
  {
    var line = new Line(new Point3d(), new Point3d(10, 20, 30));
    var currentSpace = (BlockTableRecord) tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
    currentSpace.AppendEntity(line);
    tr.AddNewlyCreatedDBObject(line, true);
    tr.Commit();
  }
}

If you want to do this in an older version of AutoCAD, it will be more complicated:

List<ObjectId> ids;

[CommandMethod("CMD1")]
public void Cmd1()
{
  Document doc = Application.DocumentManager.MdiActiveDocument;
  ids = new List<ObjectId>();
  doc.CommandEnded += Doc_CommandEnded;
  doc.SendStringToExecute("_CMD2 0 ", false, false, true);
}

private void Doc_CommandEnded(object sender, CommandEventArgs e)
{
  if (e.GlobalCommandName != "CMD2") return;

  ids.Add(Utils.EntLast());

  var doc = (Document) sender;
  if (ids.Count < 10)
  {
    double angle = ids.Count * Math.PI / 10;
    doc.SendStringToExecute("_CMD2 " + Converter.AngleToString(angle) + "\n", false, false, true);
  }
  else
  {
    doc.CommandEnded -= Doc_CommandEnded;
    doc.Editor.WriteMessage("\nHandles: {0}", string.Join(", ", ids.Select(id => id.Handle.ToString())));
  }
}

[CommandMethod("CMD2")]
public void Cmd2()
{
  Document doc = Application.DocumentManager.MdiActiveDocument;
  Database db = doc.Database;
  PromptDoubleResult pdr = doc.Editor.GetAngle("\nAngle: ");
  if (pdr.Status == PromptStatus.Cancel) return;

  using (Transaction tr = db.TransactionManager.StartTransaction())
  {
    var line = new Line(new Point3d(), new Point3d(Math.Cos(pdr.Value), Math.Sin(pdr.Value), 0));
    var currentSpace = (BlockTableRecord) tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
    currentSpace.AppendEntity(line);        
    tr.AddNewlyCreatedDBObject(line, true);
    tr.Commit();
  }
}
Sign up to request clarification or add additional context in comments.

4 Comments

thanks for that. Didn't know the Await command even existed until now!
I am using AutoCad 2013. What is the equivalent of Editor.CommandAsync()?
how can this be achieved using AutoCad 2013?
I have updated my answer for AutoCAD versions before 2015

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.