Last year, I wrote a post on how to implement a DocumentManager for Civil 3D documents. The motivation was to overcome the limitations in the Civil 3D API that made very difficult to work with multiple documents at once. Many of you have pointed out how difficult is to keep track of the different document and database objects even when the code is well abstracted into an owned 'Document' and 'DocumentManager' classes.
In Jay Peak, we have introduced a new static method 'GetCivilDocument() in the 'CivilDocument' class, which allows you to instantiate a 'CivilDocument' object from an AutoCAD 'Database' object. This new method highly simplifies the process because it allows you to implement all document management through the AutoCAD API; therefore, your 'DocumentManager' abstraction should only depend on the AutoCAD API and its document management functionality. From an AutoCAD 'Document' object, you can access the 'Database' object, which in turn allows you to instantiate a 'CivilDocument', and from these objects you can also access their COM instances.
In this post, I will go through the process of porting the 'Document' and 'DocumentManager' classes in 'Colibra' to make use of the new functionality and remove as many dependencies as possible.
Porting ‘Colibra.Document'
Looking at last year's implementation, the first thing we notices is that the 'Colibra.Document' class provides an internal constructor that takes both an AutoCAD 'Document' object and an instance of 'CivilDocument'.
C#
internal Document(acadappsvcs.Document acadDoc,
CivilDocument civilDoc)
{
m_ThisAcadDocument = acadDoc;
m_ThisCivilDocument = civilDoc;
m_ActiveTransaction = null;
}
VB.NET
Friend Sub New(acadDoc As acadappsvcs.Document, _
civilDoc As CivilDocument)
m_ThisAcadDocument = acadDoc
m_ThisCivilDocument = civilDoc
m_ActiveTransaction = Nothing
End Sub
This is no longer necessary because we can access the ‘Database’ object from the AutoCAD ‘Document’, which will allow us to instantiate a ‘CivilDocument’. Therefore, our first change will be to remove the ‘CivilDocument’ parameter from the internal constructor and initialize the member variable using the ‘Database’ object.
C#
internal Document(acadappsvcs.Document acadDoc)
{
m_ThisAcadDocument = acadDoc;
m_ThisCivilDocument = CivilDocument.GetCivilDocument(
m_ThisAcadDocument.Database);
m_ActiveTransaction = null;
}
VB.NET
Friend Sub New(acadDoc As acadappsvcs.Document)
m_ThisAcadDocument = acadDoc
m_ThisCivilDocument = CivilDocument.GetCivilDocument(
m_ThisAcadDocument.Database)
m_ActiveTransaction = Nothing
End Sub
At this point, our project will not compile because we have to update every location where we are instantiating a ‘Colibra.Document’ object to remove the ‘CivilDocument’ parameter. Thankfully, our code is well abstracted; therefore, the only class we need to update is the ‘Colibra.DocumentManager’ class.
Porting ‘Colibra.DocumentManager’
‘Colibra.DocumentManager’ had the responsibility to keep in sync the AutoCAD ‘Document’ object with its corresponding ‘CivilDocument’ object. This is no longer necessary, so we can start updating and refactoring the implementation.
There are two public interfaces that instantiate a ‘Colibra.Document’ in ‘Colibra.DocumentManager’: the static property ‘ActiveDocument’ and the static method ‘OpenDocument’. The implementation of both of these public interfaces make use of a private method ‘createNewAndActivateFromAutoCADDocument()’, which was the place we insured both objects were kept in sync.
C#
public static Document ActiveDocument
{
get
{
if (m_ActiveDocument == null)
{
createNewAndActivateFromAutoCADDocument(
acadappsvcs.Application
.DocumentManager.MdiActiveDocument);
}
return m_ActiveDocument;
}
}
public static Document OpenDocument(string fileName)
{
acadappsvcs.Document acadDoc = acadappsvcs.Application
.DocumentManager.Open(fileName);
createNewAndActivateFromAutoCADDocument(acadDoc);
return m_ActiveDocument;
}
private static void createNewAndActivateFromAutoCADDocument(
acadappsvcs.Document acadDoc)
{
CivilDocument civilDoc = getCivilDocumentAndActivate(acadDoc);
m_ActiveDocument = new Document(acadDoc, civilDoc);
}
private static CivilDocument getCivilDocumentAndActivate(
acadappsvcs.Document acadDoc)
{
acadappsvcs.Application.DocumentManager.MdiActiveDocument
= acadDoc;
return CivilApplication.ActiveDocument;
}
VB.NET
Public Shared ReadOnly Property ActiveDocument() As Document
Get
If m_ActiveDocument Is Nothing Then
createNewAndActivateFromAutoCADDocument(
acadappsvcs.Application. _
DocumentManager.MdiActiveDocument)
End If
Return m_ActiveDocument
End Get
End Property
Public Shared Function OpenDocument(fileName As String) As Document
Dim manager As DocumentCollection =
acadappsvcs.Application.DocumentManager
Dim acadDoc As acadappsvcs.Document = manager.Open(fileName)
createNewAndActivateFromAutoCADDocument(acadDoc)
Return m_ActiveDocument
End Function
Private Shared Sub createNewAndActivateFromAutoCADDocument(
acadDoc As acadappsvcs.Document)
Dim civilDoc As CivilDocument = getCivilDocumentAndActivate(acadDoc)
m_ActiveDocument = New Document(acadDoc, civilDoc)
End Sub
Private Shared Function getCivilDocumentAndActivate(
acadDoc As acadappsvcs.Document) As CivilDocument
acadappsvcs.Application.DocumentManager.MdiActiveDocument = acadDoc
Return CivilApplication.ActiveDocument
End Function
public static Document ActiveDocument
{
get
{
if (m_ActiveDocument == null)
{
m_ActiveDocument = new Document(acadappsvcs.Application
.DocumentManager.MdiActiveDocument);
}
return m_ActiveDocument;
}
}
public static Document OpenDocument(string fileName)
{
acadappsvcs.Document acadDoc = acadappsvcs.Application
.DocumentManager.Open(fileName);
return new Document(acadDoc);
}
Public Shared ReadOnly Property ActiveDocument() As Document
Get
If m_ActiveDocument Is Nothing Then
m_ActiveDocument = New Document(acadappsvcs.Application. _
DocumentManager.MdiActiveDocument)
End If
Return m_ActiveDocument
End Get
End Property
Public Shared Function OpenDocument(fileName As String) As Document
Dim manager As DocumentCollection =
acadappsvcs.Application.DocumentManager
Dim acadDoc As acadappsvcs.Document = manager.Open(fileName)
Return New Document(acadDoc)
End Function
You got a really useful blog. I have been here reading for about an hour. I am a newbie and your success is very much an inspiration for me.
Posted by: Niko Holmen | 05/27/2012 at 12:14 PM