.NET
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Entities added to Document DB but not immediately displayed

7 REPLIES 7
SOLVED
Reply
Message 1 of 8
WWFreeman
855 Views, 7 Replies

Entities added to Document DB but not immediately displayed

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.

7 REPLIES 7
Message 2 of 8

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: 

 

Відповідь корисна? Клікніть на "ВПОДОБАЙКУ" цім повідомленням! | Do you find the posts helpful? "LIKE" these posts!
Находите сообщения полезными? Поставьте "НРАВИТСЯ" этим сообщениям!
На ваше запитання відповіли? Натисніть кнопку "ПРИЙНЯТИ РІШЕННЯ" | Have your question been answered successfully? Click "ACCEPT SOLUTION" button.
На ваш вопрос успешно ответили? Нажмите кнопку "УТВЕРДИТЬ РЕШЕНИЕ"


Alexander Rivilis / Александр Ривилис / Олександр Рівіліс
Programmer & Teacher & Helper / Программист - Учитель - Помощник / Програміст - вчитель - помічник
Facebook | Twitter | LinkedIn
Expert Elite Member

Message 3 of 8

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?

Message 4 of 8

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

Message 5 of 8


@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. 🙂 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.

Message 6 of 8


@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;
   };

}}}

 

 

Message 7 of 8

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

 

Message 8 of 8

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 );
}

 

 

 

Can't find what you're looking for? Ask the community or share your knowledge.

Post to forums  

Autodesk DevCon in Munich May 28-29th


Autodesk Design & Make Report

”Boost