Author Topic: ELockViolation when upgrading an object to open.  (Read 5671 times)

0 Members and 1 Guest are viewing this topic.

Keith Brown

  • Swamp Rat
  • Posts: 601
ELockViolation when upgrading an object to open.
« on: December 24, 2012, 03:24:59 PM »
I have an issue where I am getting an ELockViolation when I am trying to upgrade and object from readonly to open using .upgradeopen.  Here is my command code

Code - C#: [Select]
  1.     // Create a command to start the Point Monitor
  2.     // In the future this will be added to the Initialize startup procedure
  3.     [CommandMethod("PointMonitor")]
  4.     public static void PointMonitor()
  5.     {
  6.         Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
  7.  
  8.         ed.PointMonitor += new PointMonitorEventHandler(MEPUtilities.ToolTips.ed_PointMonitor);
  9.     }

And here is my eventhandler code

Code - C#: [Select]
  1.  public class ToolTips
  2.     {
  3.  
  4.         // Method to handle the point monitor event for tooltips
  5.         public static void ed_PointMonitor(object sender, PointMonitorEventArgs e)
  6.         {
  7.  
  8.             // Check to see if there is anything under the aperature
  9.             if (e.Context == null)
  10.             {
  11.                 return;
  12.             }
  13.  
  14.             // Check to see if there is anytype of command in progress.  If so we do not want to display a tooltip
  15.             if ((short)Autodesk.AutoCAD.ApplicationServices.Application.GetSystemVariable("CMDACTIVE") !=0 )
  16.             {
  17.                 return;
  18.             }
  19.  
  20.             FullSubentityPath[] fullEntPath = e.Context.GetPickedEntities();
  21.  
  22.             if (fullEntPath.Length > 0)
  23.             {
  24.  
  25.                 Transaction trans = Application.DocumentManager.MdiActiveDocument.Database.TransactionManager.StartTransaction();
  26.  
  27.                 try
  28.                 {
  29.  
  30.                     Entity ent = (Entity)trans.GetObject((ObjectId)fullEntPath[0].GetObjectIds()[0], OpenMode.ForRead);
  31.  
  32.  
  33.                     // Get the Entity Object Class Name and create a string variable to hold our tooltip information
  34.                     string entType = ent.Id.ObjectClass.Name;
  35.                     string str1 = "";
  36.  
  37.                     switch (entType)
  38.                     {
  39.  
  40.                         case "AecbDbMvPart":
  41.  
  42.                             // The object under the aperature is a MvPart.  We need to add the MvPartToolTip Property Set
  43.                             // Definition to the object and then read its values and place those values into the tooltip.
  44.  
  45.                             // Get the ObjectId of the PropertySet
  46.                             ObjectId PropertySetId = psUtilities.GetPropertySet("MvPartToolTip");
  47.                            
  48.                             if (PropertySetId.IsNull)
  49.                             {
  50.                                 // If the property set does not exist then we will display a tooltip informing the user
  51.                                 // To create the property set and fill it with information.
  52.                                 str1 = String.Format("MULTI-VIEW PART{0}{0}", System.Environment.NewLine);
  53.                                 str1 = String.Format("{0}Please create a property set named MvPartToolTip{1}", str1, System.Environment.NewLine);
  54.                                 str1 = String.Format("{0}Fill it with relevant property set definitions{1}", str1, System.Environment.NewLine);
  55.                                 e.AppendToolTipText(str1);
  56.                                 return;
  57.                             }
  58.                            
  59.                             // If we are here then the property set exists but we do not know if the property
  60.                             // Is attached to the object.  The AttachPropertySet method will check and will
  61.                             // Add the property set if needed.
  62.                             if (psUtilities.AttachPropertySet(ent.ObjectId, PropertySetId))
  63.                             {
  64.                                 str1 = String.Format("MULTI-VIEW PART{0}{0}", System.Environment.NewLine);
  65.                                 str1 = String.Format("{0}Property Set Attached{1}", str1, System.Environment.NewLine);
  66.                                 e.AppendToolTipText(str1);
  67.                             }
  68.                             else
  69.                             {
  70.                                 str1 = String.Format("MULTI-VIEW PART{0}{0}", System.Environment.NewLine);
  71.                                 str1 = String.Format("{0}Property is not attached{1}", str1, System.Environment.NewLine);
  72.                                 e.AppendToolTipText(str1);
  73.                             }
  74.                             break;
  75.  
  76.                         case "AecbDbDuct":
  77.                             str1 = String.Format("DUCT{0}{0}", System.Environment.NewLine);
  78.                             e.AppendToolTipText(str1);
  79.                             break;
  80.                         case "AecbDbDuctFitting":
  81.                             str1 = String.Format("DUCT FITTING{0}{0}", System.Environment.NewLine);
  82.                             e.AppendToolTipText(str1);
  83.                             break;
  84.                         case "AecbDbPipe":
  85.                             str1 = String.Format("PIPE{0}{0}", System.Environment.NewLine);
  86.                             e.AppendToolTipText(str1);
  87.                             break;
  88.                         case "AecbDbPipeFitting":
  89.                             str1 = String.Format("PIPE FITTING{0}{0}", System.Environment.NewLine);
  90.                             e.AppendToolTipText(str1);
  91.                             break;
  92.                         default:
  93.                             return;
  94.                     }
  95.  
  96.                     trans.Commit();
  97.                 }
  98.                 catch (Autodesk.AutoCAD.Runtime.Exception ex)
  99.                 {
  100.  
  101.                 }
  102.                 finally
  103.                 {
  104.                     trans.Dispose();
  105.                 }
  106.             }
  107.         }
  108.  
  109.  
  110.     }
  111.  

And finally here is my code that actually attaches the property set on the object.

Code - C#: [Select]
  1.  #region AttachPropertySet (Single)
  2.  
  3.         /// <summary>
  4.         /// Attaches a property set on a given object.
  5.         /// Requires that the property set exists in the current database.
  6.         /// </summary>
  7.         /// <param name="MepObjectId">The objectID of the object to create the property set on.</param>
  8.         /// <param name="PropertySetObjectId">The objectID of the property set to create on the object </param>
  9.         /// <returns>True if the property set was created on the object or was already attached to the object.</returns>
  10.         /// <returns>False if the property set does not apply to the object or there was an exception.</returns>
  11.         public static bool AttachPropertySet(ObjectId MepObjectId, ObjectId PropertySetId)
  12.         {
  13.             Database db = Application.DocumentManager.MdiActiveDocument.Database;
  14.             AcadDb.TransactionManager tm = db.TransactionManager;
  15.             using (Transaction trans = tm.StartTransaction())
  16.             {
  17.                 try
  18.                 {
  19.                     AcadDb.Entity dbObject = (AcadDb.Entity)tm.GetObject(MepObjectId, OpenMode.ForRead, true);
  20.                      
  21.                     // Check to see if the property set is already attached to the object.  If it is then there is no
  22.                     // need to go any further.
  23.                     if (IsPropertySetAttached(dbObject, PropertySetId))
  24.                     {
  25.                         return true;
  26.                     }
  27.                     // .Net will let us attach a property set to an object even if it does not apply to the object.
  28.                     // So make sure that the property set applies.
  29.                     if (!AppliesToObject(MepObjectId, PropertySetId))
  30.                     {
  31.                         return false;
  32.                     }
  33.  
  34.                     // At this point we have a valid object:property set pair so attach the property set
  35.                     dbObject.UpgradeOpen();
  36.                     AecPropDb.PropertyDataServices.AddPropertySet(dbObject, PropertySetId);
  37.                 }
  38.  
  39.                 catch (Autodesk.AutoCAD.Runtime.Exception)
  40.                 {
  41.                     return false;
  42.                 }  
  43.  
  44.                 trans.Commit();
  45.            
  46.             }
  47.    
  48.             return true;
  49.        
  50.         }
  51.         #endregion
  52.  

My error is on line 35 of the AttachPropertySet method where I am attempting to open the object so I can attach the property set to it.  I suspected that the problem was that I had already opened the object for read in the eventhandler on line 30.  So I took the code from the AttachPropertySet method and moved it into my eventhandler.  So this time I was only opening the object for read once but I still got the error in the eventhandler when I tried to UpgradeOpen the object.  So now I am stuck.  I reset my code to its original form and did some searches but did not find anything that would help me.  I am sure that this is a simple issue but I just don't undertand the api or .net well enough to figure it out.  Any ideas?
Keith Brown | AutoCAD MEP Blog | RSS Feed
AutoCAD MEP 2014 / Revit MEP 2014 / EastCoast CAD/CAM addon / Visual Studio 2013

fixo

  • Guest
Re: ELockViolation when upgrading an object to open.
« Reply #1 on: December 24, 2012, 04:33:46 PM »
Try to add LockDocument

Code: [Select]
public static bool AttachPropertySet(ObjectId MepObjectId, ObjectId PropertySetId)
        {
           [color=red]Document doc =Application.DocumentManager.MdiActiveDocument;
           using (DocumentLock docloc= doc.LockDocument())[/color]
           {
            Database db = Application.DocumentManager.MdiActiveDocument.Database;
            AcadDb.TransactionManager tm = db.TransactionManager;
            using (Transaction trans = tm.StartTransaction())
            {
          // rest your code here
          }
          }

Keith Brown

  • Swamp Rat
  • Posts: 601
Re: ELockViolation when upgrading an object to open.
« Reply #2 on: December 24, 2012, 04:41:48 PM »
Thanks Fixo.
That fixed it. 
Keith Brown | AutoCAD MEP Blog | RSS Feed
AutoCAD MEP 2014 / Revit MEP 2014 / EastCoast CAD/CAM addon / Visual Studio 2013

fixo

  • Guest
Re: ELockViolation when upgrading an object to open.
« Reply #3 on: December 24, 2012, 04:43:51 PM »
Merry X-mas
Cheers :)

TheMaster

  • Guest
Re: ELockViolation when upgrading an object to open.
« Reply #4 on: December 27, 2012, 03:33:33 AM »
I have an issue where I am getting an ELockViolation when I am trying to upgrade and object from readonly to open using .upgradeopen. 


My error is on line 35 of the AttachPropertySet method where I am attempting to open the object so I can attach the property set to it.  I suspected that the problem was that I had already opened the object for read in the eventhandler on line 30.  So I took the code from the AttachPropertySet method and moved it into my eventhandler.  So this time I was only opening the object for read once but I still got the error in the eventhandler when I tried to UpgradeOpen the object.  So now I am stuck.  I reset my code to its original form and did some searches but did not find anything that would help me.  I am sure that this is a simple issue but I just don't undertand the api or .net well enough to figure it out.  Any ideas?

You shouldn't be modifying objects from a PointMonitor event handler in the first place. Doing that is asking for trouble, as you've yet to discover. Don't make assumptions about what may be happening in the drawing editor when a PointMonitor event handler fires. It also isn't wise to use a transaction in that context either, because it can corrupt UNDO/REDO for one thing, that is, assuming it doesn't outright crash AutoCAD,

If you put code like that into production use, I would suggest stocking up on asbestos shorts.

Keith Brown

  • Swamp Rat
  • Posts: 601
Re: ELockViolation when upgrading an object to open.
« Reply #5 on: December 27, 2012, 10:43:33 AM »
Hi Tony,

I have changed the code quite a bit since that first proof of concept because of some of the things that you mentioned.  Currently my steps are as follows:

1. Start a point monitor event handling procedure.
2. Start a transaction to read information about the object under the cursor.
3. If the object is one that I care about then,
4. Upgrade the transaction to write so I can attach the correct property set to the object
5. Read information in the property set about the object
6. Display the information in a tooltip (or a custom form)
7. Remove the property set from the object
8. Dispose of the transaction.

So would that actually qualify as modifying an object from a Point Monitor Event Handler?  Since the transaction is disposed and not committed the object never actually gets modified so from a UNDO/REDO perspective it doesnt matter (I think).  My intent is to not permanently modify the object but just temporarily so I can read some information about it.

Is there anything wrong with doing something along this line of thought inside of a point monitor event handler?

EDIT:  It occured to me that any event handlers that monitered the database for an object being modified would possibly fire off using this method even though the transaction was not being committed.  I think I will need to investigate this further.

Quote
If you put code like that into production use, I would suggest stocking up on asbestos shorts.

I was drinking my morning cup of coffee when I read this and actually spit up the coffee on my keyboard.  Luckily I have encountered this event before and knew the correct steps to rectify the situation.  The good news is that none of the code that I currently write is being put into production!  yay!!  It is just a hobby for me right now and everything that I do is just stuff that I use at home.  That is why I really value and respect the comments that I get from you and the rest of the swamp community.  So thank you again.
« Last Edit: December 27, 2012, 02:00:20 PM by Keith Brown »
Keith Brown | AutoCAD MEP Blog | RSS Feed
AutoCAD MEP 2014 / Revit MEP 2014 / EastCoast CAD/CAM addon / Visual Studio 2013

Keith Brown

  • Swamp Rat
  • Posts: 601
Re: ELockViolation when upgrading an object to open.
« Reply #6 on: December 27, 2012, 06:15:07 PM »
So I did a little bit more testing this afternoon and it does appear that adding a property set and then disposing of the transaction still fires off all of the modify events.  In one particular case, all of the aec schedules will show the fittings as being modifed which is not a good scenario.  So I am going to change the way the process in which the property set gets added.  The whole reason for adding it and then removing it in the point monitor was to keep it from being attached to the object when not needed.  As I can see no other way around this, I will just attach the property set when the object is added to the database.  I can then just hide the property set from the property palette by setting its visible flag to no and keep its writable flag to yes.  I was trying to avoid this but there doesnt seem to be any other way.


Keith Brown | AutoCAD MEP Blog | RSS Feed
AutoCAD MEP 2014 / Revit MEP 2014 / EastCoast CAD/CAM addon / Visual Studio 2013