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

Layout from template - I am missing something here

6 REPLIES 6
Reply
Message 1 of 7
Anonymous
1028 Views, 6 Replies

Layout from template - I am missing something here

Hello all,

I 'm trying to create a function that simulates the AutoCAD command "Layout
from Template". The added code almost works: it recognizes the desired
layoutname in the layoutdictionary of the template, and I also get no errors
when I create a new Layout object with the found ObjectId. When I read its
properties, I also see the correct layoutname.

But an error "eAlreadyInDb" appears when the line "idLayout =
db.AddDBObject((DBObject)oLayout);" is executed, and the Layout is not added
to the current drawing. What am I missing here, is this a wrong method to
add a Layout object to a database? Or has anyone another solution for this
tool?

Thanks,
Henk


using System;
using System.Collections;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;


public static ObjectId importLayout(string filename, string layout)
{
ObjectId idLayout = ObjectId.Null;

DocumentLock oLock =
acadApp.DocumentManager.MdiActiveDocument.LockDocument();
Database db = HostApplicationServices.WorkingDatabase;
Transaction trans = db.TransactionManager.StartTransaction();
try
{
Database dbTemplate = new Database(false, false);
dbTemplate.ReadDwgFile(filename, System.IO.FileShare.Read,
true, null);

DBDictionary dbdLayout =
(DBDictionary)trans.GetObject(dbTemplate.LayoutDictionaryId,
OpenMode.ForRead, false, false);
foreach (DictionaryEntry deLayout in dbdLayout)
{
string sLayout = deLayout.Key.ToString();
if (sLayout.ToUpper() == layout.ToUpper())
{
idLayout = (ObjectId)deLayout.Value;
Layout oLayout = (Layout)trans.GetObject(idLayout,
OpenMode.ForRead, false, false);
idLayout = db.AddDBObject((DBObject)oLayout);
break;
}
}
trans.Commit();
}
catch (Autodesk.AutoCAD.Runtime.Exception ex)
{
trans.Dispose();
MessageBox.Show(ex.ToString(), "Error",
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
catch (System.Exception ex)
{
trans.Dispose();
MessageBox.Show(ex.ToString(), "Error",
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
finally
{
oLock.Dispose();
}
return idLayout;
}
6 REPLIES 6
Message 2 of 7
Anonymous
in reply to: Anonymous

You can't add an object that is in one database,
to another database.

You have to create a copy of the object and add
the copy to the destination database.

That's why you're getting eAlreadyInDb.

See the DeepCloneObjects and WBlockCloneObjects
methods of the Database for ways of copying and
adding the copies to another owner/database in one
step.

--
http://www.caddzone.com

AcadXTabs: MDI Document Tabs for AutoCAD 2008
Supporting AutoCAD 2000 through 2008
http://www.acadxtabs.com

"HeNkL" wrote in message news:5624623@discussion.autodesk.com...
Hello all,

I 'm trying to create a function that simulates the AutoCAD command "Layout
from Template". The added code almost works: it recognizes the desired
layoutname in the layoutdictionary of the template, and I also get no errors
when I create a new Layout object with the found ObjectId. When I read its
properties, I also see the correct layoutname.

But an error "eAlreadyInDb" appears when the line "idLayout =
db.AddDBObject((DBObject)oLayout);" is executed, and the Layout is not added
to the current drawing. What am I missing here, is this a wrong method to
add a Layout object to a database? Or has anyone another solution for this
tool?

Thanks,
Henk


using System;
using System.Collections;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;


public static ObjectId importLayout(string filename, string layout)
{
ObjectId idLayout = ObjectId.Null;

DocumentLock oLock =
acadApp.DocumentManager.MdiActiveDocument.LockDocument();
Database db = HostApplicationServices.WorkingDatabase;
Transaction trans = db.TransactionManager.StartTransaction();
try
{
Database dbTemplate = new Database(false, false);
dbTemplate.ReadDwgFile(filename, System.IO.FileShare.Read,
true, null);

DBDictionary dbdLayout =
(DBDictionary)trans.GetObject(dbTemplate.LayoutDictionaryId,
OpenMode.ForRead, false, false);
foreach (DictionaryEntry deLayout in dbdLayout)
{
string sLayout = deLayout.Key.ToString();
if (sLayout.ToUpper() == layout.ToUpper())
{
idLayout = (ObjectId)deLayout.Value;
Layout oLayout = (Layout)trans.GetObject(idLayout,
OpenMode.ForRead, false, false);
idLayout = db.AddDBObject((DBObject)oLayout);
break;
}
}
trans.Commit();
}
catch (Autodesk.AutoCAD.Runtime.Exception ex)
{
trans.Dispose();
MessageBox.Show(ex.ToString(), "Error",
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
catch (System.Exception ex)
{
trans.Dispose();
MessageBox.Show(ex.ToString(), "Error",
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
finally
{
oLock.Dispose();
}
return idLayout;
}
Message 3 of 7
Anonymous
in reply to: Anonymous

Thanks Tony,

I think I'm almost there. Running this code the new layout tab appears in
AutoCAD's screen with the correct layoutname. But also a fatal error appears
and AutoCAD shuts down. When I comment out the lines where the new layout is
set active, the fatal error is postponed, but also the new layout tab is not
visible yet. When I switch from Modelspace to "Layout1" my new layout tab
"A4" shows up (between "Layout1" and "Layout"2"). When I click on it, the
same fatal error appears. It looks like the new tab is locked or cannot be
accessed yet. Do you have an idea what is happening?

(I thought maybe I should define the owner as db.BlockTableId instead of
db.LayoutDictionaryId, but then other errors appear like eWasErased and
eWrongDatabase).

Henk


public static ObjectId importLayout(string filename, string
layoutname)
{
ObjectId idLayout = ObjectId.Null;

DocumentLock oLock =
acadApp.DocumentManager.MdiActiveDocument.LockDocument();
Database dbSource = new Database(false, false);
Database db = HostApplicationServices.WorkingDatabase;
Transaction trans = db.TransactionManager.StartTransaction();
try
{
dbSource.ReadDwgFile(filename, System.IO.FileShare.Read,
true, null);
ObjectId idDbdSource = dbSource.LayoutDictionaryId;
DBDictionary dbdLayout =
(DBDictionary)trans.GetObject(idDbdSource, OpenMode.ForRead, false, false);
foreach (DictionaryEntry deLayout in dbdLayout)
{
string sLayout = deLayout.Key.ToString();
if (sLayout.ToUpper() == layoutname.ToUpper())
{
idLayout = (ObjectId)deLayout.Value;
break;
}
}
if (idLayout != ObjectId.Null)
{
ObjectIdCollection idc = new ObjectIdCollection();
idc.Add(idLayout);
IdMapping im = new IdMapping();
db.WblockCloneObjects(idc, db.LayoutDictionaryId, im,
DuplicateRecordCloning.Replace, true);
IdPair ip = im.Lookup(idLayout);
idLayout = ip.Value;
LayoutManager lm = LayoutManager.Current;
lm.CurrentLayout = layoutname;
}
trans.Commit();
}
catch (Autodesk.AutoCAD.Runtime.Exception ex)
{
trans.Dispose();
MessageBox.Show(ex.ToString(), "Error",
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
catch (System.Exception ex)
{
trans.Dispose();
MessageBox.Show(ex.ToString(), "Error",
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
finally
{
dbSource.Dispose();
oLock.Dispose();
}
return idLayout;
}
Message 4 of 7
Anonymous
in reply to: Anonymous

Hi Henk
I've changed slightly your function
seems to be working for me nice

~'J'~

Public Shared Function importLayout(ByVal filename As String, ByVal layoutname As String) As ObjectId
Dim idLayout As ObjectId = ObjectId.Null
Dim doc As Document = acadApp.DocumentManager.MdiActiveDocument
Dim ed As Editor = doc.Editor
Dim oLock As DocumentLock = doc.LockDocument()
Dim dbSource As New Database(False, False)
Dim db As Database = HostApplicationServices.WorkingDatabase
Dim trans As Transaction = db.TransactionManager.StartTransaction()
Try
dbSource.ReadDwgFile(filename, System.IO.FileShare.Read, True, Nothing)
Dim idDbdSource As ObjectId = dbSource.LayoutDictionaryId
Dim dbdLayout As DBDictionary = DirectCast(trans.GetObject(idDbdSource, OpenMode.ForRead, False, False), DBDictionary)
For Each deLayout As DictionaryEntry In dbdLayout

Dim sLayout As String = deLayout.Key.ToString()
If sLayout.ToUpper() = layoutname.ToUpper() Then
idLayout = DirectCast(deLayout.Value, ObjectId)
Exit For
End If
Next
If idLayout <> ObjectId.Null Then
Dim idc As New ObjectIdCollection()
idc.Add(idLayout)
Dim im As IdMapping = New IdMapping()
Dim dbdict As DBDictionary = DirectCast(trans.GetObject(db.LayoutDictionaryId, OpenMode.ForRead, False, False), DBDictionary)

dbdict.UpgradeOpen()
db.WblockCloneObjects(idc, db.LayoutDictionaryId, im, DuplicateRecordCloning.MangleName, False)
Dim ip As IdPair = im.Lookup(idLayout)
idLayout = ip.Value
Dim lm As LayoutManager = LayoutManager.Current

lm.CurrentLayout = layoutname
dbdict.DecomposeForSave(DwgVersion.Current)
ed.Regen()
End If
trans.Commit()
Catch ex As Autodesk.AutoCAD.Runtime.Exception
MsgBox(ex.StackTrace)
'MessageBox.Show(ex.ToString(), "Error", MessageBoxButtons.OK, MessageBoxIcon.[Error])
Finally
trans.Dispose()
dbSource.Dispose()
oLock.Dispose()
End Try
Return idLayout
End Function
Message 5 of 7
Anonymous
in reply to: Anonymous

He thanks Fatty!!

It all works now. Reading your code I edited my C# code like this:
1. Changing this line did the fatal error disappear:
db.WblockCloneObjects(idc, db.LayoutDictionaryId, im,
DuplicateRecordCloning.MangleName, false);
2. Adding this line the function now activates the new layout correctly:
ed.Regen();
3. I didn't add your lines of code with DecomposeForSave(). Seems like it's
not necessary.


For all people who are interested here's the complete C# code again:

using System;
using System.Collections;
using AcadApp = Autodesk.AutoCAD.ApplicationServices.Application;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;

public static ObjectId importLayout(string filename, string
layoutname)
{
ObjectId idLayout = ObjectId.Null;

DocumentLock oLock =
acadApp.DocumentManager.MdiActiveDocument.LockDocument();
Database dbSource = new Database(false, false);
Database db = HostApplicationServices.WorkingDatabase;
Editor ed = AcadApp.DocumentManager.MdiActiveDocument.Editor;
Transaction trans = db.TransactionManager.StartTransaction();
try
{
dbSource.ReadDwgFile(filename, System.IO.FileShare.Read,
true, null);
ObjectId idDbdSource = dbSource.LayoutDictionaryId;
DBDictionary dbdLayout =
(DBDictionary)trans.GetObject(idDbdSource, OpenMode.ForRead, false, false);
foreach (DictionaryEntry deLayout in dbdLayout)
{
string sLayout = deLayout.Key.ToString();
if (sLayout.ToUpper() == layoutname.ToUpper())
{
idLayout = (ObjectId)deLayout.Value;
break;
}
}
if (idLayout != ObjectId.Null)
{
ObjectIdCollection idc = new ObjectIdCollection();
idc.Add(idLayout);
IdMapping im = new IdMapping();
db.WblockCloneObjects(idc, db.LayoutDictionaryId, im,
DuplicateRecordCloning.MangleName, false);
IdPair ip = im.Lookup(idLayout);
idLayout = ip.Value;

LayoutManager lm = LayoutManager.Current;
lm.CurrentLayout = layoutname;
ed.Regen();
}
trans.Commit();
}
catch (Autodesk.AutoCAD.Runtime.Exception ex)
{
trans.Dispose();
MessageBox.Show(ex.ToString(), "Error",
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
catch (System.Exception ex)
{
trans.Dispose();
MessageBox.Show(ex.ToString(), "Error",
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
finally
{
dbSource.Dispose();
oLock.Dispose();
}
return idLayout;
}


schreef in bericht news:5625167@discussion.autodesk.com...
Hi Henk
I've changed slightly your function
seems to be working for me nice
Message 6 of 7
Anonymous
in reply to: Anonymous

Hi Henk
When I've tried to use as template a
.DWG file then this line (with MangleName option):

>>db.WblockCloneObjects(idc, db.LayoutDictionaryId, im,
>>DuplicateRecordCloning.MangleName, false);

did ocurred the fatal error, but with .DWT files it work
correctly
the same story with .Replace option there

This line:
>>DecomposeForSave() might be unnesessary,
agreed

Cheers 🙂

~'J'~
Message 7 of 7
Anonymous
in reply to: Anonymous

Thank you for posting the complete program.

Tom

"HeNkL" wrote in message
news:5625977@discussion.autodesk.com...
He thanks Fatty!!

It all works now. Reading your code I edited my C# code like this:
1. Changing this line did the fatal error disappear:
db.WblockCloneObjects(idc, db.LayoutDictionaryId, im,
DuplicateRecordCloning.MangleName, false);
2. Adding this line the function now activates the new layout correctly:
ed.Regen();
3. I didn't add your lines of code with DecomposeForSave(). Seems like it's
not necessary.


For all people who are interested here's the complete C# code again:

using System;
using System.Collections;
using AcadApp = Autodesk.AutoCAD.ApplicationServices.Application;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;

public static ObjectId importLayout(string filename, string
layoutname)
{
ObjectId idLayout = ObjectId.Null;

DocumentLock oLock =
acadApp.DocumentManager.MdiActiveDocument.LockDocument();
Database dbSource = new Database(false, false);
Database db = HostApplicationServices.WorkingDatabase;
Editor ed = AcadApp.DocumentManager.MdiActiveDocument.Editor;
Transaction trans = db.TransactionManager.StartTransaction();
try
{
dbSource.ReadDwgFile(filename, System.IO.FileShare.Read,
true, null);
ObjectId idDbdSource = dbSource.LayoutDictionaryId;
DBDictionary dbdLayout =
(DBDictionary)trans.GetObject(idDbdSource, OpenMode.ForRead, false, false);
foreach (DictionaryEntry deLayout in dbdLayout)
{
string sLayout = deLayout.Key.ToString();
if (sLayout.ToUpper() == layoutname.ToUpper())
{
idLayout = (ObjectId)deLayout.Value;
break;
}
}
if (idLayout != ObjectId.Null)
{
ObjectIdCollection idc = new ObjectIdCollection();
idc.Add(idLayout);
IdMapping im = new IdMapping();
db.WblockCloneObjects(idc, db.LayoutDictionaryId, im,
DuplicateRecordCloning.MangleName, false);
IdPair ip = im.Lookup(idLayout);
idLayout = ip.Value;

LayoutManager lm = LayoutManager.Current;
lm.CurrentLayout = layoutname;
ed.Regen();
}
trans.Commit();
}
catch (Autodesk.AutoCAD.Runtime.Exception ex)
{
trans.Dispose();
MessageBox.Show(ex.ToString(), "Error",
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
catch (System.Exception ex)
{
trans.Dispose();
MessageBox.Show(ex.ToString(), "Error",
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
finally
{
dbSource.Dispose();
oLock.Dispose();
}
return idLayout;
}


schreef in bericht news:5625167@discussion.autodesk.com...
Hi Henk
I've changed slightly your function
seems to be working for me nice

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