.NET

Reply
*Expert Elite*
Alfred.NESWADBA
Posts: 8,893
Registered: ‎06-29-2007
Message 21 of 29 (759 Views)

Re: Edit a Block via C#

03-11-2012 05:23 AM in reply to: klahie

Hi,

 

>> I see many attributes like kmh, beleuchtet, mast_id, etc. but non of those, I've mentioned.

Male a breakpoint and watch the variable tAttDef and it's properties. There you find e.g. a property Layer, you find a property Position for insertion point, you also find the property Height and Rotation.

But once more, be careful ... changing these values for AttributeDefinition(s) will only effect the next commands _INSERT (EINFÜGE) .... so for the blockreferences you create after making the changes to your definitions.

 

If you want to change the properties and values for the BlockReferences already inserted in your drawing you have first to select the BlockReferences, then scan through their AttributeCollection (= collection of ObjectIDs pointing to the AttributeReference).

 

You have a lot of learning quite in front of you ==> your screen (showing the help-file) :smileywink:

 

Good luck, - alfred -

-------------------------------------------------------------------------
Alfred NESWADBA
Ingenieur Studio HOLLAUS ... www.hollaus.at
-------------------------------------------------------------------------
Active Contributor
klahie
Posts: 26
Registered: ‎03-10-2012
Message 22 of 29 (749 Views)

Re: Edit a Block via C#

03-11-2012 12:32 PM in reply to: Alfred.NESWADBA

Okay, next problem:

 

When I try to show the window:

 

Autodesk.AutoCAD.ApplicationServices.Application.ShowModelessWindow(window);

 an errorpage comes up in visual studio.

Error:

No source Available

No symbols are loaded for any call stack frame. The source code cannot be displayed.

 

What does this mean to me?

 

Kind Regards

Active Contributor
klahie
Posts: 26
Registered: ‎03-10-2012
Message 23 of 29 (747 Views)

Re: Edit a Block via C#

03-11-2012 12:50 PM in reply to: klahie

Okay, error is gone. I don't know why, but its gone...

 

Now I've excluded the databaselogic in a new class, before it was in the myPlugin class.

The problem now is, I can't read data from BlockTable, BlockTableRecord, etc. because of an AccessViolationException. Is there any option to give the rights, which the myPlugin class has, to another class?

 

Reading data from BlockTable, etc. works great in the myPlugin class, but if i exclude the logic, the programm fails.

*Expert Elite*
Alfred.NESWADBA
Posts: 8,893
Registered: ‎06-29-2007
Message 24 of 29 (742 Views)

Re: Edit a Block via C#

03-11-2012 01:47 PM in reply to: klahie

Hi,

 

>> No source Available. No symbols are loaded for any [...]

look to >>>that link<<< that shows what's going on when getting this message.

 

The other problem I'm sorry, I have not understood what is now going on with your code and when BlockTableRecord-reading works and when not. Maybe you can minimize the code and upload a snippet that makes it more clear for us.

 

- alfred -

-------------------------------------------------------------------------
Alfred NESWADBA
Ingenieur Studio HOLLAUS ... www.hollaus.at
-------------------------------------------------------------------------
Active Contributor
klahie
Posts: 26
Registered: ‎03-10-2012
Message 25 of 29 (738 Views)

Re: Edit a Block via C#

03-11-2012 04:19 PM in reply to: Alfred.NESWADBA

Okay, this is the code:

 

My Plugin Class:

 

using System;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Windows;
using System.Collections.Generic;
using System.Collections;



[assembly: ExtensionApplication(typeof(AutoCAD_BE.MyPlugin))]
[assembly: CommandClass(typeof(AutoCAD_BE.MyPlugin))]

namespace AutoCAD_BE
{   
    public class MyPlugin : IExtensionApplication
    {   
        [CommandMethod("loadbe")]
        public void LoadBe()
        {
            Document doc = Application.DocumentManager.MdiActiveDocument;
            Database db = doc.Database;
            Transaction tr = db.TransactionManager.StartTransaction();
            Datenbank datenbank = new Datenbank(doc, db, tr);

            Window1 window = new Window1(datenbank);
            Autodesk.AutoCAD.ApplicationServices.Application.ShowModelessWindow(window);

        }
    }

This is my Window Class:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using Autodesk.AutoCAD.DatabaseServices;

namespace AutoCAD_BE
{
    public partial class Window1 : System.Windows.Window
    {
        Datenbank datenbank;

        public Window1(Datenbank datenbank)
        {
            this.datenbank = datenbank;
            InitializeComponent();
        }
        // fills the listBox in the UI with blocknames
        public void fillList(List<String> blockList)
        {
            foreach (String s in blockList)
            {
                listBlocks.Items.Add(s.ToString());
            }

        }
        // fills the attribute-editting form with the attributes of the in the listbox selected block
        private void listBlocks_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            datenbank.setBlockAttributes(listBlocks.SelectedItem.ToString());
            AttributeDefinition tAttDef = datenbank.getAttributeDefinition();
            tbRotation.Text = tAttDef.Layer;
            tbLayer.Text = tAttDef.Layer;
            tbEinfuegepunktX.Text = tAttDef.Position.X.ToString();
            tbEinfuegepunktY.Text = tAttDef.Position.Y.ToString();
            tbEinfuegepunktZ.Text = tAttDef.Position.Z.ToString();
        }
        
        //calls the fillList-method with the in the class datenbank generated blockList
        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            fillList(datenbank.getBlockTableRecordNames());
        }
    }
}

and this is my Class whitch holds the Transactions with the database:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Windows;

namespace AutoCAD_BE
{
    public class Datenbank
    {
        Database db;
        Transaction tr;
        Document doc;
        AttributeDefinition AttDef;
        List<String> BlockList = new List<String>();

        public Datenbank(Document doc, Database db, Transaction tr)
        {
            this.doc = doc;
            this.db = db;
            this.tr = tr;
            setBlockTableRecordNames();
        }

        //Gets the Blocktablerecordnames out of the blocktable and adds them into a list.
        public void setBlockTableRecordNames()
        {
            using (tr)
            {
                BlockTable bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead);
                foreach (ObjectId objId in bt)
                {
                    BlockTableRecord btr = (BlockTableRecord)tr.GetObject(objId, OpenMode.ForRead);

                    BlockList.Add(btr.Name);
                }
            }
        }

        public List<String> getBlockTableRecordNames()
        {
            return (BlockList);
        }

        //Gets the AttributeDefinitions out of the BlocktableRecord
        public void setBlockAttributes(String blockname)
        {
          using (tr)
            {
               BlockTable bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead);
                foreach (ObjectId objId in bt)
                {
                    BlockTableRecord btr = (BlockTableRecord)tr.GetObject(objId, OpenMode.ForRead);
                    if (btr.Name == blockname)
                    {
                        foreach (ObjectId tObjID in btr)
                        {
                            if ((tObjID.IsValid) && (!tObjID.IsErased) && (tObjID.ObjectClass.DxfName.ToUpper() == "ATTDEF"))
                            {
                                AttributeDefinition tAttDef = (AttributeDefinition)tr.GetObject(tObjID, OpenMode.ForRead);
                                setAttributeDefinition(tAttDef);
                            }
                        }
                    }
                }
            }
        }
        public void setAttributeDefinition(AttributeDefinition tAttDef)
        {
            AttDef = tAttDef;
        }

        public AttributeDefinition getAttributeDefinition()
        {
            return AttDef;
        }

        public void refreshBlockList(Transaction tr, Database db)
        {
            this.tr = tr;
            this.db = db;
            getBlockTableRecordNames();
        }
    }
}

 Attached, you find a screenshot of the error and the whole "solution". :smileywink:

 

What I want to do:

MyPlugin.cs gives the Document, Database and Transaction to Datenbank.cs. 

Datenbank.cs gets the Blocktablerecordnames, my WPF-Window Window1.xaml is loaded and gets the datenbank.cs. In the Window1.xaml, the blocktablerecordnames are shown in a listbox, the user selects one and the setBlockAttributes-method in datenbank.cs is called. The datenbank.cs sets the right AttributeDefinition, the Window-class gets it and fills the attributes in to a form.

 

As I've understood the error, I have no permissions to access the Blocktable/Blocktablerecord/AttributeDefinitions/etc. in another class than myPlugin.cs. 

 

Kind Regards

Klaus

 

*Expert Elite*
Alfred.NESWADBA
Posts: 8,893
Registered: ‎06-29-2007
Message 26 of 29 (732 Views)

Re: Edit a Block via C#

03-11-2012 05:31 PM in reply to: klahie

Hi,

 

you load your application window with this procedure:

[CommandMethod("loadbe")]
public void LoadBe()
  {
     Document doc = Application.DocumentManager.MdiActiveDocument;
     Database db = doc.Database;
     Transaction tr = db.TransactionManager.StartTransaction();
     Datenbank datenbank = new Datenbank(doc, db, tr);

     Window1 fenster = new Window1(datenbank);
            Autodesk.AutoCAD.ApplicationServices.Application.ShowModelessWindow(fenster);

  }

Now the problem is, that you start a transaction, then you open your application window modeless ==> and modeless means your code does run to the end of "Public void LoadBe". That means also that the livetime of your transaction finishes (and the GarbageCollector purges it from memory at any time).

 

So when you now click to any button on your form you try to use a transaction that does not exist any more. ==> That's the reason why your code crashes.

 

Let me give some tips how I do see the structure you built:

  • You have a modeless dialog, so the user can goon working with AutoCAD. He also can change the active document by creating a new one or opening an existing DWG or close your DWG you just analyzed. ==> Your form does not recognize this, any click to any function points to the document that was active during load of your app.
  • If you have a modeless dialog, don't assign objects that are DWG-specific (doc, db, tr) in the code that starts the dialog. Assign these variables when the user presses a button on your form (or does any other action that accesses AutoCAD). In this functions (that get called not from a self defined command) use also doc.LockDocument to get all rights as the document is then really locked.
  • I haven't seen any Try-Catch statements within your code, so your code crashes AutoCAD. If you use Try-Catch you may do some errors, but as long as they are in a Try{}-zone your dotNET code will run into the catch and the error gets handled without crashing AutoCAD (in most cases).

 

Please don't see that as criticism, it's just a small list of tips. :smileywink:

 

- alfred -

-------------------------------------------------------------------------
Alfred NESWADBA
Ingenieur Studio HOLLAUS ... www.hollaus.at
-------------------------------------------------------------------------
Active Contributor
klahie
Posts: 26
Registered: ‎03-10-2012
Message 27 of 29 (724 Views)

Re: Edit a Block via C#

03-12-2012 01:04 AM in reply to: Alfred.NESWADBA

This is no criticism, this is great! I've never had such an good support in any forum. :smileyhappy:

 

Okay, I thought about that a while and came to the conclusion that it probably had a reason that the old VB version of this blockeditor had a modal window. :smileywink:

 

If I want to do that with 

Autodesk.AutoCAD.ApplicationServices.Application.ShowModalWindow(window);

I probably have to do more than that to get it working. Am I right?

I did the doc.LockDocument() too but its still not working... :smileysad:

 

PS: Wirklich, aller herzlichsten Dank für deine Hilfe, ich wäre wohl ziemlich aufgeschmissen ohne dich. :smileywink:

Active Contributor
klahie
Posts: 26
Registered: ‎03-10-2012
Message 28 of 29 (671 Views)

Re: Edit a Block via C#

04-03-2012 09:52 AM in reply to: klahie

I still have the same problem. :smileysad:

 

Can anybody help me again?

Valued Mentor
jeff
Posts: 322
Registered: ‎05-12-2009
Message 29 of 29 (654 Views)

Re: Edit a Block via C#

04-03-2012 04:21 PM in reply to: klahie

When you say a 'Block's attributes' do you mean its properties or an actual Attribute object.

 

 

From there are you wanting a AttributeDefinition or AttributeReference?

 

You will never see a AttributeDefinition in a drawing. What you see is a AttributeReference which is built from a AttributeDefinition and from there they are no longer linked.

 

So for one block when you make a edit do you want to change all 'insertions' or just one?

Wanting to show a single value in your window for layer, scale, etc.... would lead me to think a AttributeDefinition since each AttributeReference could vary.

 

Keep in mind if you want to change position or scale the existing AttributeReferences could already been scaled and moved separately from the BlockReference so should changes be relative to existing AttributeReference or created from new AttributeDefinition? 

You can also find your answers @ TheSwamp

You are not logged in.

Log into access your profile, ask and answer questions, share ideas and more. Haven't signed up yet? Register

Announcements
Are you familiar with the Autodesk Expert Elites? The Expert Elite program is made up of customers that help other customers by sharing knowledge and exemplifying an engaging style of collaboration. To learn more, please visit our Expert Elite website.

Need installation help?

Start with some of our most frequented solutions to get help installing your software.

Ask the Community