Author Topic: LockDocument()  (Read 2754 times)

0 Members and 1 Guest are viewing this topic.

Atook

  • Swamp Rat
  • Posts: 1027
  • AKA Tim
LockDocument()
« on: July 24, 2015, 01:20:57 PM »
So I just ran into the problem of needing to lock the document before I can open the database for write. This may be obvious to some, but I’d love to get some confirmation or correction about my understanding of the issue.

I’ve got functions that get called from a [CommandMethod] and run great. If I call the same functions from a button on my palette, I get an eLockViolation. In order to get this code to run, I need to call the LockDocument() function, which I found via the interwebs in Lab6 of the Autodesk .NET tutorials from back in the day.

My guess is that CAD locks the document everytime a command is called, which is why I don’t need to call it at all if my functions have been called by commands. Is this correct?
If so, I only need to lock the document when calling a database write from a non command (such as a button click) or an updated field in a properties grid.
My current approach is to lock the document in the button click event as shown. This looks like a bad practice to me, but I’m not sure I need to imbed it deeper in my code. Are the interface events a good place to lock the document from? Is there some sort of document unlock/release I should call when I'm done?

Code - C#: [Select]
  1. private void btnValveInsert_Click(object sender, EventArgs e)
  2. {
  3.         Active.Document.LockDocument(DocumentLockMode.ProtectedAutoWrite, null, null, true);
  4.         ValveFactory.InsertDynamicValve(30);
  5. }
  6.  
  7. // VS
  8.  
  9. [CommandMethod("IR_InsValve")]
  10. public void InsertValve()
  11. {
  12.         ValveFactory.InsertDynamicValve(30);
  13. }
  14.  

On a slightly different note, when reviewing the LAB6 from the tutorial, I noticed that the following comment: //Whatever happens we must dispose the transaction. (This is in the Finally block).

Whenever I use a transaction, I commit() it when I’m done with it and have not been calling dispose(), and things have been running fine. What's the purpose of disposing of a transaction?

Jeff H

  • Needs a day job
  • Posts: 6144
Re: LockDocument()
« Reply #1 on: July 24, 2015, 01:32:03 PM »
This is a little class that ties transaction and document locking together

Code - C#: [Select]
  1. using System;
  2. using Autodesk.AutoCAD.DatabaseServices;
  3. using Autodesk.AutoCAD.ApplicationServices;
  4.  
  5. namespace Autodesk.AutoCAD.Runtime
  6. {
  7.    public class LockedTransaction : Transaction
  8.     {
  9.        DocumentLock docLock;
  10.        public LockedTransaction(Transaction trx, DocumentLock docLock)
  11.            : base(trx.UnmanagedObject, trx.AutoDelete)
  12.        {
  13.            Interop.DetachUnmanagedObject(trx);
  14.            GC.SuppressFinalize(trx);
  15.            this.docLock = docLock;
  16.            
  17.        }
  18.  
  19.        protected override void Dispose(bool A_1)
  20.        {
  21.  
  22.            base.Dispose(A_1);
  23.            if (A_1)
  24.            {
  25.                docLock.Dispose();
  26.            }
  27.        }
  28.     }
  29.  
  30.  
  31. }
  32.  

Call it through a extension method
Code - C#: [Select]
  1. using Autodesk.AutoCAD.ApplicationServices.Core;
  2. using Autodesk.AutoCAD.Runtime;
  3.  
  4. namespace Autodesk.AutoCAD.ApplicationServices
  5. {
  6.    public static class TransactionManagerExtensions
  7.     {
  8.        public static LockedTransaction StarLockedTransaction(this TransactionManager tm)
  9.        {
  10.            DocumentLock doclock = Application.DocumentManager.MdiActiveDocument.LockDocument();
  11.            return new LockedTransaction(tm.StartTransaction(), doclock);
  12.        }
  13.  
  14.        public static LockedTransaction StarLockedTransaction(this TransactionManager tm, DocumentLockMode lockMode, string globalCommandName, string localCommandName, bool promptIfFails)
  15.        {
  16.            DocumentLock doclock = Application.DocumentManager.MdiActiveDocument.LockDocument(lockMode, globalCommandName, localCommandName, promptIfFails);
  17.            return new LockedTransaction(tm.StartTransaction(), doclock);
  18.        }
  19.     }
  20. }
  21.  
  22.  
  23.  

Atook

  • Swamp Rat
  • Posts: 1027
  • AKA Tim
Re: LockDocument()
« Reply #2 on: July 24, 2015, 01:49:45 PM »
Thanks Jeff. I'm always impressed with extension methods, I'm using some of Giles, and they seem to be an elegant solution to some of the boilerplate code I run into.

If I'm reading this correctly, it would make sense to instantiate a LockedTransaction anytime I open the database for write?

I look forward to trying this code out later this afternoon. Thanks again.

huiz

  • Swamp Rat
  • Posts: 913
  • Certified Prof C3D
Re: LockDocument()
« Reply #3 on: July 24, 2015, 02:07:16 PM »
I'm  not exactly sure why you need a document lock, but running code from a Palette needs a lock. Maybe because there is no connection between the Palette and the current document, since a Palette floats around in the application and not in a document.

There are other actions that need a document lock, for example if you switch between Layouts nothing really happens if you don't lock the document.

It does not hurt to always use a lock. So you can use a lock in each function you write.
The conclusion is justified that the initialization of the development of critical subsystem optimizes the probability of success to the development of the technical behavior over a given period.

Atook

  • Swamp Rat
  • Posts: 1027
  • AKA Tim
Re: LockDocument()
« Reply #4 on: July 24, 2015, 02:38:37 PM »
It does not hurt to always use a lock. So you can use a lock in each function you write.

Thanks for the reply huiz. Are you saying there isn't a considerable performance hit with locking the document for every transaction? If so, that's precisely what I'll do. Though I have to wonder why it's not built in to the transaction manager if that's the case.

@Jeff, thanks for sharing your extension classes.  Looks like unless it's readonly, I'll be using locked transactions.

To answer my own question publicly, I noted that the dispose() override was called after the transaction falls from scope, presumably during garbage collection. Meaning there's no reason for me to call it.
« Last Edit: July 24, 2015, 03:21:43 PM by Atook »

BlackBox

  • King Gator
  • Posts: 3770
Re: LockDocument()
« Reply #5 on: July 24, 2015, 03:46:54 PM »
The issue is Context in which a Method is called, as I understand it.

CommandMethod places application in a specific context that a Button or MenuItem Click event does not (inherently) - hence, you supply a call to 'using' LockDocument() and the issue is mitigated.

I use a lot of ContextMenuExtensions (read MenuItem.Click), and have never seen a noticeable difference in performance in my Transactions, but that's not to say that there isn't a hit per-se.

Cheers
"How we think determines what we do, and what we do determines what we get."

gile

  • Gator
  • Posts: 2507
  • Marseille, France
Re: LockDocument()
« Reply #6 on: July 24, 2015, 03:49:51 PM »
Hi,

Autodesk provides some documentation about this.
Speaking English as a French Frog

mohnston

  • Bull Frog
  • Posts: 305
  • CAD Programmer
Re: LockDocument()
« Reply #7 on: July 27, 2015, 10:54:22 AM »
The key is whether your application is modal or modeless.
If modeless then you will need to lock a document before making any changes to it. Since your app could potentially change any open document locking is necessary.
If modal then the document lock is implied.
It's amazing what you can do when you don't know what you can't do.
CAD Programming Solutions