This is common request: identify what have changed on Modified event of entities. In fact this feature is not available on the API, mainly because it can potentially represent a big use of memory. But a (partial) workaround may help in some cases!
The main thing is that is not easy to track everything that change on a entity, mainly because one can refer to another, or even contain internal data not easily exposed. Also, in complex scenarios like this, a generic approach may not capture everything.
So I decided to do a quick try with .NET properties, basically using reflection mechanism to store the data and compare back. Below is a common code that track changes with Modified event, but it has a few extra lines (marked in yellow) enabled by .NET Extension mechanism.
[CommandMethod("monitorEntity")] public void CmdMonitorEntity() { // select an entity Editor ed = Application.DocumentManager. MdiActiveDocument.Editor; PromptEntityResult resEnt = ed.GetEntity( "Select an entity: "); if (resEnt.Status != PromptStatus.OK) return; // and register the event MonitorEntity(resEnt.ObjectId); } private void MonitorEntity(ObjectId objectId) { Database db = Application.DocumentManager. MdiActiveDocument.Database; using (Transaction trans = db. TransactionManager.StartTransaction()) { Entity ent = trans.GetObject(objectId, OpenMode.ForRead) as Entity; // start the monitor this object ent.MonitorPropertyChanges(); // as usual, register for 'Modified' event ent.Modified += new EventHandler(ent_Modified); } } void ent_Modified(object sender, EventArgs e) { Entity ent = sender as Entity; if (ent == null) return; // list of what changed string[] propsModified = ent.GetModifiedProperties(); if (propsModified.Length == 0) return; Editor ed = Application.DocumentManager. MdiActiveDocument.Editor; // write the values that changed ed.WriteMessage("nProperties were modified:"); foreach (string propName in propsModified) { ed.WriteMessage("n{0}, previous value {1}", propName, ent.GetPreviousValue(propName)); } }
The code above should look very common, no extra feature other than those in yellow. As a side note, that is the beauty of .NET Extension: we can add new methods for certain types of object and the syntax is quite sharp.
At the image below, note how the properties changed are tracked after the user change the layer using the Property palette. Please test this and make sure the properties you’re tracking are listed with this mechanism. Things like nodes of a polyline will not appear.
Ok, to enable this extension methods, simply create a new class and mark as ‘static’ in C# or create as a ‘Module’ on VB.NET (where an additional metadata is required: <Extension()>).
public static class DBObjectMonitor { private static Dictionary _monitorList; // list of properties for objects monitored private static Dictionary MonitorList { get { if (_monitorList == null) _monitorList = new Dictionary(); return _monitorList; } } /// /// Prepare the object to monitor what have changed /// public static void MonitorPropertyChanges(this DBObject dbObj) { dbObj.OpenedForModify += new EventHandler(dbObj_OpenedForModify); } private static void dbObj_OpenedForModify( object sender, EventArgs e) { StorePropeties((DBObject)sender); } private static void StorePropeties(DBObject dbObj) { Dictionary objPropBefore = new Dictionary(); System.Reflection.PropertyInfo[] props = dbObj.GetType().GetProperties(); foreach (System.Reflection.PropertyInfo prop in props) { try { // if we cannot write, // let's not monitor it if (!prop.CanWrite) continue; // save the value of the propery objPropBefore.Add(prop.Name, prop.GetValue(dbObj, null)); } catch { // get the value through reflection // cannot be safe... } } // store all the properties based // on the objectId MonitorList.Remove(dbObj.ObjectId); MonitorList.Add(dbObj.ObjectId, objPropBefore); } /// /// List of properties changed on the Modified event /// public static string[] GetModifiedProperties(this DBObject dbObj) { // is on the list? if (!MonitorList.ContainsKey(dbObj.ObjectId)) return null; // get the list of values Dictionary objPropBefore = MonitorList[dbObj.ObjectId]; // this will store the name of what was changed List propList = new List(); // list of properties System.Reflection.PropertyInfo[] props = dbObj.GetType().GetProperties(); foreach (System.Reflection.PropertyInfo prop in props) { try { // if we cannot write, // let's not monitor it if (!prop.CanWrite) continue; // save the value of the propery object valueBefore = objPropBefore[prop.Name]; object valueAfter = prop.GetValue(dbObj, null); if (valueBefore.Equals(valueAfter)) // remove from the original list objPropBefore.Remove(prop.Name); else propList.Add(prop.Name); } catch { // get the value through reflection // may not be safe... } } return propList.ToArray(); } /// /// Get the value for the property /// before this current change /// /// /// Name of the property /// The previous value public static object GetPreviousValue( this DBObject dbObj, string propertyName) { // get the list Dictionary objPropBefore = MonitorList[dbObj.ObjectId]; // this property exist? if (!objPropBefore.ContainsKey(propertyName)) return null; return objPropBefore[propertyName]; } }


Leave a Reply to BlackBoxCancel reply