Hello people,
I'm working on an application that run as an AutoCAD palette. Among various things, my palette has some buttons working as shortcut for some command line like "PAN" ou "ZOOM W", some other making more complex things, including waiting for the user to select a point with Editor.GetPoint(), and a Cancel button.
Each of my control button begin with a cancellation command to be sure we clear any running command before going for the next.
Before AutoCAD 2015, my cancellation sub was a call to acedPostCommand("CANCELCMD") and everything was fine. It's not supported anymore and I have some trouble to replace it with something working every time.
For now, my solution is to send some escape character with Document.SendStringToExecute. The last case that doesn't work is when there is a pending command line and I try to cancel it before making an Editor.GetPoint in the same call. The cancellation fails and the GetPoint immediately returns a PromptStatus.Cancel. If I make a cancellation alone (with my cancel button), it works.
What do I miss ?
Here's a code example for clarity :
public partial class PaletteTest : UserControl { public PaletteTest() { InitializeComponent(); } private void buttonPANcmd_Click(object sender, EventArgs e) { CancelRunningCommand(); ApplicationServices.Application.DocumentManager.MdiActiveDocument.SendStringToExecute("_.PAN ", true, false, true); } private void buttonZoomWcmd_Click(object sender, EventArgs e) { CancelRunningCommand(); ApplicationServices.Application.DocumentManager.MdiActiveDocument.SendStringToExecute("_.ZOOM _.W ", true, false, true); } private void buttonGetPoint_Click(object sender, EventArgs e) { Document doc = ApplicationServices.Application.DocumentManager.MdiActiveDocument; Editor ed = doc.Editor; ApplicationServices.Application.DocumentManager.MdiActiveDocument.Window.Focus(); Debug.WriteLine("quiescent 1 : {0}", doc.Editor.IsQuiescent); CancelRunningCommand(); // Fail to cancel any pending command line Debug.WriteLine("quiescent 2 : {0}", doc.Editor.IsQuiescent); PromptPointResult ppr = ed.GetPoint("click somewhere"); // immediately return PromptStatus.Cancel if there is a pending command line if (ppr.Status != PromptStatus.OK) return; MessageBox.Show(string.Format("clicked on {0:N4}, {1:N4}", ppr.Value.X, ppr.Value.Y)); } private void buttonCancel_Click(object sender, EventArgs e) { CancelRunningCommand(); } private void CancelRunningCommand() { Document doc = ApplicationServices.Application.DocumentManager.MdiActiveDocument; string cmds = (string)ApplicationServices.Application.GetSystemVariable("CMDNAMES"); string esc = string.Empty; if (cmds.Length > 0) { // case of a command line command to be cancelled int cmdNum = cmds.Split('\\').Length; for (int i = 0; i < cmdNum ; i++) { esc += "\x03"; } doc.SendStringToExecute(esc, true, false, true); } else if (! doc.Editor.IsQuiescent) { // case of a prompt to be cancelled esc = "\x03"; doc.SendStringToExecute(esc, true, false, true); } else { // nothing to cancel } } }
Firstly, since this is really a generic AutoCAD .NET API programming topic, you may want to post to .NET forum to reach more interested readers.
I think the issues is due to the Editor.GetXxxx() being called after SendStringToExecute() (inside the CancalRunningCommand() method). In this case, the code in the buttonGetPoint_Click() keeps going without waiting for the SendStringToExecute() being completed (that is, the SendStringToExecute() only get run when the code is waiting for user to pick point.
SendStringToExecute() should be only used as the last line of code being executed between an full cycle of user interaction with AutoCAD.
Because PaletteSet is a floating UI that should be running in application context and interact with active document out of multiple documents, this poses a challenge for us programmers to code it correctly in some cases, such as what you are intended to do: if AutoCAD is in the middle of command, what user action on PaletteSet can do to the active command.
While there is possibility to do this or that, I'd first follow known AutoCAD behaviour, Take AutoCAD's property paletteset window as example. It has "Select Object" and "Quick Select" button, so that user can click them and select in Editor. However, if there is a command active, such as waiting user to enter keyword or to pick point, clicking these 2 buttons does nothing (or prompt for invalid input), the active command still waiting to be continued/cancelled by user. If we think about it, it is only logically make sense: a command against the current drawing is waiting to be completed, and should not be unconditionally cancelled by outside app easily.
Another example: opening Design Center. We all know we can insert block from design center by dragging a block/layer/text style... from design center into current drawing, right? Well, if there is command active in AutoCAD, one cannot drag anything into current drawing.
So, I think, instead of trying to cancel whatever active command in custom paletteset's action, the paletteset action should first check if there is active command running (and waiting for user input). If yes, the paletteset action should be aborted with or without prompting user. That is, our custom paletteset should behave the same way as AutoCAD built-in PaletteSet, so that user is not surprised by our custom app.
That my thought after trying different code based on yours.
Norman Yuan