Author Topic: Solved - eInvalidInput in AttributeReference.SetAttributeFromBlock() in BricsCAD  (Read 936 times)

0 Members and 2 Guests are viewing this topic.

Bernd

  • Newt
  • Posts: 27
I'm trying to port an  AutoCAD application to BricsCAD. Most just works fine out of the box but I'm struggling with a method that draws blocks with attributes.
In AutoCAD this snippet works without a problem:
Code - C#: [Select]
  1. using (var modelSpace = (AcadDbServices.BlockTableRecord)trans.GetObject(blockTable[AcadDbServices.BlockTableRecord.ModelSpace], AcadDbServices.OpenMode.ForWrite))
  2. using (var blockDefinition = (AcadDbServices.BlockTableRecord)trans.GetObject(blockTable[block], AcadDbServices.OpenMode.ForRead))
  3. {
  4.     if (!blockDefinition.HasAttributeDefinitions)
  5.         CreateBlockDefinitionWithAttributes(trans, block, attributes.Keys);
  6.  
  7.     using (var blockReference = new AcadDbServices.BlockReference(position, blockDefinition.ObjectId))
  8.     {
  9.         modelSpace.AppendEntity(blockReference);
  10.         trans.AddNewlyCreatedDBObject(blockReference, true);
  11.  
  12.         blockReference.ScaleFactors = new AcadGeometry.Scale3d(faktor);
  13.         blockReference.Rotation = drehung;
  14.         blockReference.Layer = layer;
  15.  
  16.         foreach (AcadDbServices.ObjectId oid in blockDefinition)
  17.         {
  18.             var attributeDefinition = trans.GetObject(oid, AcadDbServices.OpenMode.ForRead) as AcadDbServices.AttributeDefinition;
  19.             if (attributeDefinition == null || attributeDefinition.Constant)
  20.                 continue;
  21.  
  22.             using (var attributeReference = new AcadDbServices.AttributeReference())
  23.             {
  24.                 /* NEXT LINE CRASHES WITH eInvalidInput */
  25.                 attributeReference.SetAttributeFromBlock(attributeDefinition, blockReference.BlockTransform);
  26.                 attributeReference.TextString = attributes[attributeDefinition.Tag];
  27.  
  28.                 blockReference.AttributeCollection.AppendAttribute(attributeReference);
  29.                 trans.AddNewlyCreatedDBObject(attributeReference, true);
  30.             }
  31.         }
  32.     }
  33.     trans.Commit();
  34. }
  35.  
CreateBlockDefinitionWithAttributes() is defined like this:
Code - C#: [Select]
  1. private static void CreateBlockDefinitionWithAttributes(AcadDbServices.Transaction trans, string blockName, IEnumerable<String> attributes)
  2. {
  3.     AcadDbServices.Database dwg = AcadDbServices.HostApplicationServices.WorkingDatabase;
  4.  
  5.     try
  6.     {
  7.         if (String.IsNullOrEmpty(blockName))
  8.             throw new ArgumentException("Blockname darf nicht leer sein");
  9.  
  10.         using (var blockTable = (AcadDbServices.BlockTable)trans.GetObject(dwg.BlockTableId, AcadDbServices.OpenMode.ForWrite))
  11.         using (var blockDefinition = (AcadDbServices.BlockTableRecord)trans.GetObject(blockTable[blockName], AcadDbServices.OpenMode.ForWrite))
  12.         {
  13.             foreach (var attribute in attributes)
  14.             {
  15.                 using (var attributeDefinition = new AcadDbServices.AttributeDefinition())
  16.                 {
  17.                     attributeDefinition.Tag = attribute;
  18.                     attributeDefinition.Visible = false;
  19.  
  20.                     blockDefinition.AppendEntity(attributeDefinition);
  21.                     trans.AddNewlyCreatedDBObject(attributeDefinition, true);
  22.                 }
  23.             }
  24.         }
  25.     }
  26.     catch (Exception e)
  27.     {
  28.         /* do something */
  29.     }
  30. }
  31.  
In BricsCAD the code crashes in line 28 attributeReference.SetAttributeFromBlock(attributeDefinition, blockReference.BlockTransform);

Any idea what might be causing this?

Thanks, Bernd
« Last Edit: February 17, 2020, 06:42:34 AM by Bernd »

owenwengerd

  • Bull Frog
  • Posts: 440
Re: eInvalidInput in AttributeReference.SetAttributeFromBlock() in BricsCAD
« Reply #1 on: February 07, 2020, 06:18:59 PM »
Does it help if you AppendAttribute() before SetAttributeFromBlock()? Or maybe try calling SetDatabaseDefaults() before SetAttributeFromBlock().

Bernd

  • Newt
  • Posts: 27
Re: eInvalidInput in AttributeReference.SetAttributeFromBlock() in BricsCAD
« Reply #2 on: February 10, 2020, 02:12:33 AM »
Does it help if you AppendAttribute() before SetAttributeFromBlock()? Or maybe try calling SetDatabaseDefaults() before SetAttributeFromBlock().
No, unfortunately not. Neither putting blockReference.AttributeCollection.AppendAttribute(attributeReference); in front of attributeReference.SetAttributeFromBlock(attributeDefinition, blockReference.BlockTransform); nor calling SetDataBaseDefaults() stops the code from crashing.

MickD

  • Gator
  • Posts: 3341
  • (x-in)->[process]->(y-out)
Re: eInvalidInput in AttributeReference.SetAttributeFromBlock() in BricsCAD
« Reply #3 on: February 10, 2020, 02:34:56 AM »
Code - C#: [Select]
  1. using (var attributeDefinition = new AcadDbServices.AttributeDefinition()) // does the db look after this ref??
  2.  

Just thinking out loud here but maybe the attributeDefinition pointer (reference) is being released (at the end of each loop) before it's added to the db?

or

Maybe you need to add this def to the db (commit it in an inner transaction) before modifying it?

Forth is like the Tao: it is a Way, and is realized when followed.
Its fragility is its strength; its simplicity is its direction - Michael Ham

Lao Tzu: “To attain knowledge, add things
every day; to obtain wisdom, remove things every day.”

Bernd

  • Newt
  • Posts: 27
Re: eInvalidInput in AttributeReference.SetAttributeFromBlock() in BricsCAD
« Reply #4 on: February 10, 2020, 06:03:49 AM »
Code - C#: [Select]
  1. using (var attributeDefinition = new AcadDbServices.AttributeDefinition()) // does the db look after this ref??
  2.  

Just thinking out loud here but maybe the attributeDefinition pointer (reference) is being released (at the end of each loop) before it's added to the db?

or

Maybe you need to add this def to the db (commit it in an inner transaction) before modifying it?

But shouldn't it have been added to the db via trans.AddNewlyCreatedDbObject()?
Nevertheless tried this:
Code - C#: [Select]
  1.     if (!blockDefinition.HasAttributeDefinitions)
  2.     {
  3.         var innerTransaction = dwg.TransactionManager.StartTransaction();
  4.         CreateBlockDefinitionWithAttributes(innerTransaction, block, attributes.Keys);
  5.     }
  6.  
and then in CreateBlockDefinitionWithAttributes():
Code - C#: [Select]
  1. ...
  2.                     foreach (var attribute in attributes)
  3.                     {
  4.                         using (var attributeDefinition = new AcadDbServices.AttributeDefinition())
  5.                         {
  6.                             attributeDefinition.Tag = attribute;
  7.                             attributeDefinition.Visible = false;
  8.  
  9.                             blockDefinition.AppendEntity(attributeDefinition);
  10.                             trans.AddNewlyCreatedDBObject(attributeDefinition, true);
  11.                         }
  12.                     }
  13.  
  14.                     trans.Commit();
  15. ...
  16.  
But still the same old eInvalidInput  :-( Before the call to CreateBlockDefinitionWithAttributes() I have two ActiveTransactions and afterwards again one as expected.
I read about BricsCAD treating objects opened via a closed transaction object differently than AutoCAD **, but I don't think this should pertain here - should it?

** I meant this: Access DBObject after transaction ends:
In AutoCAD, objects belonging to a transaction remain accessible in some cases even after the transaction has ended. In BricsCAD, all transaction resident objects are closed when the transaction ends.

It's Alive!

  • BricsCAD
  • Needs a day job
  • Posts: 6993
  • AKA Daniel
Re: eInvalidInput in AttributeReference.SetAttributeFromBlock() in BricsCAD
« Reply #5 on: February 10, 2020, 07:05:49 AM »
I think This:

Code: [Select]
using (var attributeDefinition = new AcadDbServices.AttributeDefinition())
{
    attributeDefinition.Tag = attribute;
    attributeDefinition.Visible = false;
    blockDefinition.AppendEntity(attributeDefinition);
    trans.AddNewlyCreatedDBObject(attributeDefinition, true);
}

Should be like this:

Code: [Select]
using (var attributeDefinition = new AcadDbServices.AttributeDefinition())
{
    blockDefinition.AppendEntity(attributeDefinition);
    trans.AddNewlyCreatedDBObject(attributeDefinition, true);
    attributeDefinition.Tag = attribute;
    attributeDefinition.Visible = false;
}

   

It's Alive!

  • BricsCAD
  • Needs a day job
  • Posts: 6993
  • AKA Daniel
Re: eInvalidInput in AttributeReference.SetAttributeFromBlock() in BricsCAD
« Reply #6 on: February 10, 2020, 07:14:46 AM »
The Using should be fine, the transaction won’t dispose the object a second time.

Also, you can cache the object ids for use outside a transaction. If you just need to open for read its faster to use the openclose transaction.
or objectid.open() in a using statement

It's Alive!

  • BricsCAD
  • Needs a day job
  • Posts: 6993
  • AKA Daniel
Re: eInvalidInput in AttributeReference.SetAttributeFromBlock() in BricsCAD
« Reply #7 on: February 10, 2020, 07:21:46 AM »
FYI, Teigha is a bit unforgiving, It’s a great habit to use set database defaults immediately after creating a DB object, or add it to the database

Bernd

  • Newt
  • Posts: 27
Re: eInvalidInput in AttributeReference.SetAttributeFromBlock() in BricsCAD
« Reply #8 on: February 10, 2020, 10:30:03 AM »
I think This:

Code: [Select]
using (var attributeDefinition = new AcadDbServices.AttributeDefinition())
{
    attributeDefinition.Tag = attribute;
    attributeDefinition.Visible = false;
    blockDefinition.AppendEntity(attributeDefinition);
    trans.AddNewlyCreatedDBObject(attributeDefinition, true);
}

Should be like this:

Code: [Select]
using (var attributeDefinition = new AcadDbServices.AttributeDefinition())
{
    blockDefinition.AppendEntity(attributeDefinition);
    trans.AddNewlyCreatedDBObject(attributeDefinition, true);
    attributeDefinition.Tag = attribute;
    attributeDefinition.Visible = false;
}
Sigh - still no success.
I'm really lost now. Just to make sure it's not the block definition itself that's causing problems, I skipped appending the attributes. This resulted in drawing the blocks correctly.
I think I posted the relevant part of the method in the beginning of the post, but just to make sure I haven't done anything stupid (BricsCAD-wise, as in AutoCAD everything runs smoothly), here's the whole method:
Code - C#: [Select]
  1. public static long DrawBlockWithAttributes(string block,
  2.                                            AcadGeometry.Point3d position,
  3.                                            string layer,
  4.                                            double faktor,
  5.                                            double drehung,
  6.                                            Dictionary<String, String> attribute,
  7.                                            bool useStartOpenClose)
  8. {
  9.     AcadDbServices.Database dwg = AcadDbServices.HostApplicationServices.WorkingDatabase;
  10.     AcadDbServices.Transaction trans = null;
  11.     long handle = -1L;
  12.  
  13.     using (trans = useStartOpenClose ? dwg.TransactionManager.StartOpenCloseTransaction() : dwg.TransactionManager.StartTransaction())
  14.     {
  15.         /*
  16.          * blockTable wird nicht in einen using-Block genommen,
  17.          * weil unter BricsCAD mit dem Disposen() der Transaktion auch ein darin allokiertes Objekt
  18.          * seine Gültigkeit verliert.
  19.          * Siehe https://www.bricsys.com/bricscad/help/en_US/CurVer/DevRef/index.html?page=source%2FdotNET_overview.htm
  20.          * */
  21.         AcadDbServices.BlockTable blockTable = null;
  22.         try
  23.         {
  24.             if (String.IsNullOrEmpty(block))
  25.                 throw new ArgumentException("Blockname darf nicht leer sein");
  26.  
  27.             AcadDbServices.ObjectId blockTableId = dwg.BlockTableId;
  28.             blockTable = (AcadDbServices.BlockTable)trans.GetObject(blockTableId, AcadDbServices.OpenMode.ForRead, true);
  29.             if (!blockTable.Has(block))
  30.                 /* Inserts the block and calls Commit() on the transaction parameter */
  31.                 InsertBlock(block, dwg, trans);
  32.  
  33.             if (trans.IsDisposed)
  34.             {
  35.                 trans = useStartOpenClose ? dwg.TransactionManager.StartOpenCloseTransaction() : dwg.TransactionManager.StartTransaction();
  36. #if BRX_APP
  37.                 blockTable = (AcadDbServices.BlockTable)trans.GetObject(blockTableId, AcadDbServices.OpenMode.ForRead, true);
  38. #endif
  39.             }
  40.  
  41.             using (var modelSpace = (AcadDbServices.BlockTableRecord)trans.GetObject(blockTable[AcadDbServices.BlockTableRecord.ModelSpace], AcadDbServices.OpenMode.ForWrite))
  42.             using (var blockDefinition = (AcadDbServices.BlockTableRecord)trans.GetObject(blockTable[block], AcadDbServices.OpenMode.ForRead))
  43.             {
  44.                 if (!blockDefinition.HasAttributeDefinitions)
  45.                     CreateBlockDefinitionWithAttributes(trans, block, attribute.Keys);
  46.  
  47.                 using (var blockReference = new AcadDbServices.BlockReference(position, blockDefinition.ObjectId))
  48.                 {
  49.                     modelSpace.AppendEntity(blockReference);
  50.                     trans.AddNewlyCreatedDBObject(blockReference, true);
  51.  
  52.                     handle = blockReference.Handle.Value;
  53.  
  54.                     blockReference.ScaleFactors = new AcadGeometry.Scale3d(faktor);
  55.                     blockReference.Rotation = drehung;
  56.                     blockReference.Layer = layer;
  57.  
  58.                     foreach (AcadDbServices.ObjectId oid in blockDefinition)
  59.                     {
  60.                         var attributeDefinition = trans.GetObject(oid, AcadDbServices.OpenMode.ForRead) as AcadDbServices.AttributeDefinition;
  61.                         if (attributeDefinition == null || attributeDefinition.Constant)
  62.                             continue;
  63.  
  64.                         using (var attributeReference = new AcadDbServices.AttributeReference())
  65.                         {
  66.                             blockReference.AttributeCollection.AppendAttribute(attributeReference);
  67.                             trans.AddNewlyCreatedDBObject(attributeReference, true);
  68.  
  69.                             //attributeReference.SetDatabaseDefaults();
  70.                             attributeReference.SetAttributeFromBlock(attributeDefinition, blockReference.BlockTransform);
  71.                             attributeReference.TextString = attribute[attributeDefinition.Tag];
  72.                         }
  73.                     }
  74.                 }
  75.                 trans.Commit();
  76.  
  77.                 return handle;
  78.             }
  79.         }
  80.         catch (Exception e)
  81.         {
  82.             // ... do something
  83.         }
  84.         finally
  85.         {
  86.             blockTable.Dispose();
  87.         }
  88.     }
  89. }
  90.  
The method that inserts the block:
Code - C#: [Select]
  1. private static ObjectId InsertBlock(string block, Database dwg, Transaction trans)
  2. {
  3.     string blockPfad;
  4.     if (!_bloecke.ContainsKey(block + ".dwg"))
  5.         blockPfad = GibPfadZuBlock(block);
  6.     else
  7.         blockPfad = _bloecke[block];
  8.  
  9.     if (String.IsNullOrEmpty(blockPfad))
  10.         throw new System.Exception(String.Format("Konnte Block {0} nicht finden",
  11.                                                  block));
  12.     /* I *think* the outer transaction has to be committed for the block insertion to be successful */
  13.     trans.Commit();
  14.     trans.Dispose();
  15.  
  16.     ObjectId blockId;
  17.     using (var dwgMitBlock = new AcadDbServices.Database(false, false))
  18.     {
  19.         dwgMitBlock.ReadDwgFile(blockPfad, FileShare.Read, true, "");
  20.         blockId = dwg.Insert(block, dwgMitBlock, false);
  21.     }
  22.  
  23.     return blockId;
  24. }
  25.  

And finally the method that creates the block definition (or rather appends the attributes to the block existing definition)...

Code - C#: [Select]
  1. private static void CreateBlockDefinitionWithAttributes(AcadDbServices.Transaction trans, string blockName, IEnumerable<String> attributes)
  2. {
  3.     AcadDbServices.Database dwg = AcadDbServices.HostApplicationServices.WorkingDatabase;
  4.  
  5.     try
  6.     {
  7.         if (String.IsNullOrEmpty(blockName))
  8.             throw new ArgumentException("Blockname darf nicht leer sein");
  9.  
  10.         using (var blockTable = (AcadDbServices.BlockTable)trans.GetObject(dwg.BlockTableId, AcadDbServices.OpenMode.ForWrite))
  11.         using (var blockDefinition = (AcadDbServices.BlockTableRecord)trans.GetObject(blockTable[blockName], AcadDbServices.OpenMode.ForWrite))
  12.         {
  13.             foreach (var attribute in attributes)
  14.             {
  15.                 using (var attributsDefinition = new AcadDbServices.AttributeDefinition())
  16.                 {
  17.                     //attributsDefinition.SetDatabaseDefaults();
  18.                     blockDefinition.AppendEntity(attributsDefinition);
  19.                     trans.AddNewlyCreatedDBObject(attributsDefinition, true);
  20.  
  21.                     attributsDefinition.Tag = attribute;
  22.                     attributsDefinition.Visible = false;
  23.                 }
  24.             }
  25.         }
  26.     }
  27.     catch (Exception e)
  28.     {
  29.         // ... do something
  30.     }
  31. }
  32.  
Anyone mind testing this code and see if it works? Or seeing something obviously stupid?

MickD

  • Gator
  • Posts: 3341
  • (x-in)->[process]->(y-out)
Re: eInvalidInput in AttributeReference.SetAttributeFromBlock() in BricsCAD
« Reply #9 on: February 10, 2020, 06:26:22 PM »
Got most of this setup for testing, still need a few pieces and I can take a look a bit later today if time permits.

Where are the bold italic objects defined?
if (!_bloecke.ContainsKey(block + ".dwg"))
                blockPfad = GibPfadZuBlock(block);
            else
                blockPfad = _bloecke[block];
Forth is like the Tao: it is a Way, and is realized when followed.
Its fragility is its strength; its simplicity is its direction - Michael Ham

Lao Tzu: “To attain knowledge, add things
every day; to obtain wisdom, remove things every day.”

Bernd

  • Newt
  • Posts: 27
Re: eInvalidInput in AttributeReference.SetAttributeFromBlock() in BricsCAD
« Reply #10 on: February 11, 2020, 02:05:42 AM »
Got most of this setup for testing, still need a few pieces and I can take a look a bit later today if time permits.

Where are the bold italic objects defined?
if (!_bloecke.ContainsKey(block + ".dwg"))
                blockPfad = GibPfadZuBlock(block);
            else
                blockPfad = _bloecke[block];

Code - C#: [Select]
  1. private static Dictionary<string, string> _bloecke; // blockname to blockpath, e.g. "myBlock", "C:\temp\myBlock.dwg"
  2. private static string _searchPath;  // directory that contains blocks (drawings)
  3.  
  4. internal static string GibPfadZuBlock(string blockName)
  5. {
  6.     try
  7.     {
  8.         if (String.IsNullOrEmpty(_searchPath) || String.IsNullOrEmpty(blockName))
  9.             return String.Empty;
  10.  
  11.         if (Path.GetExtension(blockName) != ".dwg")
  12.             blockName = Path.ChangeExtension(blockName, ".dwg");
  13.  
  14.         string[] files = Directory.GetFiles(_searchPath, blockName, SearchOption.AllDirectories);
  15.  
  16.         if (files.Length == 0)
  17.             return String.Empty;
  18.  
  19.         _bloecke[blockName] = files[0];
  20.         return files[0];
  21.     }
  22.     catch (System.Exception e)
  23.     {
  24.         // do something...
  25.     }
  26. }
  27.  
Thanks for taking your time!

n.yuan

  • Bull Frog
  • Posts: 285
Re: eInvalidInput in AttributeReference.SetAttributeFromBlock() in BricsCAD
« Reply #11 on: February 11, 2020, 09:42:19 AM »
Since you say the same code works OK in AutoCAD, but not in BricsCAD, there must be something BricsCAD implements in its .NET API subtly different. With this in mind, let me try a shoot in the dark.

the CreateBlockDefinitionWithAttributes() method, if I understand it correctly is to add AttributeDefinitions to an existing block definition. I also assume you add multiple attribute definitions mostly, especially in your test run, which resulted in the said error. This is where I thought the code is a bit weird: the code adds multiple attributes without setting any of the attribute properties, especially its position (meaning they would stack one on top of another). This would be fine theoretically (since you said it worked in AutoCAD), but practically, you would not want many attributes at the same position in most cases. The point here is that could be the attributeDefinition added in this way is not properly initialized due to how BricsCAD implement its .NET API (thus different from AutoCAD subtly)?

You might want to try these 2 ways to see what happens:

1. Only run the code of CreateBlockDefinitionWithAttributes() so an existing block definition is changed (attributes are added). Then in the drawing, you manually insert a block reference to it,see if you get error, or if the block reference is inserted correctly (with attribute references created, of course). You can also use block editor to examine the block definition to verify the added attribute definitions.

2. In the CreateBlockDefinitionWithAttributes(), after new AttributeDefinition created, explicitly set its position. Maybe, just maybe, this is something causes the trouble?

Bernd

  • Newt
  • Posts: 27
Re: eInvalidInput in AttributeReference.SetAttributeFromBlock() in BricsCAD
« Reply #12 on: February 14, 2020, 07:49:39 AM »
Hi Norman,
sorry for answering so late.

the CreateBlockDefinitionWithAttributes() method, if I understand it correctly is to add AttributeDefinitions to an existing block definition. I also assume you add multiple attribute definitions mostly, especially in your test run, which resulted in the said error. This is where I thought the code is a bit weird: the code adds multiple attributes without setting any of the attribute properties, especially its position (meaning they would stack one on top of another).

Everything correct. The attributes are not supposed to be visible in the drawing but only to get information about them in the property grid. This is why I don't care about their positions.

1. Only run the code of CreateBlockDefinitionWithAttributes() so an existing block definition is changed (attributes are added). Then in the drawing, you manually insert a block reference to it,see if you get error, or if the block reference is inserted correctly (with attribute references created, of course). You can also use block editor to examine the block definition to verify the added attribute definitions.

What I did was, I skipped the part of adding the attribute definitions to to the block reference. I think this is what you suggested. Then examining the block via block attribute manager shows the added attributes. Trying to insert the block via ''INSERT'' yields "Invalid input. BricsCAD cannot finish this operation" (more or less - translated from german). So you're on the right track.

2. In the CreateBlockDefinitionWithAttributes(), after new AttributeDefinition created, explicitly set its position. Maybe, just maybe, this is something causes the trouble?

Still to be tested...

It's Alive!

  • BricsCAD
  • Needs a day job
  • Posts: 6993
  • AKA Daniel
Re: eInvalidInput in AttributeReference.SetAttributeFromBlock() in BricsCAD
« Reply #13 on: February 14, 2020, 08:04:30 AM »
Do you have a sample VS Solution?

Bernd

  • Newt
  • Posts: 27
Re: eInvalidInput in AttributeReference.SetAttributeFromBlock() in BricsCAD
« Reply #14 on: February 14, 2020, 08:17:37 AM »
I'll try to put one together,  but it might take a bit. Right now I'm struggling with some really weird behaviour regarding MPolygons with bulges  :woow: . But that'll become another thread  :hahanot:

ribarm

  • Water Moccasin
  • Posts: 2253
  • Marko Ribar, architect
Re: eInvalidInput in AttributeReference.SetAttributeFromBlock() in BricsCAD
« Reply #15 on: February 14, 2020, 08:37:23 AM »
Do you know that after adding ATTRIBUTE to BLOCK, so called INSERT entity gets permanently "corrupted" - DXF flag (66 . 1) is added and then if you want to restore BLOCK as it was without attributes, it's impossible to remove flag (66 . 1) even if all attributes removed from block definition... I find this in LISP cumbersome, so perhaps if you operate in NET, you could investigate and this operation...
Relevant AutoLisp topic here :
http://www.theswamp.org/index.php?topic=55172.msg594767#msg594767
Marko Ribar, d.i.a. (graduated engineer of architecture)

:)

M.R. on Youtube

Bernd

  • Newt
  • Posts: 27
Re: eInvalidInput in AttributeReference.SetAttributeFromBlock() in BricsCAD
« Reply #16 on: February 17, 2020, 03:34:54 AM »
Do you have a sample VS Solution?
A sample solution can be downloaded here: https://my.hidrive.com/lnk/R0hpj1zF - attached!
What puzzles me is that the block reference gets inserted even though - in my understanding - the transaction is not being committed (because of the exception - is there an exception? I'm confused).
But one still cannot insert the block afterwards - see my answer to @n.yuan
« Last Edit: February 17, 2020, 05:17:55 AM by Bernd »

It's Alive!

  • BricsCAD
  • Needs a day job
  • Posts: 6993
  • AKA Daniel
Re: eInvalidInput in AttributeReference.SetAttributeFromBlock() in BricsCAD
« Reply #17 on: February 17, 2020, 05:31:36 AM »
a start, attributeDefinition.Height that is zero, makes teigha sad

Code: [Select]
if (attributeDefinition.Height == 0)
     attributeDefinition.Height = 1;
attributeReference .SetDatabaseDefaults();

Bernd

  • Newt
  • Posts: 27
Re: eInvalidInput in AttributeReference.SetAttributeFromBlock() in BricsCAD
« Reply #18 on: February 17, 2020, 06:40:27 AM »
 :smitten: Feel virtually kissed! That's it.

FYI, Teigha is a bit unforgiving, It’s a great habit to use set database defaults immediately after creating a DB object, or add it to the database
I'm afraid, this is exactly what you pointed out several answers ago  :oops:

Nevertheless - thanks a lot for your patience and to the others trying to help!

It's Alive!

  • BricsCAD
  • Needs a day job
  • Posts: 6993
  • AKA Daniel
I only added the attributeReference .SetDatabaseDefaults();, so you knew where to put the lines above it   :laugh:

n.yuan

  • Bull Frog
  • Posts: 285
I previously suspected:

<QUOTE>
The point here is that could be the attributeDefinition added in this way is not properly initialized due to how BricsCAD implement its .NET API
</QUOTE>

It looks like it has been proved: it is BricsCAD's .NET API implementation bug: AttributeDefinition has 0 height if not explicitly set.

I tried this with AutoCAD:

1. Create a TextStyle with its Text Height=0.0, and set this TextStyle as current (so, if Text/Attribute Def/Ref is created and its text style is not specified, this text Style would be used).

2. If manually create text/attribute definition in AutoCAD, and this Text Style is used, AutoCAD always gives a default text height of 0.2, and one cannot set the height to 0.0.

3, Following code adds attribute definition to an existing block (the same as the OP) without setting any property (so, the attribute definition would use current text style):

Code: [Select]
       private static ObjectId UpdateBlockDefinition(Document dwg)
        {
            var blkId = ObjectId.Null;
            var blkName = "TestBlock";

            using (var tran=dwg.TransactionManager.StartTransaction())
            {
                var bt = (BlockTable)tran.GetObject(dwg.Database.BlockTableId, OpenMode.ForRead);
                if (bt.Has(blkName))
                {
                    blkId = bt[blkName];

                    var blk = (BlockTableRecord)tran.GetObject(blkId, OpenMode.ForWrite);
                    var att = new AttributeDefinition();
                    att.Tag = "TAG A";
                    [color=blue]// att = 0.0 //When I explicitly try to set height to 0.0, AutoCAD raises exception[/color]
                    [color=red]blk.AppendEntity(att);[/color]
                    tran.AddNewlyCreatedDBObject(att, true);
                }

                tran.Commit();
            }

            return blkId;
        }

When I examine the varaiable "att" in debugging when a break point is placed in the red line, I can see AutoCAD set its height to 0.2 in spite the TextStyle applied to it has text height being 0.0 and the code does not explicitly set the attribute definition's height. Also, the blue line of code indicates that attribute definition height cannot be 0.0.

So, that is why the OP's code works in AutoCAD.

Since the same code does not work in BriscCAD, one could do the same debugging to examine if BricsCAD somehow makes/allows 0.0 height attribute definition being added into block definition. If so, that is BricsCAD's bug.