Namespace: Autodesk.AutoCAD.DatabaseServices
Assembly: AcDbMgd.dll
The Database class exposes numerous events that fire when database objects are created, modified, or deleted. These events enable reactive programming patterns where your code responds automatically to changes in the drawing.
Key Concept: Database events allow you to monitor and react to changes in the drawing database without polling. They're essential for maintaining data integrity, synchronization, and implementing custom behaviors.
Events that fire when objects are added, modified, or erased.
Events related to transaction lifecycle.
Events that fire during drawing save and load operations.
Events for tracking database modifications.
| Event | Description |
|---|---|
ObjectAppended |
Fires when an object is added to the database |
ObjectErased |
Fires when an object is erased |
ObjectModified |
Fires when an object is modified |
ObjectReappended |
Fires when an erased object is unerased |
ObjectUnappended |
Fires when an appended object is removed |
ObjectOpenedForModify |
Fires when an object is opened for write |
BeginSave |
Fires before drawing is saved |
SaveComplete |
Fires after drawing is saved |
BeginDeepClone |
Fires before deep clone operation |
BeginDeepCloneTranslation |
Fires during deep clone translation |
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Runtime;
public class DatabaseEventHandler
{
private Database _db;
public void RegisterEvents()
{
Document doc = Application.DocumentManager.MdiActiveDocument;
_db = doc.Database;
_db.ObjectAppended += OnObjectAppended;
}
public void UnregisterEvents()
{
if (_db != null)
{
_db.ObjectAppended -= OnObjectAppended;
}
}
private void OnObjectAppended(object sender, ObjectEventArgs e)
{
Document doc = Application.DocumentManager.MdiActiveDocument;
Editor ed = doc.Editor;
using (Transaction tr = _db.TransactionManager.StartTransaction())
{
DBObject obj = tr.GetObject(e.DBObject.ObjectId, OpenMode.ForRead);
ed.WriteMessage($"\n>>> Object Added: {obj.GetType().Name}");
if (obj is Entity ent)
{
ed.WriteMessage($" on layer '{ent.Layer}'");
}
tr.Commit();
}
}
}
[CommandMethod("STARTEVENTMON")]
public void StartEventMonitoring()
{
DatabaseEventHandler handler = new DatabaseEventHandler();
handler.RegisterEvents();
Application.DocumentManager.MdiActiveDocument.Editor.WriteMessage(
"\nEvent monitoring started. Draw something to see events fire.");
}public class ModificationTracker
{
private Database _db;
private int _modificationCount = 0;
public void Start()
{
_db = Application.DocumentManager.MdiActiveDocument.Database;
_db.ObjectModified += OnObjectModified;
}
public void Stop()
{
if (_db != null)
{
_db.ObjectModified -= OnObjectModified;
Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
ed.WriteMessage($"\nTotal modifications tracked: {_modificationCount}");
}
}
private void OnObjectModified(object sender, ObjectEventArgs e)
{
_modificationCount++;
using (Transaction tr = _db.TransactionManager.StartTransaction())
{
DBObject obj = tr.GetObject(e.DBObject.ObjectId, OpenMode.ForRead);
Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
ed.WriteMessage($"\n>>> Modified: {obj.GetType().Name} (Total: {_modificationCount})");
tr.Commit();
}
}
}public class EraseMonitor
{
private Database _db;
public void RegisterEvents()
{
_db = Application.DocumentManager.MdiActiveDocument.Database;
_db.ObjectErased += OnObjectErased;
_db.ObjectReappended += OnObjectReappended;
}
private void OnObjectErased(object sender, ObjectErasedEventArgs e)
{
Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
if (e.Erased)
{
ed.WriteMessage($"\n>>> Object ERASED: {e.DBObject.GetType().Name}");
}
else
{
ed.WriteMessage($"\n>>> Object UNERASED: {e.DBObject.GetType().Name}");
}
}
private void OnObjectReappended(object sender, ObjectEventArgs e)
{
Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
ed.WriteMessage($"\n>>> Object REAPPENDED: {e.DBObject.GetType().Name}");
}
}public class SaveEventHandler
{
private Database _db;
public void RegisterEvents()
{
_db = Application.DocumentManager.MdiActiveDocument.Database;
_db.BeginSave += OnBeginSave;
_db.SaveComplete += OnSaveComplete;
}
private void OnBeginSave(object sender, DatabaseIOEventArgs e)
{
Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
ed.WriteMessage($"\n>>> Begin Save: {e.FileName}");
// Perform pre-save operations
// e.g., validate data, update metadata, etc.
}
private void OnSaveComplete(object sender, DatabaseIOEventArgs e)
{
Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
ed.WriteMessage($"\n>>> Save Complete: {e.FileName}");
// Perform post-save operations
// e.g., backup, logging, etc.
}
}public class LayerObjectMonitor
{
private Database _db;
private string _targetLayer;
public LayerObjectMonitor(string layerName)
{
_targetLayer = layerName;
}
public void Start()
{
_db = Application.DocumentManager.MdiActiveDocument.Database;
_db.ObjectAppended += OnObjectAppended;
}
public void Stop()
{
if (_db != null)
{
_db.ObjectAppended -= OnObjectAppended;
}
}
private void OnObjectAppended(object sender, ObjectEventArgs e)
{
using (Transaction tr = _db.TransactionManager.StartTransaction())
{
DBObject obj = tr.GetObject(e.DBObject.ObjectId, OpenMode.ForRead);
if (obj is Entity ent && ent.Layer == _targetLayer)
{
Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
ed.WriteMessage($"\n>>> New {obj.GetType().Name} on layer '{_targetLayer}'");
// Perform layer-specific logic
// e.g., auto-assign properties, validate placement, etc.
}
tr.Commit();
}
}
}
[CommandMethod("MONITORLAYER")]
public void MonitorLayerCommand()
{
Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
PromptStringOptions pso = new PromptStringOptions("\nEnter layer name to monitor: ");
PromptResult pr = ed.GetString(pso);
if (pr.Status == PromptStatus.OK)
{
LayerObjectMonitor monitor = new LayerObjectMonitor(pr.StringResult);
monitor.Start();
ed.WriteMessage($"\nMonitoring layer '{pr.StringResult}'");
}
}public class DatabaseEventLogger
{
private Database _db;
private System.IO.StreamWriter _logWriter;
public void StartLogging(string logFilePath)
{
_db = Application.DocumentManager.MdiActiveDocument.Database;
_logWriter = new System.IO.StreamWriter(logFilePath, true);
// Register all major events
_db.ObjectAppended += OnObjectAppended;
_db.ObjectModified += OnObjectModified;
_db.ObjectErased += OnObjectErased;
_db.BeginSave += OnBeginSave;
_db.SaveComplete += OnSaveComplete;
LogEvent("Event logging started");
}
public void StopLogging()
{
if (_db != null)
{
_db.ObjectAppended -= OnObjectAppended;
_db.ObjectModified -= OnObjectModified;
_db.ObjectErased -= OnObjectErased;
_db.BeginSave -= OnBeginSave;
_db.SaveComplete -= OnSaveComplete;
}
if (_logWriter != null)
{
LogEvent("Event logging stopped");
_logWriter.Close();
_logWriter = null;
}
}
private void LogEvent(string message)
{
string timestamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff");
_logWriter.WriteLine($"[{timestamp}] {message}");
_logWriter.Flush();
}
private void OnObjectAppended(object sender, ObjectEventArgs e)
{
LogEvent($"APPENDED: {e.DBObject.GetType().Name} (ID: {e.DBObject.ObjectId})");
}
private void OnObjectModified(object sender, ObjectEventArgs e)
{
LogEvent($"MODIFIED: {e.DBObject.GetType().Name} (ID: {e.DBObject.ObjectId})");
}
private void OnObjectErased(object sender, ObjectErasedEventArgs e)
{
string action = e.Erased ? "ERASED" : "UNERASED";
LogEvent($"{action}: {e.DBObject.GetType().Name} (ID: {e.DBObject.ObjectId})");
}
private void OnBeginSave(object sender, DatabaseIOEventArgs e)
{
LogEvent($"BEGIN SAVE: {e.FileName}");
}
private void OnSaveComplete(object sender, DatabaseIOEventArgs e)
{
LogEvent($"SAVE COMPLETE: {e.FileName}");
}
}graph TD
A[User Action] --> B{Action Type}
B -->|Create| C[ObjectAppended]
B -->|Modify| D[ObjectModified]
B -->|Erase| E[ObjectErased]
B -->|Unerase| F[ObjectReappended]
B -->|Save| G[BeginSave]
G --> H[SaveComplete]
- Always unregister: Remove event handlers when done to prevent memory leaks
- Use transactions: Always use transactions when accessing objects in event handlers
- Avoid recursion: Be careful not to trigger the same event within its handler
- Keep handlers fast: Event handlers should execute quickly
- Handle exceptions: Wrap event handler code in try-catch blocks
- Document-specific: Register events per document, not globally
// Register
_db.ObjectAppended += OnObjectAppended;
// Unregister (CRITICAL!)
_db.ObjectAppended -= OnObjectAppended;private void OnEvent(object sender, ObjectEventArgs e)
{
using (Transaction tr = _db.TransactionManager.StartTransaction())
{
DBObject obj = tr.GetObject(e.DBObject.ObjectId, OpenMode.ForRead);
// Process object
tr.Commit();
}
}private void OnObjectAppended(object sender, ObjectEventArgs e)
{
if (e.DBObject is Circle)
{
// Process only circles
}
}❌ Forgetting to unregister: Causes memory leaks
❌ Modifying in event handler: Can cause recursion
❌ Not using transactions: Causes access violations
❌ Slow event handlers: Degrades performance
❌ Global event handlers: Should be document-specific
- Database - Exposes these events
- ObjectEventArgs - Event argument class
- Transaction - Required for object access
- Document - Document-level events