000

Index Labels

A Simple Undoable Custom Command

.
When doing AutoCAD programming, you might very likely come across this situation: your code may have to manipulate objects in drawing, such as creating new entities, or transforming existing entities, or changing something like current layer, text style.... However, after all the changes are being made, you may want user to confirm the changes and give the user an option to drop/cancel the changes.

Since your own code causes the changes, surely you can right the code to reverse the changes back. But the code to reversing things back could be very tedious to write.

All AutoCAD users know the "UNDO" command (or simply press "Ctrl+Z") is very useful to reverse changes made by previous commands back.

When doing .NET programming, the Transaction class does provides a mechanism of undoing changes back by rolling back or aborting the working transaction. One of my previous post touched this topic here. However, if the process of changing is quite complicated and some changes must be first applied to the drawing database before it can be presented to user to decide whether the changes should stay or to be rolled back, then using Transaction as the mechanism of undoing in code might be quite difficult to implement. So, why not utilize AutoCAD's built-in "UNDO" command to make the coding easier?

I recently worked on a project for a drafting tool, which starts a custom command and then leads user to create a serious entities and the end of the process. Since the user is guided via command line prompt, based on previous steps, the entities created have to be added into drawing database in order to give user clear visual feedback on what have been done in the process. At the end, I thought it would be better to allow user to decide he/she wants to cancelled the command has done so far. This this particular case, writing code to reverse back the changes are quite difficult, if not impossible. Well, I can let the command end and just tell user that if he/she still can execute UNDO command to reverse back the changes done by the custom command. However, it would be much better the custom command itself can undo the changes based on user interaction. Thus, I wrote some code and tried with satisfactory result, which is presented in this post.

Here what I did is to use AutoCAD built-in UNDO command to set an UNDO mark and to undo the changes back to the UNDO mark. However, the trick is how the call UNDO command to set UNDO mark before the main process in the custom command and how to call UNDO command to roll changes back when necessary.

The code presented here is pretty self-descriptive. So, no more explanation is needed. Here is the code:

First, this is a class to manipulate drawing database:

    1 using System.Windows.Forms;
    2 using Autodesk.AutoCAD.ApplicationServices;
    3 using Autodesk.AutoCAD.DatabaseServices;
    4 using Autodesk.AutoCAD.EditorInput;
    5 using Autodesk.AutoCAD.Geometry;
    6 
    7 namespace UndoableCommand
    8 {
    9     public class DoWorkTool
   10     {
   11         private Document _dwg;
   12 
   13         public DoWorkTool(Document dwg)
   14         {
   15             _dwg = dwg;
   16         }
   17 
   18         public bool CreateSomething()
   19         {
   20             int count = AddEntities();
   21 
   22             if (count > 0)
   23             {
   24                 string msg = string.Format("{0} circle{1} created." +
   25                     "\n\nDo you want to keep {2}?",
   26                     count, count > 1 ? "s" : "", count > 1 ? "them" : "it");
   27 
   28                 return MessageBox.Show(msg, "Do work tool question",
   29                     MessageBoxButtons.YesNo,
   30                     MessageBoxIcon.Question) == DialogResult.Yes;
   31             }
   32             else
   33             {
   34                 return true;
   35             }
   36         }
   37 
   38         //This method creates circles in a loop
   39         private int AddEntities()
   40         {
   41             int count = 0;
   42 
   43             using (Transaction tran =
   44                 _dwg.TransactionManager.StartTransaction())
   45             {
   46                 BlockTableRecord model = (BlockTableRecord)tran.GetObject(
   47                     SymbolUtilityServices.GetBlockModelSpaceId(_dwg.Database),
   48                     OpenMode.ForWrite);
   49 
   50                 while (true)
   51                 {
   52                     Point3d centrePt;
   53                     double radius;
   54                     if (!CircleCetreRadius(out centrePt, out radius)) break;
   55 
   56                     CreateCircle(centrePt, radius, model, tran);
   57                     tran.TransactionManager.QueueForGraphicsFlush();
   58                     _dwg.Editor.UpdateScreen();
   59 
   60                     count++;
   61                 }
   62 
   63                 tran.Commit();
   64             }
   65 
   66             return count;
   67         }
   68 
   69         private bool CircleCetreRadius(out Point3d centre, out double rad)
   70         {
   71             centre=new Point3d();
   72             rad=double.MinValue;
   73 
   74             PromptPointOptions pOpt = new PromptPointOptions(
   75                 "\nPick circle centre:");
   76             PromptPointResult pRes = _dwg.Editor.GetPoint(pOpt);
   77             if (pRes.Status != PromptStatus.OK) return false;
   78             centre = pRes.Value;
   79 
   80             PromptDoubleOptions dOpt = new PromptDoubleOptions(
   81                 "\nEnter circle radius");
   82             dOpt.AllowNegative = false;
   83             dOpt.AllowNone = false;
   84             dOpt.AllowZero = false;
   85             PromptDoubleResult dRes = _dwg.Editor.GetDouble(dOpt);
   86             if (dRes.Status != PromptStatus.OK) return false;
   87             rad = dRes.Value;
   88 
   89             return true;
   90         }
   91 
   92         private void CreateCircle(
   93             Point3d centrePt, double radius,
   94             BlockTableRecord model, Transaction tran)
   95         {
   96             Circle c = new Circle();
   97             c.Center = centrePt;
   98             c.Radius = radius;
   99             c.SetDatabaseDefaults(_dwg.Database);
  100 
  101             model.AppendEntity(c);
  102             tran.AddNewlyCreatedDBObject(c, true);  
  103         }
  104     }
  105 }

Then, here is the CommandClass that defines the "undoable" custom command MyCmd:

    1 using Autodesk.AutoCAD.ApplicationServices;
    2 using Autodesk.AutoCAD.EditorInput;
    3 using Autodesk.AutoCAD.Runtime;
    4 
    5 [assembly: CommandClass(typeof(UndoableCommand.MyCommands))]
    6 
    7 namespace UndoableCommand
    8 {
    9     public class MyCommands
   10     {
   11         private static bool _validCall = false;
   12 
   13         [CommandMethod("MyCmd")]
   14         public static void RunMyCommand()
   15         {
   16             Document dwg = Application.DocumentManager.MdiActiveDocument;
   17             Editor ed = dwg.Editor;
   18             dwg.CommandEnded += dwg_CommandEnded;
   19 
   20             //Set UNDO mark
   21             dwg.SendStringToExecute("UNDO M ", true, false, false);
   22         }
   23 
   24         static void dwg_CommandEnded(object sender, CommandEventArgs e)
   25         {
   26             if (e.GlobalCommandName.ToUpper() == "MYCMD")
   27             {
   28                 //Run my real command
   29                 Document dwg = Application.DocumentManager.MdiActiveDocument;
   30                 Editor ed = dwg.Editor;
   31 
   32                 ed.WriteMessage("\nUndo mark has been set.");
   33 
   34                 //Run the command that does real work with its result
   35                 //might be undone
   36                 _validCall = true;
   37                 dwg.SendStringToExecute("MyRealCmd ", true, false, false);
   38             }
   39         }
   40 
   41         [CommandMethod("MyRealCmd")]
   42         public static void DoWork()
   43         {
   44             Document dwg = Application.DocumentManager.MdiActiveDocument;
   45             Editor ed = dwg.Editor;
   46 
   47             //Prevent this command being used without UNDO mark is set
   48             if (!_validCall)
   49             {
   50                 ed.WriteMessage(
   51                     "\ncommand \"MyRealCmd\" cannot be executed directly. " +
   52                     "Use command \"MyCmd\" instead.");
   53                 return;
   54             }
   55 
   56             //Do real work here and with return indicating
   57             //whether UNDO is required
   58             DoWorkTool work = new DoWorkTool(dwg);
   59             bool keep = work.CreateSomething();
   60 
   61             //Remove the commandEnded handler
   62             dwg.CommandEnded -= dwg_CommandEnded;
   63             _validCall = false;
   64 
   65             if (!keep)
   66             {
   67                 //Undo if it is needed
   68                 dwg.SendStringToExecute("UNDO B ", true, false, false);
   69             } 
   70         }
   71     }
   72 }

Go to this video clip to see the undoable command in action.


Blog Archive

Labels

.NET Programming 2D Drafting 3D design 3D Modeling 3D models 3D Printing 3D rendering 3D scanning 3D Sketch Inventor 3D visualization 3D Web App 3ds Max ACC Add-in Development Additive Manufacturing AEC Technology affordable Autodesk tools AI Design AI in CAD AI in Manufacturing AI Tools AR architectural design architectural modeling architectural preservation architectural visualization Architecture architecture design Architecture Engineering Architecture Firm Architecture Productivity architecture software Artificial Intelligence As-Built Model augmented reality AutoCAD AutoCAD advice AutoCAD API AutoCAD Basics AutoCAD Beginners AutoCAD Civil 3D AutoCAD Civil3D AutoCAD commands AutoCAD efficiency AutoCAD features AutoCAD File Management AutoCAD Layer AutoCAD learning AutoCAD print settings AutoCAD productivity AutoCAD Teaching AutoCAD Techniques AutoCAD tips AutoCAD tools AutoCAD training. AutoCAD tricks AutoCAD Tutorial AutoCAD workflow AutoCAD Xref Autodesk Autodesk 2025 Autodesk 2026 Autodesk 3ds Max Autodesk AI Autodesk AI Tools Autodesk Alias Autodesk AutoCAD Autodesk BIM Autodesk BIM 360 Autodesk Certification Autodesk Cloud Autodesk Construction Cloud Autodesk Docs Autodesk Dynamo Autodesk features Autodesk Forge Autodesk FormIt Autodesk Fusion 360 Autodesk InfraWorks Autodesk Inventor Autodesk Inventor Frame Generator Autodesk Inventor iLogic Autodesk License Autodesk Navisworks Autodesk news Autodesk plugins Autodesk Recap Autodesk Revit Autodesk Software Autodesk Takeoff Autodesk Tips Autodesk training Autodesk update Autodesk Upgrade Autodesk Vault Autodesk Video Autodesk Viewer Automation Automation Tutorial automotive design automotive visualization Backup Basic Commands Basics Beginner Beginner Tips Big Data BIM BIM 360 BIM collaboration BIM Compliance BIM Coordination BIM Data BIM for Infrastructure BIM Implementation BIM Library BIM Management BIM modeling BIM software BIM Standards BIM technology BIM tools BIM Trends BIM workflow Block Editor Building Maintenance Building Systems Building Technology ByLayer CAD CAD API CAD Automation CAD commands CAD comparison CAD Customization CAD Data Management CAD Design CAD Evolution CAD File Size Reduction CAD Integration CAD line thickness CAD management CAD modeling CAD Optimization CAD plugins CAD Productivity CAD Security CAD Skills CAD software CAD software 2026 CAD software training CAD technology CAD Tips CAD Tools CAD workflow car design software Case Study CGI design Civil 3D civil engineering Clash Detection Class-A surfacing clean CAD file cleaning command client engagement Cloud CAD Cloud Collaboration Cloud design platform Cloud Engineering Cloud Management Cloud Storage Cloud-First collaboration command abbreviations Complex Renovation concept car conceptual workflow construction Construction Analytics Construction BIM Construction Cloud Construction Planning Construction Technology contractor tools Contractor Workflow Contraints Cost Effective Design cost estimation Create resizable blocks CTB STB Cybersecurity Data Backup data management Data Protection Data Reference Data Security Data Shortcut Design Automation Design Collaboration Design Comparison Design Coordination design review Design Rules design software design software tips Design Technology Design Tools Design Workflow design-to-construction Designer Tools Digital Construction Digital Construction Technology Digital Design Digital engineering digital fabrication Digital Manufacturing digital marketing digital takeoff Digital Twin Digital Twins digital workflow Drafting Standards Drawing Automation Dref Dynamic Block Dynamic Block AutoCAD Dynamic Blocks Dynamic doors Dynamic windows Dynamo automation early stage design eco design editing commands Energy Analysis energy efficiency Engineering Engineering Automation engineering data Engineering Design Engineering Innovation Engineering Productivity engineering software Engineering Technology engineering tools Engineering Tools 2025 Engineering Workflow Excel Export Workflow Express Tools External Reference Facility Management Fast Structural Design Field Documentation File Optimization File Recovery Forge Development Forge Viewer FreeCAD Fusion 360 Fusion 360 API Fusion 360 tutorial Future Skills Generative Design Geospatial Data GIS Global design teams green building Green Technology Grips Handoff heavy CAD file Heavy CAD Files heritage building conservation HVAC Design Tools HVAC Engineering Hydraulic Modeling iLogic Import Workflow Industry 4.0 infrastructure design Infrastructure Monitoring Infrastructure Planning Infrastructure Technology InfraWorks Insight interactive presentation Interior Design Inventor Inventor API Inventor Drawing Template Inventor Frame Generator Inventor Graphics Issues Inventor IDW Inventor Tips Inventor Tutorial IoT ISO 19650 Keyboard Shortcuts Large Projects Laser Scan Learn AutoCAD Licensing Linked Models Machine Learning in CAD maintenance command Management Manufacturing Innovation Mapping Technology marketing visuals Mechanical Design Mechanical Engineering MEP Modeling Mesh-to-BIM Metal Structure Model Management Model Optimization Modular Housing Multi Office Workflow Multi-User Environment Navisworks Best Practices Net Zero Design ObjectARX .NET API Open Source CAD Organization OVERKILL OVERKILL AutoCAD Palette parametric design parametric family PDF PDM system PlanGrid Plot Style AutoCAD Plugin Tutorial point cloud Post Construction Practice Drawing preconstruction workflow Predictive Maintenance Prefabrication Printing Quality Product Design Product Development product lifecycle product rendering Productivity productivity tools professional printing Professional Tips project management Project Management Tools PTC Creo PURGE PURGE AutoCAD realistic rendering ReCap reduce CAD file size rendering engine rendering software Renovation Project Renovation Workflow Resizable Block restoration workflow Revit Revit add-ins Revit API Revit automation Revit Best Practices Revit Family Revit integration Revit MEP Revit Performance Revit Phasing Revit Scripting Revit skills Revit Tips Revit tutorial Revit Workflow Ribbon ROI Scale Autodesk screen Secure Collaboration Sensor Data Sheet Metal Design Sheet Metal Tricks shortcut keys Shortcuts Siemens NX Simulation Sketch Small Firms Smart Architecture Smart Block Smart Building Design Smart City Smart Factory Smart Infrastructur Software Compliance Software Management Software Update SolidWorks Startup Design Steel Structure Design Structural Optimization Subscription Value sustainability sustainable design Sustainable Manufacturing team training guide Technical Drawing time saving tools toolbar Troubleshooting Tutorial urban planning User Interface (UI) Vault Best Practices Vault Lifecycle Vault Mistakes vehicle modeling virtual reality visualization workflow VR VR Tools VRED Water Infrastructure Water Management What’s New in Autodesk Workbook workflow Workflow Automation Workflow Optimization Worksets Worksharing Workspace XLS Xref