how can i get and set property set data(extended data) in civil 3d using c#

how can i get and set property set data(extended data) in civil 3d using c#

Anonymous
Not applicable
9,315 Views
11 Replies
Message 1 of 12

how can i get and set property set data(extended data) in civil 3d using c#

Anonymous
Not applicable

Hi,

 how can i get and set property set data(extended data) in civil 3d using c#  on each entity using c#

0 Likes
9,316 Views
11 Replies
Replies (11)
Message 2 of 12

Anonymous
Not applicable

Have same issue...

0 Likes
Message 3 of 12

dunc.sargent
Participant
Participant

So in my situation I extra object information in three places:  Object Data, XData, and Extension Dictionaries.

The Property Sets are down in an Extension Dictionary.

 

DBObject dbObject = pcc.TheTransaction.GetObject( dbId, OpenMode.ForRead );
ObjectId dbIdExtDict = dbObject.ExtensionDictionary;
if( !dbIdExtDict.IsValid )
{
    Acad.Report( "Object has no extension dictionary." );
    break;
}
DBDictionary dbExtDict = pcc.TheTransaction.GetObject( dbIdExtDict, OpenMode.ForRead ) as DBDictionary;
if( dbExtDict == null )
{
    Acad.Report( "Object has no extension dictionary." );
    break;
}
Acad.Report( "Extension dictionary:" );
ReportDictionary( pcc, dbExtDict, 0 );
Acad.Report( "\n" );

pcc.TheTransaction is just a drawing transaction.  Acad.Report just burps some output to the command window.

 

Down inside ReportDictionary I go through the dictionaries looking for the PropertySet one.

public static void ReportDictionary( CaddDB.Context.PublisherCommand pcc, DBDictionary dbDictionary, int level )
{
    do
    {
        try
        {
            string indent = "    ";
            for( int i = 0; i < level; i++ )
                indent += "    ";

            int n = 0;
            foreach( DBDictionaryEntry ent in dbDictionary )
            {
                DBObject dbEntry = pcc.TheTransaction.GetObject( ent.Value, OpenMode.ForRead, false );
                if( dbEntry == null )
                    continue;
                string type = String.Format( "({0}): ", dbEntry.GetType().ToString() );
                Acad.Report( String.Format(
                    "{0}{1}.{2}: key: {3}; type: {4}",
                    indent,
                    level,
                    n++,
                    ent.Key,
                    type
                    ) );
                if( dbEntry.GetType() == typeof( Xrecord ) )
                {
                    Xrecord xRec = dbEntry as Xrecord;
                    if( xRec == null )
                        continue;
                    ReportRecord( pcc, xRec, level + 1 );
                    continue;
                }
                if( dbEntry.GetType() == typeof( DBDictionary ) )
                {
                    DBDictionary dbd = dbEntry as DBDictionary;
                    if( dbd == null )
                        continue;
                    ReportDictionary( pcc, dbd, level + 1 );
                    continue;
                }
                if( dbEntry.GetType() == typeof( PropertySet ) )
                {
                    PropertySet ps = dbEntry as PropertySet;
                    if( ps == null )
                        continue;
                    ReportPropertySet( pcc, ps, level + 1 );
                    continue;
                }            }
        }
        catch( System.Exception ex )
        {
            Chronicle.AddException( ex );
        }
    }
    while( false );
}

 

 

 

public static void ReportPropertySet( CaddDB.Context.PublisherCommand pcc, PropertySet ps, int level )
{
    do
    {
        try
        {
            string indent = "    ";
            for( int i = 0; i < level; i++ )
                indent += "    ";
            ObjectId idDef = ps.PropertySetDefinition;
            // pcc.TheTransaction is a drawing transaction
            PropertySetDefinition propSetDef = (PropertySetDefinition)pcc.TheTransaction.GetObject( idDef, OpenMode.ForRead );
            PropertyDefinitionCollection propDefCol = propSetDef.Definitions;
            // create a list so that it's easier to index later
            PropertyDefinitionList propDefList = new PropertyDefinitionList();
            foreach( PropertyDefinition propDef in propDefCol )
            {
                propDefList.Add( propDef );
            }
            PropertySetDataCollection psdc = ps.PropertySetData;
            foreach( PropertySetData psd in psdc )
            {
                PropertyDefinition[] ies = propDefList.Where( x => x.Id == psd.Id ).ToArray();
                if( ies.Count() > 0 )
                {
                    PropertyDefinition propDef = ies[0];
                    Acad.Report(
                            $"{indent}{psd.Id}, {psd.DataType}, {propDef.Name} = {psd.GetData()}"
                         );
                }
                else
                {
                    Acad.Report(
                            $"{indent}{psd.Id}, {psd.DataType}, {psd.FieldBucketId} = {psd.GetData()}"
                         );
                }
            }
        }
        catch( System.Exception ex )
        {
            Chronicle.AddException( ex );
        }
    }
    while( false );
}

So in my example you get the value at psd.GetData(), and you could use SetData() as you like.

 

I hope that helps.

 

 

--dunc
0 Likes
Message 4 of 12

norman.yuan
Mentor
Mentor

Great code, @dunc.sargent

 

Since your code actually uses class "PropertySet", I assume that the DLL project has AecPropDataMgd.dll set as reference. If so, why bother to check ExtensionDictionary to determine if PropertySet data existence, and if yes, cast the Dictionary entry as PropertySet object?

 

These 2 methods:

 

PropertyDataServices.GetPropertytSetDefinitionUsed(DBObject ent)

PropertyDataServices.GetPropertySet(DBObject ent, ObjectId setdefId)

 

would let us find all PropertySets attached to an Entity without the need to dig into the ExtensionDictionary first.

 

 

Norman Yuan

Drive CAD With Code

EESignature

Message 5 of 12

dunc.sargent
Participant
Participant

I was exploring through extension dictionaries in general before I added the PropertySet stuff.  When I do a specific PropertySet task, I'll certainly use the PropertyDataServices.  Those are good tips, thanks for that!   

--dunc
0 Likes
Message 6 of 12

lu_an_jie
Advocate
Advocate

https://github.com/AndreasLuka/ALC-C3D-LX/tree/master/ALC-SolidStair

Is a complete plug-in using property sets to create a solid stair

It includes functions for

  • during start-up sanity check if property set definition exist and if not create a property set definition
  • write, read and update  property sets attached to object
  • create object based on property set data

 

Regards

Andreas Luka (Lu An Jie)

http://www.luka-consult.de

Creator of the LX-Stair App for Civil 3D
0 Likes
Message 7 of 12

moonlikestoneBX57A
Enthusiast
Enthusiast

Thanks for your nice code, @dunc.sargent 

After I try to use setData() to add new property in the property set, I got some question:

I can get the new property information in the runtime of program.

After the program was finished, the new property will not be found in the object information.

 

Do I need to update the property definition of the object?

Or the property set need to be added by other method?

 

 

0 Likes
Message 8 of 12

lu_an_jie
Advocate
Advocate

Could pleas p;ost your code, so i can have a look to it.

Regards

Andreas Luka (Lu An Jie)

http://www.luka-consult.de

Creator of the LX-Stair App for Civil 3D
0 Likes
Message 9 of 12

moonlikestoneBX57A
Enthusiast
Enthusiast

Hi, @lu_an_jie:

This is my code to add new property into the property set:

Using:

using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.DatabaseServices;
using civilAppSer = Autodesk.Civil.ApplicationServices;
using civilApp = Autodesk.AutoCAD.ApplicationServices.Application;
using Autodesk.Aec.PropertyData.DatabaseServices;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.Civil.DatabaseServices;
using Autodesk.Civil.DatabaseServices;
using Autodesk.AutoCAD.DatabaseServices;

 

Code:

using(Transaction ts = civilApp.DocumentManager.MdiActiveDocument.Database.TransactionManager.StartTransaction())
  {

ObjectIdCollection id = doc.GetPipeNetworkIds(); if (id == null) civilApp.DocumentManager.MdiActiveDocument.Editor.WriteMessage("No Pipe network."); else { Network network = ts.GetObject(id[0], OpenMode.ForWrite) as Network; Pipe pipe = ts.GetObject(network.GetPipeIds()[0], OpenMode.ForWrite) as Pipe; ObjectIdCollection psdColl = PropertyDataServices.GetPropertySets(pipe); if (psdColl == null) { MessageBox.Show("Object has not Property Set"); return; } MessageBox.Show("This object has" + psdColl.Count + "Property Set"); PropertySet set = psdColl[0].GetObject(OpenMode.ForWrite, false) as PropertySet; ObjectId idDef = set.PropertySetDefinition; PropertySetDefinition def = (PropertySetDefinition)ts.GetObject(idDef, OpenMode.ForWrite); MessageBox.Show(def.Name); PropertyDefinitionCollection propDefColl = def.Definitions; PropertyDefinition Newdef = new PropertyDefinition(); Newdef.DataType = Autodesk.Aec.PropertyData.DataType.Text; //類型 Newdef.Name = "NewAutoTestProperty"; Newdef.Description = Newdef.Name; Newdef.IsVisible = true; def.Definitions.Add(Newdef); foreach (PropertyDefinition propDef in propDefColl) { if (propDef != null) MessageBox.Show(propDef.Name); } }
}

 

Thanks for your help!

0 Likes
Message 10 of 12

lu_an_jie
Advocate
Advocate

Your transaction is incomplete., ts.Commit()  is missing.

 

I also would recommend some more changes to make your routine safer. and easier to read.

 

First easier read:

set variable for document, database  and editor 

Document doc = Application.DocumentManager.MdiActiveDocument;     
Database db = doc.Database;
TransactionManager tm = db.TransactionManager;
Editor ed = doc.Editor;

Second usability:

Use MessageBox or Editor for Error messages.

 

Second safety, logic performance :

 

if (id == null)
{ doc.Editor.WriteMessage("No Pipe network.");
return;
}

//no need for else as you already leave the function in case of no network

using(Transaction ts = doc.Database.TransactionManager.StartTransaction())
{
try
{
// network and pipe need only read rights
Network network = ts.GetObject(id[0], OpenMode.ForRead) as Network;
Pipe pipe = ts.GetObject(network.GetPipeIds()[0], OpenMode.ForRead) as Pipe;

// your code here

// commit your changes
ts.Commit ();
}
catch (Exception ex)
{
doc.Editor.WriteMessage(ex.Message);
}
}

No need to open a transaction if you do not have a pipe network 

Network and pipes you put only ForRead

Use try and catch  for write operation, so you can see what's may going wrong

Write your data in to the drawing by committing the transaction

Regards

Andreas Luka (Lu An Jie)

http://www.luka-consult.de

Creator of the LX-Stair App for Civil 3D
Message 11 of 12

Anonymous
Not applicable

Is there any way to do this with using the PropertySet class and referencing the AecPropDataMgd.dll? Due to design automation restrictions: https://stackoverflow.com/questions/57853402/aec-assemblies-in-forge-design-automation/

0 Likes
Message 12 of 12

norman.yuan
Mentor
Mentor

Forge design automation's support for AutoCAD verticals has always been a gray area (or a work in progress, to put it in better words) as to whether full vertical-specific APIs/features are available or not. I think you'd better directly ask Autodesk's Forge support team for a clear answer.

Norman Yuan

Drive CAD With Code

EESignature

0 Likes