.NET

.NET

Reply
Active Contributor
WWFreeman
Posts: 27
Registered: ‎09-02-2012
Message 1 of 8 (421 Views)
Accepted Solution

Entities added to Document DB but not immediately displayed

421 Views, 7 Replies
02-28-2013 07:29 AM

Hello everyone.

 

Now I am exploring how entities can be drawn in a document that is not active, but is open. While the drawn entities are recorded to the document's database, they are not keen on being displayed when I make the document active. Sometimes Z+A (zoom all) triggers redrawing the elements, sometimes not. Closing and reopening the document helps though. However, I am looking for the way to have them displayed immediately after they're drawn.

 

If you would like to help me figure this one out, here is the script I am testing this with:

 

using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.DatabaseServices;
using System;
using Autodesk.AutoCAD.Geometry;
using System.IO;

[assembly: CommandClass(typeof(CPerformTest.PerformTest))]

namespace CPerformTest {
  public class PerformTest : IExtensionApplication {

    [CommandMethod("performtest")]
    public static void Perform() {
      try {
        string helpFileName = "HelpDrawing.dwg";
        Document mainDoc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument;
        Editor mainEditor = mainDoc.Editor;

        mainEditor.WriteMessage("\nPress ENTER to add a new entity and ESC to break the loop.\n");
        PromptPointOptions opts = new PromptPointOptions("");
        opts.AllowNone = true;
        while(true) {
          PromptPointResult ppr = mainEditor.GetPoint(opts);
          if(ppr.Status == PromptStatus.OK) {
            // Just ignore it
          } else if(ppr.Status == PromptStatus.None) {
            Document helpDrawing = OpenBkgDocument(helpFileName);
            if(helpDrawing != null) {
              helpFileName = helpDrawing.Name;
              Database helpDB = helpDrawing.Database;
              using(DocumentLock dl = helpDrawing.LockDocument(DocumentLockMode.ProtectedAutoWrite, null, null, true)) {
                using(Transaction tr = helpDB.TransactionManager.StartTransaction()) {
                  BlockTableRecord btr = (BlockTableRecord) tr.GetObject(helpDB.CurrentSpaceId, OpenMode.ForWrite);

                  Random r = new Random();
                  Point3d a = new Point3d(r.NextDouble() * 10, 0, 0);
                  Point3d b = new Point3d(0, r.NextDouble() * 10, 0);
                  Line line = new Line();
                  line.StartPoint = a;
                  line.EndPoint = b;

                  ObjectId objId = btr.AppendEntity(line);
                  tr.AddNewlyCreatedDBObject(line, true);

                  tr.Commit();
                }
              }
            }
          } else if(ppr.Status == PromptStatus.Cancel) {
            mainEditor.WriteMessage("*Canceled*");
            break;
          }
        }
      } catch(System.Exception e) {
      }
    }

    public static Document OpenBkgDocument(string fileName) {
      DocumentCollection docs = Application.DocumentManager;
      Document result = null;
      foreach(Document doc in docs) {
        string dname = doc.Name;
        if(dname.Equals(fileName, StringComparison.CurrentCultureIgnoreCase)) {
          result = doc;
          break;
        }
      }

      if(result == null) {
        if(!File.Exists(fileName)) {
          Document doc = Application.DocumentManager.Add("acad.dwt");
          doc.Database.SaveAs(
            fileName,
            true,
            DwgVersion.Current,
            doc.Database.SecurityParameters
          );
          doc.CloseAndDiscard();
        }
      }

      if(result == null) {
        DocumentCollection acDocMgr = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager;
        if(File.Exists(fileName)) {
          result = acDocMgr.Open(fileName, false);
        }
      }
      return result;
    }

    public void Initialize() {
    }

    public void Terminate() {
    }
  }
}

I use GetPoint to capture enters and escs. Here each ENTER will produce a line in the background drawing, and the ESC will break the loop. Because I am still learning the code might not be optimal in all aspects.

 

Well, thanks.

I will remind you what Tony Tanzillo wrote to you some months ago here:

 You can manipulate the database of a drawing that's not the active document direclty via the API, except that there is a problem with graphics not updating, and currently there is no way to solve that one in purely managed code. The solution requires native code, and specifically a couple of calls to the AcApDocManager::setCurDocument(). API.
That API must be called and passed the AcApDocument containing the objects you will be modifying, and once you've finished modifying that document's database, you must call the same API again, and pass it the AcApDocument representing the active document. I'm still not sure why Autodesk hasn't exposed this API since this is a very long-standing problem that they've been made aware of more times than I care to recall. :smileyfrustrated: 

 


WWFreeman wrote:

Thanks for bringing up that one.

 

So solution is below the managed code. Alright, I am actually good with C++ and I had already used the COM interface. Can we discuss whether that is something generally doable having this particular action on mind or Autodesk hasn't exposed it for a good reason?


As I mentioned, the reason it's not exposed to managed code is still a puzzle.

 

Here is my C++/CLI source for the CurrentDocument class. It implements IDisposable, and works similar to a DocumentLock. You pass the constructor the Document to be made current, and call Dispose() when you want to restore the previously-current document.

 

#pragma once
#pragma managed
using namespace Autodesk::AutoCAD::DatabaseServices;
using namespace Autodesk::AutoCAD::Runtime;
using namespace Autodesk::AutoCAD::ApplicationServices;
#define GETDOCUMENT( doc ) static_cast<AcApDocument*>( doc->UnmanagedObject.ToPointer() );
namespace CaddZone { namespace AutoCAD { namespace Native
{
public ref class CurrentDocument : IDisposable
{
public:
CurrentDocument( Document^ doc ) : m_prev(NULL), m_cur(NULL), m_docToBeDestroyedHandler(nullptr)
{
MgdUtils::CheckNull( "doc", doc );
AcApDocument* pCurrent = acDocManager->curDocument();
AcApDocument* pDoc = GETDOCUMENT( doc );
if( pCurrent != NULL && pDoc != pCurrent )
{
acDocManager->setCurDocument( pDoc );
m_cur = pDoc;
m_prev = pCurrent;
WireEvents();
}
}
~CurrentDocument()
{
if( m_prev != NULL && acDocManager->curDocument() == m_cur )
acDocManager->setCurDocument( m_prev );
Clear();
}
!CurrentDocument()
{
MgdUtils::Throw( "CurrentDocument must be determinstically disposed" );
}
private:
void documentToBeDestroyed( Object^ sender, DocumentCollectionEventArgs^ e )
{
if( e->Document != nullptr )
{
AcApDocument* pDoc = GETDOCUMENT( e->Document );
if( pDoc == m_prev )
Clear();
}
}
void Clear()
{
UnwireEvents();
m_prev = NULL;
m_cur = NULL;
}
void WireEvents()
{
if( m_docToBeDestroyedHandler == nullptr )
{
m_docToBeDestroyedHandler = gcnew DocumentCollectionEventHandler( this, &CurrentDocument::documentToBeDestroyed );
Autodesk::AutoCAD::ApplicationServices::Application::DocumentManager->DocumentToBeDestroyed += m_docToBeDestroyedHandler;
}
}
void UnwireEvents()
{
if( m_docToBeDestroyedHandler != nullptr )
{
Autodesk::AutoCAD::ApplicationServices::Application::DocumentManager->DocumentToBeDestroyed -= m_docToBeDestroyedHandler;
m_docToBeDestroyedHandler = nullptr;
}
}
DocumentCollectionEventHandler^ m_docToBeDestroyedHandler;
AcApDocument* m_prev;
AcApDocument* m_cur;
};
}}}

 

 

Moderator
Alexander.Rivilis
Posts: 1,450
Registered: ‎04-09-2008
Message 2 of 8 (393 Views)

Re: Entities added to Document DB but not immediately displayed

02-28-2013 02:01 PM in reply to: WWFreeman

I will remind you what Tony Tanzillo wrote to you some months ago here:

  You can manipulate the database of a drawing that's not the active document direclty via the API, except that there is a problem with graphics not updating, and currently there is no way to solve that one in purely managed code. The solution requires native code, and specifically a couple of calls to the AcApDocManager::setCurDocument(). API.
  That API must be called and passed the AcApDocument containing the objects you will be modifying, and once you've finished modifying that document's database, you must call the same API again, and pass it the AcApDocument representing the active document.  I'm still not sure why Autodesk hasn't exposed this API since this is a very long-standing problem that they've been made aware of more times than I care to recall. :smileyfrustrated: 

 


Пожалуйста не забывайте про Утвердить в качестве решения! Утвердить в качестве решения и Give Kudos!Баллы
Please remember to Accept Solution! Accept as Solution and Give Kudos!Kudos

Active Contributor
WWFreeman
Posts: 27
Registered: ‎09-02-2012
Message 3 of 8 (381 Views)

Re: Entities added to Document DB but not immediately displayed

02-28-2013 02:50 PM in reply to: Alexander.Rivilis

Thanks for bringing up that one.

 

So solution is below the managed code. Alright, I am actually good with C++ and I had already used the COM interface. Can we discuss whether that is something generally doable having this particular action on mind or Autodesk hasn't exposed it for a good reason?

Valued Mentor
DiningPhilosopher
Posts: 370
Registered: ‎05-06-2012
Message 4 of 8 (373 Views)

Re: Entities added to Document DB but not immediately displayed

02-28-2013 03:21 PM in reply to: WWFreeman

As per Alex's quote, that solution, or temporarily switching the active document, are the only ways to solve the problem.

Active Contributor
WWFreeman
Posts: 27
Registered: ‎09-02-2012
Message 5 of 8 (370 Views)

Re: Entities added to Document DB but not immediately displayed

02-28-2013 04:10 PM in reply to: DiningPhilosopher

DiningPhilosopher wrote:

As per Alex's quote, that solution, or temporarily switching the active document, are the only ways to solve the problem.


You were quoted there. :smileyhappy: I was merely interested in writing unmanaged code that does the job and running it through the COM, but since I am not really willing to try that hard right now, I'll have to wait for a while to see why that wouldn't be possible.

 

As for the known .NET options, it is also possible to programatically close and reopen the document. In case that temporary doc switching happens unacceptably often (in the eye of observer), having a command like specregen that closes and reopens the other document just seems like a fair alternative.

Valued Mentor
DiningPhilosopher
Posts: 370
Registered: ‎05-06-2012
Message 6 of 8 (338 Views)

Re: Entities added to Document DB but not immediately displayed

03-01-2013 06:10 AM in reply to: WWFreeman

WWFreeman wrote:

Thanks for bringing up that one.

 

So solution is below the managed code. Alright, I am actually good with C++ and I had already used the COM interface. Can we discuss whether that is something generally doable having this particular action on mind or Autodesk hasn't exposed it for a good reason?


As I mentioned, the reason it's not exposed to managed code is still a puzzle.

 

Here is my C++/CLI source for the CurrentDocument class. It implements IDisposable, and works similar to a DocumentLock. You pass the constructor the Document to be made current, and call Dispose() when you want to restore the previously-current document.

 

#pragma once
#pragma managed

using namespace Autodesk::AutoCAD::DatabaseServices;
using namespace Autodesk::AutoCAD::Runtime;
using namespace Autodesk::AutoCAD::ApplicationServices;

#define GETDOCUMENT( doc ) static_cast<AcApDocument*>( doc->UnmanagedObject.ToPointer() );

namespace CaddZone { namespace AutoCAD { namespace Native
{

   public ref class CurrentDocument : IDisposable
   {
   public:

      CurrentDocument( Document^ doc ) : m_prev(NULL), m_cur(NULL), m_docToBeDestroyedHandler(nullptr)
      {
         MgdUtils::CheckNull( "doc", doc );        
         AcApDocument* pCurrent = acDocManager->curDocument();
         AcApDocument* pDoc = GETDOCUMENT( doc );
         if( pCurrent != NULL && pDoc != pCurrent )
         {
            acDocManager->setCurDocument( pDoc );
            m_cur = pDoc;
            m_prev = pCurrent;
            WireEvents();
         }
      }

      ~CurrentDocument()
      {
         if( m_prev != NULL && acDocManager->curDocument() == m_cur )
            acDocManager->setCurDocument( m_prev );
         Clear();
      }

      !CurrentDocument()
      {
         MgdUtils::Throw( "CurrentDocument must be determinstically disposed" );
      }

   private:

      void documentToBeDestroyed( Object^ sender, DocumentCollectionEventArgs^ e )
      {
         if( e->Document != nullptr )
         {
            AcApDocument* pDoc = GETDOCUMENT( e->Document );
            if( pDoc == m_prev )
               Clear();
         }
      }

      void Clear()
      {
         UnwireEvents();
         m_prev = NULL;
         m_cur = NULL;
      }

      void WireEvents()
      {
         if( m_docToBeDestroyedHandler == nullptr )
         {
            m_docToBeDestroyedHandler = gcnew DocumentCollectionEventHandler( this, &CurrentDocument::documentToBeDestroyed );
            Autodesk::AutoCAD::ApplicationServices::Application::DocumentManager->DocumentToBeDestroyed += m_docToBeDestroyedHandler;
         }
      }

      void UnwireEvents()
      {
         if( m_docToBeDestroyedHandler != nullptr )
         {
            Autodesk::AutoCAD::ApplicationServices::Application::DocumentManager->DocumentToBeDestroyed -= m_docToBeDestroyedHandler;
            m_docToBeDestroyedHandler = nullptr;
         }
      }

      DocumentCollectionEventHandler^ m_docToBeDestroyedHandler;
      AcApDocument* m_prev;
      AcApDocument* m_cur;
   };

}}}

 

 

Active Contributor
WWFreeman
Posts: 27
Registered: ‎09-02-2012
Message 7 of 8 (317 Views)

Re: Entities added to Document DB but not immediately displayed

03-01-2013 11:03 PM in reply to: DiningPhilosopher

Thanks. That is rather very generous on your part. I'll need some time however to revisit the topic and try this.

 

Valued Mentor
DiningPhilosopher
Posts: 370
Registered: ‎05-06-2012
Message 8 of 8 (297 Views)

Re: Entities added to Document DB but not immediately displayed

03-02-2013 01:53 PM in reply to: WWFreeman

You're welcome. I just noticed a more-recent version of that class which has a bug fix in it that wasn't in the one I posted.

 

So, if someone is going to use it, they need to change the Clear() method to this:

 

void Clear()
{
   UnwireEvents();
   m_prev = NULL;
   m_cur = NULL;
   GC::SuppressFinalize( this );
}

 

 

 

Post to the Community

Have questions about Autodesk products? Ask the community.

New Post
Announcements
Do you have 60 seconds to spare? The Autodesk Community Team is revamping our site ranking system and we want your feedback! Please click here to launch the 5 question survey. As always your input is greatly appreciated.