Author Topic: Insert Dynamic block  (Read 4857 times)

0 Members and 1 Guest are viewing this topic.

GegH1

  • Guest
Insert Dynamic block
« on: April 06, 2013, 06:31:28 AM »
I am trying to insert a dynamic block and manipulate it using the values of a form, width, length, etc...

The block has linear parameters and stretch actions. I can get it to work with fixed values and i have previously got a form to draw a series of boxes, but i can't seem to get the form to insert the block and manipulate it

I'm more than happy to pass the code on if anyone is willing to help.

WILL HATCH

  • Bull Frog
  • Posts: 450
Re: Insert Dynamic block
« Reply #1 on: April 06, 2013, 11:55:55 AM »
What's the error? At first it sounds like the code in your form may be updating in the wrong context.

TheMaster

  • Guest
Re: Insert Dynamic block
« Reply #2 on: April 06, 2013, 12:20:34 PM »
I am trying to insert a dynamic block and manipulate it using the values of a form, width, length, etc...

The block has linear parameters and stretch actions. I can get it to work with fixed values and i have previously got a form to draw a series of boxes, but i can't seem to get the form to insert the block and manipulate it

I'm more than happy to pass the code on if anyone is willing to help.

Well, a form doesn't insert blocks or draw boxes. Your code does that.

Without showing it, there's really not much anyone can do to help you.

fixo

  • Guest
Re: Insert Dynamic block
« Reply #3 on: April 06, 2013, 04:17:29 PM »
I am trying to insert a dynamic block and manipulate it using the values of a form, width, length, etc...

The block has linear parameters and stretch actions. I can get it to work with fixed values and i have previously got a form to draw a series of boxes, but i can't seem to get the form to insert the block and manipulate it

I'm more than happy to pass the code on if anyone is willing to help.
Here is quick code written on fly badly commented,
try this outside the form as is, then let us know how it works
Change block name and parameter names within the code

Code: [Select]
        [CommandMethod("indyn",  CommandFlags.Modal | CommandFlags.Redraw)]
        public static void InsertDynBlockUpdate()
        {

            Document doc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument;

            Database db = doc.Database;

            Editor ed = doc.Editor;

            string blkname = "dynrect";// block name

            BlockReference bref = null;
            try
            {
                using (Transaction tr = db.TransactionManager.StartTransaction())
                {
                    BlockTable bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead, false);

                    BlockTableRecord btr = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite, false);

                    BlockTableRecord blk = (BlockTableRecord)tr.GetObject(bt[blkname], OpenMode.ForRead, false);

                    Point3d ip = ed.GetPoint("\nPick insertion point: ").Value.TransformBy(ed.CurrentUserCoordinateSystem);

                    Plane plan = new Plane(Point3d.Origin, Vector3d.ZAxis);

                    bref = new BlockReference(ip, bt[blkname]);//   or blk.ObjectId;

                    btr.AppendEntity(bref);

                    tr.AddNewlyCreatedDBObject(bref, true);

                    SetAttributes(db, tr, bref);

                    UpdateBlockParams(bref, new List<double>() { 120, 12.5 });
                   
                    tr.Commit();
                }

            }
            catch (System.Exception ex)
            {
                ed.WriteMessage("\n{0}\n{1}", ex.Message, ex.StackTrace);
            }
            finally
            {
                Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument.Editor.WriteMessage("\n\t---\tDone?\t---\n");
            }
        }


        public static void SetAttributes(Database db, Transaction tr, BlockReference bref)
        {
            BlockTableRecord btrec = tr.GetObject(bref.BlockTableRecord, OpenMode.ForRead) as BlockTableRecord;

            if (btrec.HasAttributeDefinitions)
            {
                Autodesk.AutoCAD.DatabaseServices.AttributeCollection atcoll = bref.AttributeCollection;


                foreach (ObjectId subid in btrec)
                {
                    Entity ent = (Entity)subid.GetObject(OpenMode.ForRead);

                    AttributeDefinition attDef = ent as AttributeDefinition;


                    if (attDef != null)
                    {
                        AttributeReference attRef = new AttributeReference();

                        attRef.SetDatabaseDefaults();

                        attRef.SetAttributeFromBlock(attDef, bref.BlockTransform);

                        attRef.Position = attDef.Position.TransformBy(bref.BlockTransform);

                        attRef.Tag = attDef.Tag;

                        attRef.TextString = attDef.TextString;

                        attRef.AdjustAlignment(db);

                        atcoll.AppendAttribute(attRef);

                        tr.AddNewlyCreatedDBObject(attRef, true);

                    }

                }
            }
        }
        private static void UpdateBlockParams(BlockReference bref, List<double> dblvalues)
        {
            if (!bref.IsDynamicBlock)
            {
                Autodesk.AutoCAD.ApplicationServices.Application.ShowAlertDialog("Selected block is not Type of Dynamic! Exit...");
                return;
            }
            if (!bref.IsWriteEnabled)
            {
                bref.UpgradeOpen();
            }

            DynamicBlockReferencePropertyCollection dynprops = bref.DynamicBlockReferencePropertyCollection;

            List<string> pattern = new List<string>(new string[] {
"DoorWidth",//  Linear
"DoorHeight"//  Linear1
});

            foreach (DynamicBlockReferenceProperty prop in dynprops)
            {
                string pName = prop.PropertyName;
               
                if (pName.Equals(pattern[0], StringComparison.CurrentCulture))
                {
                    prop.Value = Convert.ToDouble(dblvalues[0]);

                }
                else if (pName.Equals(pattern[1], StringComparison.CurrentCulture))
                {
                    prop.Value = Convert.ToDouble(dblvalues[1]);

                }
                //else if (pName.Equals(pattern[2], StringComparison.CurrentCulture))
                //{
                //    prop.Value = Convert.ToDouble(dblvalues[2]);
                //}
                else
                {
                    //empty code line
                }
            }
        }

GegH1

  • Guest
Re: Insert Dynamic block
« Reply #4 on: April 07, 2013, 04:13:50 AM »
The full code gets rather long but on further investigation i am getting an eLockViolation at this point in the code:

            Dim myBlockTableRecord As BlockTableRecord = _
                myBlockTable(BTRToAddTo).GetObject(OpenMode.ForWrite)

The full code is here:

Imports Autodesk.AutoCAD.Runtime
Imports Autodesk.AutoCAD
Imports Autodesk.AutoCAD.DatabaseServices
Imports Autodesk.AutoCAD.EditorInput
Imports Autodesk.AutoCAD.Geometry
Imports Autodesk.AutoCAD.ApplicationServices
Imports Autodesk.AutoCAD.ApplicationServices.Application
Imports Autodesk.AutoCAD.LayerManager
Imports Autodesk.AutoCAD.Windows
Public Class Commands

    <CommandMethod("DrawShed")> _
    Public Sub DrawShed()

        Dim recFrm As New ShedForm()
        Application.ShowModelessDialog(recFrm)

    End Sub

End Class

Public Class InsBlock
    Public Function InsertBlock(ByVal DatabaseIn As Database, _
         ByVal BTRToAddTo As String, _
         ByVal InsPt As Geometry.Point3d, _
         ByVal BlockName As String, _
         ByVal XScale As Double, _
         ByVal YScale As Double, _
         ByVal ZScale As Double) As DatabaseServices.ObjectId
        Using myTrans As Transaction = DatabaseIn.TransactionManager.StartTransaction
            Dim myBlockTable As BlockTable = DatabaseIn.BlockTableId.GetObject(OpenMode.ForRead)
            'If the suppplied Block Name is not
            'in the specified Database, get out gracefully.
            If myBlockTable.Has(BlockName) = False Then
                Return Nothing
            End If
            'If the specified BlockTableRecord does not exist,
            'get out gracefully
            If myBlockTable.Has(BTRToAddTo) = False Then
                Return Nothing
            End If
            Dim myBlockDef As BlockTableRecord = _
                myBlockTable(BlockName).GetObject(OpenMode.ForRead)
            Dim myBlockTableRecord As BlockTableRecord = _
                myBlockTable(BTRToAddTo).GetObject(OpenMode.ForWrite)
            'Create a new BlockReference
            Dim myBlockRef As New BlockReference(InsPt, myBlockDef.Id)
            'Set the scale factors
            myBlockRef.ScaleFactors = New Geometry.Scale3d(XScale, YScale, ZScale)
            'Add the new BlockReference to the specified BlockTableRecord
            myBlockTableRecord.AppendEntity(myBlockRef)
            'Add the BlockReference to the BlockTableRecord.
            myTrans.AddNewlyCreatedDBObject(myBlockRef, True)
            Dim myAttColl As DatabaseServices.AttributeCollection = _
                myBlockRef.AttributeCollection
            'Find Attributes and add them to the AttributeCollection
            'of the BlockReference
            For Each myEntID As ObjectId In myBlockDef
                Dim myEnt As Entity = myEntID.GetObject(OpenMode.ForRead)
                If TypeOf myEnt Is DatabaseServices.AttributeDefinition Then
                    Dim myAttDef As DatabaseServices.AttributeDefinition = myEnt
                    Dim myAttRef As New DatabaseServices.AttributeReference
                    myAttRef.SetAttributeFromBlock(myAttDef, myBlockRef.BlockTransform)
                    myAttColl.AppendAttribute(myAttRef)
                    myTrans.AddNewlyCreatedDBObject(myAttRef, True)
                End If
            Next
            myTrans.Commit()
            Return myBlockRef.Id
        End Using
    End Function


    Function SetParameter(ByVal BlockID As ObjectId, ByVal ParameterName As String, _
            ByVal Value As Double) As Boolean
        Using myTrans As Transaction = BlockID.Database.TransactionManager.StartTransaction
            Dim myBRef As BlockReference = BlockID.GetObject(OpenMode.ForRead)
            For Each myDynamProp As DynamicBlockReferenceProperty In _
                    myBRef.DynamicBlockReferencePropertyCollection
                If myDynamProp.PropertyName.Equals( _
                        ParameterName, StringComparison.OrdinalIgnoreCase) = True Then
                    myDynamProp.Value = Value
                    myTrans.Commit()
                    Return True
                    Exit For
                End If
            Next
            Return False
        End Using
    End Function

    <CommandMethod("SizeShed")> _
    Public Sub SizeShed()
        Dim myBlockID As ObjectId = InsertBlock(HostApplicationServices.WorkingDatabase, _
                                                BlockTableRecord.ModelSpace, _
                                                New Point3d(1, 1, 0), "Plan_Base", 1, 1, 1)
        SetParameter(myBlockID, "P_Len", 30000)
        SetParameter(myBlockID, "P_Width", 20000)
        SetParameter(myBlockID, "Ridge_Height_LE", 8000)
        SetParameter(myBlockID, "Ridge_Height_RE", 8000)
        SetParameter(myBlockID, "Shed_Height_LE", 5000)
        SetParameter(myBlockID, "Shed_Height_RE", 5000)
        SetParameter(myBlockID, "Shed_Height_Front", 5000)
        SetParameter(myBlockID, "Ridge_Height_Front", 8000)
        SetParameter(myBlockID, "Shed_Height_Back", 5000)
        SetParameter(myBlockID, "Ridge_Height_Back", 8000)
    End Sub

End Class

GegH1

  • Guest
Re: Insert Dynamic block
« Reply #5 on: April 07, 2013, 04:48:46 AM »
Fixo, i tried your code and got this

Command: _Netload Cannot load assembly. Error details:
System.BadImageFormatException: Could not load file or assembly
'file:///C:\Users\Geg\Documents\Visual Studio 2010\blockupdate.dll' or one of
its dependencies. The module was expected to contain an assembly manifest.
File name: 'file:///C:\Users\Geg\Documents\Visual Studio 2010\blockupdate.dll'
   at System.Reflection.Assembly._nLoad(AssemblyName fileName, String codeBase,
Evidence assemblySecurity, Assembly locationHint, StackCrawlMark& stackMark,
Boolean throwOnFileNotFound, Boolean forIntrospection)
   at System.Reflection.Assembly.InternalLoad(AssemblyName assemblyRef,
Evidence assemblySecurity, StackCrawlMark& stackMark, Boolean forIntrospection)
   at System.Reflection.Assembly.LoadFrom(String assemblyFile)
   at Autodesk.AutoCAD.Runtime.ExtensionLoader.Load(String fileName)
   at loadmgd()

WRN: Assembly binding logging is turned OFF.
To enable assembly bind failure logging, set the registry value
[HKLM\Software\Microsoft\Fusion!EnableLog] (DWORD) to 1.
Note: There is some performance penalty associated with assembly bind failure
logging.
To turn this feature off, remove the registry value
[HKLM\Software\Microsoft\Fusion!EnableLog].

fixo

  • Guest
Re: Insert Dynamic block
« Reply #6 on: April 07, 2013, 06:25:43 AM »
This code is working good on my A2010,
same as regenerated code below,
try compile project from attachment

GegH1

  • Guest
Re: Insert Dynamic block
« Reply #7 on: April 07, 2013, 06:54:59 AM »
Fixo,
How do i compile the project from the txt file?

fixo

  • Guest
Re: Insert Dynamic block
« Reply #8 on: April 07, 2013, 07:22:56 AM »
Sorry mate, do it the same way as I recreated project from your attached code
Create project (Class Library) add in there a Module Vars.vb, add Windows form
and copy / paste code from attachment, if this would not works then
just create your own form and add controls as on my Form code
Then go to Tools -> Project -> Your Project Properties in the Debug tab and
check radio button "Start external program" then  add your AutoCAD exe file,
on my end it is on this path: ProgramFiles\AutoCAD 2010\acad.exe
It's clearly enough?

TheMaster

  • Guest
Re: Insert Dynamic block
« Reply #9 on: April 07, 2013, 08:02:01 AM »
The full code gets rather long but on further investigation i am getting an eLockViolation at this point in the code:

            Dim myBlockTableRecord As BlockTableRecord = _
                myBlockTable(BTRToAddTo).GetObject(OpenMode.ForWrite)


The eLockViolation happens when you try to modify the document from a modeless dialog, without locking the document first.

Before you call any code that modifies the document, call LockDocument, and make sure that you Dispose the result, like this:

Code - Text: [Select]
  1.  
  2.    Using docLock as IDisposable = activeDoc.LockDocument()
  3.  
  4.      ''  <<<< safe to modify active document here
  5.  
  6.    End Using
  7.  
  8.  

Where 'activeDoc' is the active document.

fixo

  • Guest
Re: Insert Dynamic block
« Reply #10 on: April 07, 2013, 01:01:26 PM »
I've already used thisin the code above:
Code: [Select]
        <CommandMethod("DS", CommandFlags.Modal)> _
        Public Sub DrawShed()
            Dim doc As Document = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument
            Dim ed As Editor = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument.Editor
            Using doclock As DocumentLock = doc.LockDocument

                Try
                    Dim recFrm As New ShedForm
           
                    Autodesk.AutoCAD.ApplicationServices.Application.ShowModelessDialog(recFrm)

                Catch ex As Autodesk.AutoCAD.Runtime.Exception
                    MsgBox(ex.ToString())
                Finally

                End Try
            End Using
        End Sub
But I investgated that the variable names are wrong,
Say I changed "Length" on "dLength" etc and changed logic
to update dynamic properties, now it working better
Please see attached file

GegH1

  • Guest
Re: Insert Dynamic block
« Reply #11 on: April 07, 2013, 10:02:44 PM »
is this where it goes?

Public Class Commands

    <CommandMethod("DrawShed")> _
    Public Sub DrawShed()
        Using docLock As IDisposable = activeDoc.LockDocument()
            Dim recFrm As New ShedForm()
            Application.ShowModelessDialog(recFrm)
        End Using
    End Sub

End Class

If so it says 'activeDoc' is not declared.

Fixo, i'm not ignoring your code at all, just trying to rationalise my code first to try to understand what's going on.

Jeff H

  • Needs a day job
  • Posts: 6150
Re: Insert Dynamic block
« Reply #12 on: April 07, 2013, 10:25:42 PM »
is this where it goes?

Public Class Commands

    <CommandMethod("DrawShed")> _
    Public Sub DrawShed()
        Using docLock As IDisposable = activeDoc.LockDocument()
            Dim recFrm As New ShedForm()
            Application.ShowModelessDialog(recFrm)
        End Using
    End Sub

End Class

If so it says 'activeDoc' is not declared.

Fixo, i'm not ignoring your code at all, just trying to rationalise my code first to try to understand what's going on.

It would not make much sense to lock a document before you open a modless form because you can change the active document after it is open.

The full code gets rather long but on further investigation i am getting an eLockViolation at this point in the code:

            Dim myBlockTableRecord As BlockTableRecord = _
                myBlockTable(BTRToAddTo).GetObject(OpenMode.ForWrite)


The eLockViolation happens when you try to modify the document from a modeless dialog, without locking the document first.

Before you call any code that modifies the document, call LockDocument, and make sure that you Dispose the result, like this:

Code - Text: [Select]
  1.  
  2.    Using docLock as IDisposable = activeDoc.LockDocument()
  3.  
  4.      ''  <<<< safe to modify active document here
  5.  
  6.    End Using
  7.  
  8.  

Where 'activeDoc' is the active document.

Typically one place to do it is where your outermost transaction is started.
« Last Edit: April 08, 2013, 01:04:08 AM by Jeff H »

TheMaster

  • Guest
Re: Insert Dynamic block
« Reply #13 on: April 08, 2013, 01:54:36 AM »
is this where it goes?

Public Class Commands

    <CommandMethod("DrawShed")> _
    Public Sub DrawShed()
        Using docLock As IDisposable = activeDoc.LockDocument()
            Dim recFrm As New ShedForm()
            Application.ShowModelessDialog(recFrm)
        End Using
    End Sub

End Class

If so it says 'activeDoc' is not declared.


See the last line of my post.

'activeDoc' was just used in the example which you're taking literally.  The 'activeDoc' has to be value of the MdiActiveDocument of the DocumentCollection.

Second, the call to ShowModelessDialog() returns as soon as the dialog becomes visible, so at the point when your code tries to modify the document, it will not be locked.

You should lock the document when you start the transaction that you use to access the objects, and unlock it when the transaction is committed or aborted.

« Last Edit: April 08, 2013, 01:59:43 AM by TT »

fixo

  • Guest
Re: Insert Dynamic block
« Reply #14 on: April 08, 2013, 02:16:22 AM »

Fixo, i'm not ignoring your code at all, just trying to rationalise my code first to try to understand what's going on.
No problem, that's very reasonable what you said, just for info see attached piccy
after I'd run my last code