Author Topic: Creating a framework for AutoCAD .NET  (Read 6976 times)

0 Members and 1 Guest are viewing this topic.

Jeff H

  • Needs a day job
  • Posts: 6150
Creating a framework for AutoCAD .NET
« on: September 25, 2012, 05:25:47 AM »
For starters a definition.
 
Framework – reusable object-orientated libraries.
 
Have had projects approved that needed to be done and sent and time for contractors to bid before the fiscal year so will be funded and have not had time to put anything together but in a way might be best as this would take some time and input from others before even attempting to create anything useful.
 
This is a precursor to Lets write a complete real world add-in, but don't you guys think having all the people here pitch in ideas and if wanted to help write the code we could come up with useful libraries?
They would be aimed at dealing with most common scenarios. People just using it and letting use know about errors encountered would be great help to making it more robust.
 
I know there has been attempts in the past but I think if we start off with some simple common scenarios and define exactly what our goal is we could build some useful libraries.
 
We could even try this thing called documentation I have heard other people talk about.
 
 
For starters could be iterating, adding, removing, etc... from the SymbolTables and/or standard dictionaries.
This might not be needed and too much hassle to just save some lines of code.
 
Should we expose extensions methods or wrap them up?
 
Here is something untested and slapped together quickly in minutes, but wrapping them up seems like it would be alot of work for all the different scenarios
Code - C#: [Select]
  1.  /// Class contains code written by or inspired by Tony Tanzillo http://www.theswamp.org/index.php?board=27.0
  2.     public class AcadSymbolTable<S, T> : IEnumerable<T>
  3.         where T : SymbolTableRecord
  4.         where S : SymbolTable
  5.     {
  6.         protected S symbolTable;        
  7.         protected TransactionManager transactionManager;
  8.         protected bool includesErased = false;    
  9.         public AcadSymbolTable(ObjectId symbolTableId)
  10.         {
  11.             this.transactionManager = symbolTableId.Database.TransactionManager;
  12.             this.symbolTable = (S)transactionManager.GetObject(symbolTableId, OpenMode.ForRead, false, false);
  13.         }
  14.         protected AcadSymbolTable(SymbolTable symbolTable)
  15.         {
  16.             this.transactionManager = symbolTable.Database.TransactionManager;
  17.             this.symbolTable = (S)symbolTable;
  18.         }
  19.         public virtual ObjectId Add(T symbolTblRecord)
  20.         {
  21.             if (!symbolTable.IsWriteEnabled)
  22.             {
  23.                 symbolTable.UpgradeOpen();
  24.             }
  25.             ObjectId id = symbolTable.Add(symbolTblRecord);
  26.             transactionManager.AddNewlyCreatedDBObject(symbolTblRecord, true);
  27.             return id;
  28.         }
  29.  
  30.        
  31.         public AcadSymbolTable<S, T> IncludingErased
  32.         {
  33.             get
  34.             {
  35.                 AcadSymbolTable<S, T> symbolTableErased = new AcadSymbolTable<S, T>(this.symbolTable.IncludingErased);
  36.                 symbolTableErased.includesErased = true;
  37.                 return symbolTableErased;
  38.             }
  39.         }
  40.         /// <summary>
  41.         /// Modified from original author: Tony Tanzillo
  42.         /// source: http://www.theswamp.org/index.php?topic=42025.msg471521#msg471521
  43.         /// </summary>
  44.         /// <param name="key"></param>
  45.         /// <returns></returns>
  46.         public bool Has(string key)
  47.         {
  48.             bool hasValue = symbolTable.Has(key);
  49.             if (includesErased)
  50.             {
  51.                 return hasValue;
  52.             }
  53.             try
  54.             {
  55.                 if (!symbolTable[key].IsNull)
  56.                 {
  57.                     return true;
  58.                 }
  59.                 return false;
  60.             }
  61.             catch (Autodesk.AutoCAD.Runtime.Exception ex)
  62.             {
  63.                 if (ex.ErrorStatus == Autodesk.AutoCAD.Runtime.ErrorStatus.KeyNotFound)
  64.                     return false;
  65.                 throw;
  66.             }
  67.         }
  68.         public bool Has(ObjectId ObjId)
  69.         {
  70.             return symbolTable.Has(ObjId);
  71.         }
  72.         public ObjectId this[string key]
  73.         {
  74.             get
  75.             {
  76.                 return symbolTable[key];
  77.             }
  78.         }
  79.  
  80.         public virtual IEnumerator<T> GetEnumerator()
  81.         {
  82.             foreach (ObjectId id in symbolTable)
  83.             {
  84.                 yield return (T)transactionManager.GetObject(id, OpenMode.ForRead, this.includesErased, false);
  85.             }
  86.         }
  87.         System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
  88.         {
  89.             return GetEnumerator();
  90.         }
  91.     }
  92.  

If you did something along the same idea not saying to use that implementation would it be better to break up BlockTableRecords into something like BlockDefinitions, Xrefs, Layouts, etc...?
 
Code - C#: [Select]
  1.     public class BlockDefinitions : AcadSymbolTable<BlockTable, BlockTableRecord>
  2.     {
  3.         protected BlockDefinitions(BlockTable blockTable) : base(blockTable) { }
  4.         public BlockDefinitions(ObjectId blockTableId) : base(blockTableId) { }
  5.  
  6.         public override IEnumerator<BlockTableRecord> GetEnumerator()
  7.         {
  8.             foreach (ObjectId id in symbolTable)
  9.             {
  10.                 BlockTableRecord btr = (BlockTableRecord)transactionManager.GetObject(id, OpenMode.ForRead, this.includesErased, false);
  11.                 if (!
  12.                     (btr.IsDependent
  13.                     || btr.IsLayout
  14.                     || btr.IsAnonymous
  15.                     || btr.IsAProxy
  16.                     || btr.IsFromExternalReference
  17.                     || btr.IsFromOverlayReference
  18.                     )
  19.                     )
  20.                 {
  21.                     yield return btr;
  22.                 }
  23.                
  24.             }
  25.         }
  26.     }
  27.  

Again that was something slapped together quickly and not well thought out, but was just something to just get conversation started.

Andrey Bushman

  • Swamp Rat
  • Posts: 864
Re: Creating a framework for AutoCAD .NET
« Reply #1 on: September 25, 2012, 06:59:51 AM »
The creating Framework it is big theme. I think, what for this must be created individual forum here. I can give my codes in this, and I can rewrite all my code comments and documentations for English, without Russian.

For such Framework must be thinking namespaces. For example:
Code - C#: [Select]
  1. using swApp = TheSwamp.AutoCAD.ApplicationServices;
  2. using swEd = TheSwamp.AutoCAD.EditorInput;
  3. using swDb = TheSwamp.AutoCAD.DatabaseServices;

e.t.c.

Today I using my namespaces, but I can rewrite it.
« Last Edit: September 25, 2012, 07:05:51 AM by Andrey »

Jeff H

  • Needs a day job
  • Posts: 6150
Re: Creating a framework for AutoCAD .NET
« Reply #2 on: September 25, 2012, 07:40:10 AM »
That would be great and yes Andrey naming and how and what goes in what namespace would be very important.
Good naming of classes and methods can be some of the best documentation and planned and getting in to that more deeply after people showed intrest.
 
 
Thanks again!
 
« Last Edit: September 25, 2012, 07:50:16 AM by Jeff H »

Andrey Bushman

  • Swamp Rat
  • Posts: 864
Re: Creating a framework for AutoCAD .NET
« Reply #3 on: September 25, 2012, 07:46:21 AM »
That would be great and yes Andrey naming and how and what goes in what namespace would be very important.
Good naming of classes and methods can be some of the documentation and planned and getting in to that more deeply after people showed intrest.
 
Thanks again!
I will make it and I will place at this forum as an example.

MexicanCustard

  • Swamp Rat
  • Posts: 705
Re: Creating a framework for AutoCAD .NET
« Reply #4 on: September 25, 2012, 09:20:12 AM »
Just keep getting Tony T to post more extension methods.  Hell, we're half way there.  :-)
Revit 2019, AMEP 2019 64bit Win 10

Jeff H

  • Needs a day job
  • Posts: 6150
Re: Creating a framework for AutoCAD .NET
« Reply #5 on: September 25, 2012, 09:50:14 AM »
Just keep getting Tony T to post more extension methods.  Hell, we're half way there.  :)
I actually thought about calling it compiled TT framework.
« Last Edit: September 25, 2012, 12:51:34 PM by Jeff H »

Andrey Bushman

  • Swamp Rat
  • Posts: 864
Re: Creating a framework for AutoCAD .NET
« Reply #6 on: November 10, 2012, 06:27:14 AM »
Above in a topic I promised. Look my attached file.
Quote
This library contains object model for management of  autoloading plugins in AutoCAD. Are implemented as an old method of control by autoload (through the registry keys), as a new (through the Autodesk Exchange). Besides, the library provides a detailed information about all installed AutoCAD versions and their updates as local machine, as and network computers. 

For example, you can use this library in your own GUI application for read/write of autoload settings in registry, and of PackageContents.xml settings of 'bundles' for any installed AutoCAD. Also, you can use this library for the creating of report with detailed settings for the all installed AutoCADs, or for control of autoload settings at level of user groups. Your plugin's installer/uninstaller too can use this library.

This library doesn't depend on AutoCAD and can be used by external applications.
It is not autoloader, it is an object model.

I hope this will be useful for many people.
« Last Edit: November 10, 2012, 06:38:43 AM by Andrey »

TheMaster

  • Guest
Re: Creating a framework for AutoCAD .NET
« Reply #7 on: November 10, 2012, 10:06:56 PM »
For starters a definition.
 
Framework – reusable object-orientated libraries.
 
Have had projects approved that needed to be done and sent and time for contractors to bid before the fiscal year so will be funded and have not had time to put anything together but in a way might be best as this would take some time and input from others before even attempting to create anything useful.
 
This is a precursor to Lets write a complete real world add-in, but don't you guys think having all the people here pitch in ideas and if wanted to help write the code we could come up with useful libraries?
They would be aimed at dealing with most common scenarios. People just using it and letting use know about errors encountered would be great help to making it more robust.
 
I know there has been attempts in the past but I think if we start off with some simple common scenarios and define exactly what our goal is we could build some useful libraries.
 
We could even try this thing called documentation I have heard other people talk about.
 
 
For starters could be iterating, adding, removing, etc... from the SymbolTables and/or standard dictionaries.
This might not be needed and too much hassle to just save some lines of code.
 
Should we expose extensions methods or wrap them up?
 
Here is something untested and slapped together quickly in minutes, but wrapping them up seems like it would be alot of work for all the different scenarios

Code - C#: [Select]
  1. ....
  2.  

Again that was something slapped together quickly and not well thought out, but was just something to just get conversation started.

I think after you do a more detailed analysis of that example, you might also agree that there's no need for the generic parameter for the table type, because the code doesn't need to make a distinction between different types derived from SymbolTable. In other words, you can ditch the first generic argument and not even bother using the BlockTable type, but rather just use its base type (SymbolTable).

I'll offer an example that shows how there's little need for a dependence on the concrete types derived from SymbolTable.

I decided to take a few hours to pursue a more complete framework for code contract enforcement for LispFunctions, along the lines of the prototype I showed in another thread, and actually implemented most of those attributes types I showed.

Here's an excerpt from the working code, which is used to constraint an argument to a LispFunction, to be the name or the entity name of a symbol table entry. It doesn't have any specific dependence on any specific derived type, so it can be used for any type of symbol table: Note that nowhere in this code will you see any use of the concrete SymbolTable types (e.g., BlockTable, LayerTable, etc).

Code - C#: [Select]
  1.  
  2. /// SymbolNameAttribute:
  3. ///
  4. /// Constrains an argument to a LispFunction to be a string that
  5. /// is the user- or application-defined name of a symbol table
  6. /// entry (e.g., a layer, block, etc., existing or proposed).
  7. ///
  8. /// In addition to validating string names, this attribute can
  9. /// accept and validate the entity name of a symbol table entry,
  10. /// by setting the AcceptObjectId property to true. When that
  11. /// property is true, the caller can pass either the name of the
  12. /// symbol table entry as a string, or its entity name (in cases
  13. /// where the entry exists). The symbol table entry must reside
  14. /// in the database of the active document. To work with other
  15. /// databases, a type derived from this class can override the
  16. /// Database property to return the database that is used.
  17. ///
  18. /// This class can be used directly by specifying the managed
  19. /// wrapper type of the SymbolTableRecord for the given table,
  20. /// or the included LayerNameAttribute and BlockNameAttribute
  21. /// specializations can be used as well. The BlockNameAttribute
  22. /// specialization adds block-specific validation rules to the
  23. /// validation rules provided by this type (which are common to
  24. /// all types of symbol table entries).
  25. ///
  26. /// Specializaions for other symbol tables can also be easily
  27. /// implemented in just a few lines of code.
  28.  
  29. public class SymbolNameAttribute : StringAttribute
  30. {
  31.    string dxfName = string.Empty;
  32.    Type recordType = null;
  33.    RXClass recordClass = null;
  34.    ObjectId objectId = ObjectId.Null;
  35.    Func<Database, ObjectId> accessor = null;
  36.    string entryName = null;
  37.  
  38.    static Dictionary<Type, Func<Database, ObjectId>> accessors =
  39.       new Dictionary<Type, Func<Database, ObjectId>>();
  40.  
  41.    static SymbolNameAttribute()
  42.    {
  43.       accessors[typeof( BlockTableRecord )] = db => db.BlockTableId;
  44.       accessors[typeof( LayerTableRecord )] = db => db.LayerTableId;
  45.       accessors[typeof( LinetypeTableRecord )] = db => db.LinetypeTableId;
  46.       accessors[typeof( ViewTableRecord )] = db => db.ViewTableId;
  47.       accessors[typeof( ViewportTableRecord )] = db => db.ViewportTableId;
  48.       accessors[typeof( DimStyleTableRecord )] = db => db.DimStyleTableId;
  49.       accessors[typeof( RegAppTableRecord )] = db => db.RegAppTableId;
  50.       accessors[typeof( TextStyleTableRecord )] = db => db.TextStyleTableId;
  51.       accessors[typeof( UcsTableRecord )] = db => db.UcsTableId;
  52.    }
  53.  
  54.    SymbolNameAttribute( int position )
  55.       : base( position )
  56.    {
  57.       base.AcceptEmpty = false;
  58.       base.AcceptAllWhiteSpace = false;
  59.    }
  60.  
  61.    public SymbolNameAttribute( int position, Type symbolTableRecordType )
  62.       : this( position )
  63.    {
  64.       if( !symbolTableRecordType.IsSubclassOf( typeof( SymbolTableRecord ) ) )
  65.          InternalException( "Requires a type derived from SymbolTableRecord" );
  66.       this.recordType = symbolTableRecordType;
  67.       this.dxfName = symbolTableRecordType.Name.ParseLeft( "TableRecord" ).ToUpper();
  68.       this.recordClass = RXClass.GetClass( symbolTableRecordType );
  69.       this.accessor = accessors[symbolTableRecordType];
  70.       // this.IsDependent = Condition.False;
  71.    }
  72.  
  73.    public override bool IsSupportedType( short typeCode )
  74.    {
  75.       return base.IsSupportedType( typeCode )
  76.          || AcceptObjectId && Exists != Condition.False && typeCode == RTENAME;
  77.    }
  78.  
  79.    protected ObjectId SymbolTableId
  80.    {
  81.       get
  82.       {
  83.          return GetSymbolTableId( this.Database );
  84.       }
  85.    }
  86.  
  87.    protected virtual ObjectId GetSymbolTableId( Database database )
  88.    {
  89.       if( database == null )
  90.          throw new ArgumentNullException( "No database" );
  91.       if( !database.BlockTableId.IsValid )
  92.          throw new ArgumentException( "Invalid database" );
  93.       ObjectId id = accessor( database );
  94.       if( id.IsNull || !id.IsValid )
  95.          throw new InvalidOperationException( "Null or Invalid Symbol Table ObjectId" );
  96.       return id;
  97.    }
  98.  
  99.    /// <summary>
  100.    /// Condition.False = disallows vertical bar separator in name
  101.    /// (e.g., xref dependents) enforced on both names and objectIds.
  102.    /// Condition.True = require vertical bar separator in name.
  103.    /// Condition.None = accept but not require vertical bar separator.
  104.    /// </summary>
  105.  
  106.    public Condition IsDependent
  107.    {
  108.       get;
  109.       set;
  110.    }
  111.  
  112.    ///<summary>
  113.    /// If true, the caller can supply either the name of the
  114.    /// symbol table entry, or its entity name (as returned
  115.    /// by the LISP (tblobjname) function). Default is false.
  116.    /// </summary>
  117.  
  118.    public bool AcceptObjectId
  119.    {
  120.       get;
  121.       set;
  122.    }
  123.  
  124.    protected virtual Database Database
  125.    {
  126.       get
  127.       {
  128.          return HostApplicationServices.WorkingDatabase;
  129.       }
  130.    }
  131.  
  132.    /// <summary>
  133.    /// The ObjectId of the validated symbol table entry.
  134.    /// </summary>
  135.  
  136.    public ObjectId ObjectId
  137.    {
  138.       get
  139.       {
  140.          CheckIsValid();
  141.          if( string.IsNullOrEmpty( this.entryName ) )
  142.             ArgumentException( "Argument not validated" );
  143.          if( objectId.IsNull )
  144.          {
  145.             {
  146.                using( SymbolTable tbl = (SymbolTable) SymbolTableId.Open( OpenMode.ForRead ) )
  147.                {
  148.                   this.objectId = tbl[this.entryName];
  149.                }
  150.             }
  151.          }
  152.          if( this.objectId.IsNull || !this.objectId.IsValid )
  153.             throw new InvalidOperationException( "Null or invalid symbol table ObjectId" );
  154.          return this.objectId;
  155.       }
  156.    }
  157.  
  158.    protected void CheckIsValid()
  159.    {
  160.       if( !this.IsValid )
  161.          ArgumentException( "Argument has not been validated" );
  162.    }
  163.  
  164.    protected virtual void ValidateObjectId( ObjectId id )
  165.    {
  166.    }
  167.  
  168.    // This can get a string or an objectid
  169.    public override void Validate( TypedValue typedValue )
  170.    {
  171.       base.Validate( typedValue );
  172.       ObjectId id;
  173.       if( TryGetValue( typedValue, out id ) )
  174.       {
  175.          if( Exists == Condition.False )
  176.             ArgumentException( "Requires the name of a non-existing table entry" );
  177.          Validate( id );
  178.       }
  179.       else
  180.       {
  181.          string value = GetValue<string>( typedValue );
  182.          try
  183.          {
  184.             SymbolUtilityServices.ValidateSymbolName( value, IsDependent != Condition.False );
  185.          }
  186.          catch( System.Exception )
  187.          {
  188.             ArgumentException( "Invalid {0} name: {1}", dxfName, value );
  189.          }
  190.          this.entryName = value;
  191.          this.objectId = GetObjectId( value );
  192.          bool found = !this.objectId.IsNull;
  193.          ValidateExists( Exists, found, "{0} {1}", dxfName, value );
  194.          if( found )
  195.             this.entryName = ValidateSymbolTableRecord( this.objectId );
  196.       }
  197.    }
  198.  
  199.    private void Validate( ObjectId id )
  200.    {
  201.       if( id.IsNull || !id.IsValid )
  202.          ArgumentException( "Null or invalid ename" );
  203.       if( id.ObjectClass != this.recordClass )
  204.          ArgumentException( "Requires the name or entity name of a {0}", this.dxfName );
  205.       if( id.Database != this.Database )
  206.          ArgumentException( "The specified {0} is from the wrong database", this.dxfName );
  207.       this.entryName = ValidateSymbolTableRecord( id );
  208.       this.objectId = id;
  209.    }
  210.  
  211.    static RXClass symbolTableRecordClass = RXClass.GetClass( typeof( SymbolTableRecord ) );
  212.  
  213.    protected virtual string ValidateSymbolTableRecord( ObjectId id )
  214.    {
  215.       if( id.IsNull || !id.IsValid )
  216.          ArgumentException( "Null or invalid ObjectId" );
  217.       if( !id.ObjectClass.IsDerivedFrom( symbolTableRecordClass ) )
  218.          ArgumentException( "Specified ObjectId is not a SymbolTableRecord" );
  219.       using( SymbolTableRecord rec = (SymbolTableRecord) id.Open( OpenMode.ForRead ) )
  220.       {
  221.          ValidateSymbolTableRecord( rec );
  222.          return rec.Name;
  223.       }
  224.    }
  225.  
  226.    protected virtual void ValidateSymbolTableRecord( SymbolTableRecord rec )
  227.    {
  228.       ValidateCondition( IsDependent, rec.IsDependent, "externally-dependent entry" );
  229.    }
  230.  
  231.    ObjectId GetObjectId( string name )
  232.    {
  233.       if( !this.objectId.IsNull )
  234.          return this.objectId;
  235.       ObjectId tableId = SymbolTableId;
  236.       if( !tableId.IsNull && tableId.IsValid )
  237.       {
  238.          using( SymbolTable tbl = (SymbolTable) tableId.Open( OpenMode.ForRead ) )
  239.          {
  240.             if( tbl.Has( name ) )
  241.             {
  242.                ObjectId recId = tbl[name];
  243.                if( !recId.IsErased )
  244.                {
  245.                   this.objectId = recId;
  246.                   return recId;
  247.                }
  248.                foreach( ObjectId entry in tbl )
  249.                {
  250.                   using( SymbolTableRecord rec = (SymbolTableRecord) entry.Open( OpenMode.ForRead ) )
  251.                   {
  252.                      if( rec.Name.Equals( name, StringComparison.OrdinalIgnoreCase ) )
  253.                         return entry;
  254.                   }
  255.                }
  256.             }
  257.          }
  258.       }
  259.       return ObjectId.Null;
  260.    }
  261.  
  262.    bool Find( string name )
  263.    {
  264.       ObjectId id = SymbolTableId;
  265.       if( !id.IsNull && id.IsValid )
  266.       {
  267.          using( SymbolTable tbl = (SymbolTable) id.Open( OpenMode.ForRead ) )
  268.             return tbl.Has( name );
  269.       }
  270.       return false;
  271.    }
  272. }
  273.  
  274. /// Constrains an argument to be the name of a layer
  275. /// or the entity name of the layer as returned by
  276. /// the LISP (tblobjname) function
  277.  
  278. /// This is incomplete, and doesn't yet implement
  279. /// the code that validates the included rules.
  280.  
  281. public class LayerNameAttribute : SymbolNameAttribute
  282. {
  283.    public LayerNameAttribute( int position )
  284.       : base( position, typeof( LayerTableRecord ) )
  285.    {
  286.       LayerTableRecord ltr = null;
  287.    }
  288.  
  289.    /// Require or Reject frozen layers
  290.    public Condition IsFrozen
  291.    {
  292.       get;
  293.       set;
  294.    }
  295.  
  296.    /// Require or Reject hidden layers
  297.    public Condition IsHidden
  298.    {
  299.       get;
  300.       set;
  301.    }
  302.  
  303.    /// Require or Reject locked layers
  304.    public Condition IsLocked
  305.    {
  306.       get;
  307.       set;
  308.    }
  309.  
  310.    /// Require or Reject non-visible layers
  311.    public Condition IsOff
  312.    {
  313.       get;
  314.       set;
  315.    }
  316.  
  317.    /// Require or Reject plottable layers
  318.    public Condition IsPlottable
  319.    {
  320.       get;
  321.       set;
  322.    }
  323.  
  324.    /// Require or Reject reconciled layers
  325.    public Condition IsReconciled
  326.    {
  327.       get;
  328.       set;
  329.    }
  330.  
  331.    /// Require or Reject unreferenced layers
  332.    public Condition IsUsed
  333.    {
  334.       get;
  335.       set;
  336.    }
  337.  
  338.    /// Require or Reject layers with property overrides
  339.    public Condition HasOverrides
  340.    {
  341.       get;
  342.       set;
  343.    }
  344.    
  345.    public override Validate( TypedValue typedValue )
  346.    {
  347.       base.Validate( typedValue );
  348.      
  349.       /// TODO....
  350.    }
  351. }
  352.  
  353.  
  354.  
  355. /// Constrains an argument to be the name of a block
  356. /// or the entity name of the block, as returned by
  357. /// the LISP (tblobjname) function.
  358.  
  359. /// Includes rules for validating various properties
  360. /// of BlockTableRecord. For example, to require an
  361. /// argument to be the name or entity name of a block
  362. /// but reject layout and xref blocks, you would use
  363. /// the following attribute:
  364.  
  365. /// [LispFunction("somefunction")]
  366. /// [BlockName( 0 , AcceptObjectId = true, IsLayout = Condition.MustBeFalse, IsXref = Condition.MustBeFalse )]
  367. ///
  368.  
  369.  
  370. public class BlockNameAttribute : SymbolNameAttribute
  371. {
  372.    public BlockNameAttribute( int position )
  373.       : base( position, typeof( BlockTableRecord ) )
  374.    {
  375.    }
  376.  
  377.    // Require/Disallow xref blocks
  378.    public Condition IsXref
  379.    {
  380.       get;
  381.       set;
  382.    }
  383.  
  384.    // Require/Disallow xref overlay blocks
  385.    public Condition IsOverlay
  386.    {
  387.       get;
  388.       set;
  389.    }
  390.  
  391.    // Require/Disallow anonymous blocks
  392.    public Condition IsAnonymous
  393.    {
  394.       get;
  395.       set;
  396.    }
  397.  
  398.    // Require/Disallow dynamic blocks
  399.    public Condition IsDynamic
  400.    {
  401.       get;
  402.       set;
  403.    }
  404.  
  405.    // Require/Disallow layout blocks
  406.    public Condition IsLayout
  407.    {
  408.       get;
  409.       set;
  410.    }
  411.  
  412.    // Require/Disallow resolved xref blocks
  413.    public Condition IsResolved
  414.    {
  415.       get;
  416.       set;
  417.    }
  418.  
  419.    // Require/Disallow loaded blocks
  420.    public Condition IsLoaded
  421.    {
  422.       get;
  423.       set;
  424.    }
  425.  
  426.    protected override void ValidateSymbolTableRecord( SymbolTableRecord rec )
  427.    {
  428.       base.ValidateSymbolTableRecord( rec );
  429.       BlockTableRecord btr = rec as BlockTableRecord;
  430.       if( btr == null )
  431.          ArgumentException( "Object is not a BLOCK" );
  432.       bool xref = btr.IsFromExternalReference || btr.IsFromOverlayReference;
  433.       ValidateCondition( IsAnonymous, btr.IsAnonymous, "Anonymous block" );
  434.       ValidateCondition( IsDynamic, btr.IsDynamicBlock, "Dynamic block" );
  435.       ValidateCondition( IsLayout, btr.IsLayout, "Layout block" );
  436.       ValidateCondition( IsXref, btr.IsFromExternalReference, "External Reference" );
  437.       ValidateCondition( IsOverlay, btr.IsFromOverlayReference, "Overlay Reference" );
  438.       if( xref || btr.IsDependent )
  439.       {
  440.          ValidateCondition( IsResolved, btr.IsResolved, "Resolved external reference" );
  441.          ValidateCondition( IsLoaded, !btr.IsUnloaded, "Loaded external reference" );
  442.       }
  443.    }
  444. }
  445.  
  446.  
« Last Edit: November 11, 2012, 12:10:17 AM by TT »

TheMaster

  • Guest
Re: Creating a framework for AutoCAD .NET
« Reply #8 on: November 12, 2012, 05:36:23 PM »

Framework – reusable object-orientated libraries.
 
For starters could be iterating, adding, removing, etc... from the SymbolTables and/or standard dictionaries.
This might not be needed and too much hassle to just save some lines of code.
 
Should we expose extensions methods or wrap them up?
 
Here is something untested and slapped together quickly in minutes, but wrapping them up seems like it would be alot of work for all the different scenarios

Code - C#: [Select]
  1.  

Again that was something slapped together quickly and not well thought out, but was just something to just get conversation started.

Frameworks need to have some significant benefit in order to justify their use and the additional dependence that entails. Major benefits include programmer productivity, performance, and abstraction that supports code portability.  So my suggestion is, if you want to start a movement on collaborative development, you need to demonstrate how the outcome is going to offer significant benefits.

Without that, any proposal may be viewed as something that would exist mostly for its own sake, rather than because it offers significant benefits to those who may use it.

The problem as I see it, is that the wrapper that you showed, even though it was just a rough sketch, doesn't seem to offer much in terms of either of the aforementioned benefits, especially considering that it is for the most part, just 'mocking' the underlying objects it wraps, making its use not very much different from using the wrapped objects directly.

If the intention was abstraction as a means of insulating application code from the underling API's, then for what purpose? For unit testing?  To port the application code to another CADD program with a similar API? Those can be viewed as legitimate reasons for using a framework. I'm just not sure what your objectives are here.

« Last Edit: November 12, 2012, 05:42:23 PM by TT »

Jeff H

  • Needs a day job
  • Posts: 6150
Re: Creating a framework for AutoCAD .NET
« Reply #9 on: November 12, 2012, 05:54:00 PM »
My main intentions were to wrap up commonly used scenerios that would be reusable for anyone to use, but looks like without being able to sit in the same room and hash out what needs to be included and how best approach it would probably never amount to much.
 
As for the example that was just asking the question is it worth wrapping up the commonly used objects or just provideing extension methods.

TheMaster

  • Guest
Re: Creating a framework for AutoCAD .NET
« Reply #10 on: November 12, 2012, 06:16:11 PM »
My main intentions were to wrap up commonly used scenerios that would be reusable for anyone to use, but looks like without being able to sit in the same room and hash out what needs to be included and how best approach it would probably never amount to much.

As I mentioned. there needs to be some significant benefit to 'wrapping', and as I see it, a wrapper like the example you showed might be useful for abstraction (with an accompanying interface), but I don't see it as offering much in terms of other benefits. In other words, it isnt really all that much easier to use than the underlying APIs, and that's really what makes or breaks a wrapper-based approach.

Quote

As for the example that was just asking the question is it worth wrapping up the commonly used objects or just provideing extension methods.

I use extension methods quite extensively now because they offer the same benefits as wrappers, and they are far more flexible because they can target many types or derived types without having to write specializations for each.

An example of why extension methods can be better than dedicated wrappers, is the DisposableList<T> class that I posted here not long ago. As it turns out, that was a hairball that was far less flexible than this:

Code - C#: [Select]
  1.  
  2. // From my revised/refactored version of Fenton Web's BlockView.NET
  3.  
  4. public static class BlockViewExtensionMethods
  5. {
  6.    /// <summary>
  7.    ///
  8.    /// This extension method can be called on any IEnumerable<T>
  9.    /// where the element type T implements the IDisposable interface.
  10.    /// It's purpose is to guarantee the entire sequence is disposed
  11.    /// even if an exception is thrown by a call to Dispose() on any
  12.    /// element in the sequence.
  13.    ///
  14.    /// If the invocation target implements ICollection<T>, and the
  15.    /// optional clear argument is true, and the ICollection<T> is
  16.    /// is not read-only, the ICollection<T>.Clear() method is called.
  17.    ///
  18.    /// </summary>
  19.  
  20.    public static void DisposeItems<T>( this IEnumerable<T> items ) where T : IDisposable
  21.    {
  22.       DisposeItems<T>( items, false );
  23.    }
  24.  
  25.    public static void DisposeItems<T>( this IEnumerable<T> items, bool clear ) where T : IDisposable
  26.    {
  27.       DisposeItems( items.GetEnumerator(), 0 );
  28.       ICollection<T> collection = items as ICollection<T>;
  29.       if( collection != null && !collection.IsReadOnly && collection.Count > 0 )
  30.          collection.Clear();
  31.    }
  32.  
  33.    // if there's more than 20 exceptions we throw in the towel
  34.    // to avoid the risk of a fatal stack overflow:
  35.  
  36.    const int DISPOSEITEMS_MAX_RECURSION_DEPTH = 20;
  37.  
  38.    static void DisposeItems<T>( IEnumerator<T> e, int level ) where T: IDisposable
  39.    {
  40.       while( e.MoveNext() )
  41.       {
  42.          try
  43.          {
  44.             IDisposable disposable = e.Current;
  45.             if( disposable != null )
  46.                disposable.Dispose();
  47.          }
  48.          catch
  49.          {
  50.             if( level < DISPOSEITEMS_MAX_RECURSION_DEPTH )
  51.                DisposeItems( e, level + 1 );
  52.             throw;
  53.          }
  54.       }
  55.    }
  56. }
  57.  
  58.  

So you see, the above extension method makes it possible to dispose the elements of any object that implements IDisposable<T>, without having to store them in a dedicated List<T> based type.

Correction: that last sentence should have said "the above extension method makes it possible to dispose the elements of any object that implements IEnumerable<IDisposable>"
« Last Edit: November 13, 2012, 02:31:01 PM by TT »

Jeff H

  • Needs a day job
  • Posts: 6150
Re: Creating a framework for AutoCAD .NET
« Reply #11 on: November 12, 2012, 06:39:39 PM »
Thanks Tony,
 
As you know you must fully have a understanding or master the fundamentals and basics of subject to truly understand something, and that is where I am falling short.
I coud be an idiot or Autodesk just does not produce documentation with that in mind or is over my head but seems hard to get a basic understaniding how many things tie together and seems tough to figure what would be beneficial or not.
 
As of right now I have a AcdbMgdExtensions.dll, AcCoreExtensions.dll, & AcMgdExtensions.dll, where I have been placing extension classes in same namespace as the class it adds extensions to.

MP

  • Seagull
  • Posts: 17750
  • Have thousands of dwgs to process? Contact me.
Re: Creating a framework for AutoCAD .NET
« Reply #12 on: November 12, 2012, 07:11:29 PM »
...I coud be an idiot...

lulzy timing for a spelling mistake lol
Engineering Technologist • CAD Automation Practitioner
Automation ▸ Design ▸ Drafting ▸ Document Control ▸ Client
cadanalyst@gmail.comhttp://cadanalyst.slack.comhttp://linkedin.com/in/cadanalyst

Kerry

  • Mesozoic relic
  • Seagull
  • Posts: 11654
  • class keyThumper<T>:ILazy<T>
Re: Creating a framework for AutoCAD .NET
« Reply #13 on: November 12, 2012, 08:25:27 PM »
< .. >  or Autodesk just does not produce documentation with that in mind or is over my head but seems hard to get a basic understanding how many things tie together and seems tough to figure what would be beneficial or not.
 
< .. >

preaching to the choir Jeff.
... but be carefull, questioning the quality of documentation can send one into a depressing downward spiral  :|
kdub, kdub_nz in other timelines.
Perfection is not optional.
Everything will work just as you expect it to, unless your expectations are incorrect.
Discipline: None at all.

TheMaster

  • Guest
Re: Creating a framework for AutoCAD .NET
« Reply #14 on: November 12, 2012, 08:31:45 PM »
Thanks Tony,
 
As you know you must fully have a understanding or master the fundamentals and basics of subject to truly understand something, and that is where I am falling short.
I coud be an idiot or Autodesk just does not produce documentation with that in mind or is over my head but seems hard to get a basic understaniding how many things tie together and seems tough to figure what would be beneficial or not.
 
As of right now I have a AcdbMgdExtensions.dll, AcCoreExtensions.dll, & AcMgdExtensions.dll, where I have been placing extension classes in same namespace as the class it adds extensions to.

My recommendation is to use extension methods wherever possible, in preference to dedicated wrappers. In fact, the Linq2Lisp library I recently started updating originally used many dedicated wrapper types. The library itself is about 6 years old and predates extension methods, and even after extension methods were introduced the library still had to run on older runtimes that didn't support extension methods). In the latest revision I've done away with the majority of the wrappers, replacing them with extension methods.

Jeff H

  • Needs a day job
  • Posts: 6150
Re: Creating a framework for AutoCAD .NET
« Reply #15 on: November 13, 2012, 01:32:46 AM »
...I coud be an idiot...

lulzy timing for a spelling mistake lol
To confirm this I was lmaf that I misspelled idiot then look at it for a second, googled it, copied and pasted to make sure used same spelling then finally noticed "coud"
 
< .. >  or Autodesk just does not produce documentation with that in mind or is over my head but seems hard to get a basic understanding how many things tie together and seems tough to figure what would be beneficial or not.
 
< .. >

preaching to the choir Jeff.
... but be carefull, questioning the quality of documentation can send one into a depressing downward spiral  :|
I am surprised you do not hear more people bitching. Instead of code examples it would be nice have an explanation of the basics for the major components of the API and to their suprise maybe we could decide what the best decision is to accomplish a task.
 
Thanks Tony,

As you know you must fully have a understanding or master the fundamentals and basics of subject to truly understand something, and that is where I am falling short.
I coud be an idiot or Autodesk just does not produce documentation with that in mind or is over my head but seems hard to get a basic understaniding how many things tie together and seems tough to figure what would be beneficial or not.

As of right now I have a AcdbMgdExtensions.dll, AcCoreExtensions.dll, & AcMgdExtensions.dll, where I have been placing extension classes in same namespace as the class it adds extensions to.

My recommendation is to use extension methods wherever possible, in preference to dedicated wrappers. In fact, the Linq2Lisp library I recently started updating originally used many dedicated wrapper types. The library itself is about 6 years old and predates extension methods, and even after extension methods were introduced the library still had to run on older runtimes that didn't support extension methods). In the latest revision I've done away with the majority of the wrappers, replacing them with extension methods.

Thanks for clearing that up.

Andrey Bushman

  • Swamp Rat
  • Posts: 864
Re: Creating a framework for AutoCAD .NET
« Reply #16 on: November 13, 2012, 11:22:15 AM »
Anybody has tried to use (for testing) a my little DLL? :)

P.S. I have tested it on my virtual machines with AutoCAD 2009-2013 as admin, and as user. I hope that the code will work and for other programmers.
« Last Edit: November 13, 2012, 11:28:15 AM by Andrey »

Andrey Bushman

  • Swamp Rat
  • Posts: 864
Re: Creating a framework for AutoCAD .NET
« Reply #17 on: November 20, 2012, 02:54:52 AM »
On the basis of this library such small animal is born: