.NET
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Show Form when inserting Block’s

7 REPLIES 7
SOLVED
Reply
Message 1 of 8
Anonymous
2060 Views, 7 Replies

Show Form when inserting Block’s

I have a lot of block’s (electrical symbols) in my toolpalettes. When I insert one into my drawing I want to show a custom attribute editor which contains comboboxes or other kind of controls to simply and quickly add value’s to their attributes. Maybe some attribute values can be modified or added programmatically but that’s for later.

What I first need to know is if it’s possible to show a form when I insert  a block from my toolpalette without creating custom toolpalettes.

 

I know how to disable the advanced attribute editor with ATTREQ set to 0.

 

Which trigger can I use to start my own program?

Do I need to have another program running to detect changes in the blocktable or something like that?

 

Any help would be appreciated.

7 REPLIES 7
Message 2 of 8
norman.yuan
in reply to: Anonymous

You can use Database.ObjectAppended event as the trigger to catch the newly inserted block, and test if the block is the target block for custom attribute data input UI. If yes, show your custom UI (of course you need to make sure "ATTREQ" is set to "0" to avoid built-in attribute UI shows up, as you are already aware of. Here I assume you only want to show your custom UI for particular block or blocks for the specific set or sets of attributes. Most likely, the block name would be the identifier to decide whether custom Attribute UI is used or not. Handling ObjectAppended event would give you chance to know specific block has just been added into database, regardless which command does it, be it from command "INSERT" directly, or from toolpallete...

 

Following code shows how to do it:

using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Runtime;
using System;
using System.Collections.Generic;
using CadApp = Autodesk.AutoCAD.ApplicationServices.Application;

[assembly: ExtensionApplication(typeof(CustomAttEditForm.CustomAttributeEditor))]

namespace CustomAttEditForm
{
    public class CustomAttributeEditor : IExtensionApplication 
    {
        public void Initialize()
        {
            var doc = CadApp.DocumentManager.MdiActiveDocument;
            try
            {
                HookEvenHandlers();
                doc.Editor.WriteMessage("\nCustom attribute editor initialized.\n");
            }
            catch(System.Exception ex)
            {
                doc.Editor.WriteMessage($"Initializing error\n{ex.Message}\n");
            }
        }

        public void Terminate()
        {
            
        }

        private static void HookEvenHandlers()
        {
            var docs = CadApp.DocumentManager;
            docs.DocumentActivated += (o, e) =>
              {
                  e.Document.Database.ObjectAppended += Database_ObjectAppended;
              };

            foreach (Document d in docs)
            {
                d.Database.ObjectAppended += Database_ObjectAppended;
            }
        }

        private static void Database_ObjectAppended(object sender, ObjectEventArgs e)
        {
            if (IsTargetBlock(e.DBObject))
            {
                EditBlockAttribute(e.DBObject as BlockReference);
            }
        }

        private static bool IsTargetBlock(DBObject dbObject)
        {
            var blk = dbObject as BlockReference;
            if (blk!=null)
            {
                var attReq = Convert.ToBoolean(CadApp.GetSystemVariable("ATTREQ"));
                if (blk.Name.ToUpper() == "TestBlock".ToUpper() && !attReq)
                {
                    return true;
                }
            }
            return false;
        }

        private static void EditBlockAttribute(BlockReference blk)
        {
            CadApp.ShowAlertDialog(
                "You are about to show custom attribute editing form.\n\n" +
                $"Block to be edited:\t {blk.Name}");

            // Show attribute editing form that matches block's name (thus the 
            // block's attributes) to collect attribute values
            var attNameList = GetAttributeNamesFromBlock(blk);
            var dic = GetUserInput(attNameList);
            if (dic!=null)
            {
                using (var tran = blk.Database.TransactionManager.StartTransaction())
                {
                    foreach (ObjectId id in blk.AttributeCollection)
                    {
                        var att = (AttributeReference)tran.GetObject(id, OpenMode.ForWrite);
                        if (dic.ContainsKey(att.Tag.ToUpper()))
                        {
                            att.TextString = dic[att.Tag.ToUpper()];
                        }
                    }
                    tran.Commit();
                }
            }
        }

        private static List<string> GetAttributeNamesFromBlock(BlockReference blk)
        {
            var lst = new List<string>();
            using (var tran = blk.Database.TransactionManager.StartTransaction())
            {
                foreach (ObjectId id in blk.AttributeCollection)
                {
                    var att = (AttributeReference)tran.GetObject(id, OpenMode.ForRead);
                    lst.Add(att.Tag);
                }
                tran.Commit();
            }
            return lst;
        }

        private static Dictionary<string, string> GetUserInput(List<string> attNames)
        {
            Dictionary<string, string> dic = null;

            using (var dlg = new AttributeEditForm(attNames))
            {
                var res = CadApp.ShowModalDialog(dlg);
                if (res== System.Windows.Forms.DialogResult.OK)
                {
                    dic = new Dictionary<string, string>();
                    // fill the Dictionary object with user inputs
                }
            }

            return dic;
        }
    }
}

In the code, I simply hard-coded the block name ("TestBlock") as the target block. I also omitted the form's detail. Pay attention to IsTargetBlock() method, which decides whether custom UI is needed or not.

 

See attached Video showing how the code works"

 

 

 

Norman Yuan

Drive CAD With Code

EESignature

Message 3 of 8
dgorsman
in reply to: Anonymous

I'll suggest something a little bit different.  Rather than inserting the blocks directly and handling that via events or other methods, you would create custom commands to handle the insertion. The commands can be placed on a palette just like a block, but you can also put them into the CUIx system so they can be called from the menu, Ribbon, or toolbars.

 

You could create one command per block but that may less-than-efficient for both development and the user.  In most cases there would be several blocks that can be inserted from the same command via prompts or other input.  You get to control which blocks are selected/inserted, and there's still the option of manually inserting them without any interruption.

----------------------------------
If you are going to fly by the seat of your pants, expect friction burns.
"I don't know" is the beginning of knowledge, not the end.


Message 4 of 8
Anonymous
in reply to: norman.yuan

Thank you very much for your extensive explanation Norman. That is exactly what I was looking for but I have some trouble to get it working. I know a little bit of writing code in VB.NET, I started programming 6 month's ago.

 

What I did is converting your code to VB.NET but I got some errors which I can not solve at this moment. So I tried your C# code. In C I have only one error message in Visual Studio. It's the red part in the code below.

I pasted your code in a class and I created a winform with the name AttributeEditForm. What am I missing here?

 

Thank you in advance

 

 

private static Dictionary<string, string> GetUserInput(List<string> attNames)
        {
            Dictionary<string, string> dic = null;

            using (var dlg = new AttributeEditForm(attNames))
            {
                var res = CadApp.ShowModalDialog(dlg);
                if (res== System.Windows.Forms.DialogResult.OK)
                {
                    dic = new Dictionary<string, string>();
                    // fill the Dictionary object with user inputs
                }
            }

            return dic;
        }
 

 

Message 5 of 8
norman.yuan
in reply to: Anonymous

My code is only meant to show the entire process, so I omitted some details, especially the form. It is up to you to build a form suitable to edit a set of attributes from a block reference. Obviously, the form need some inputs to initialize. That is why the form in my sample code (AttributeEditForm) has an constructor that takes a List<string> parameter as input. The code for the form should be like this:

 

public partial class AttributeEditForm()

{

    // This is the default constructor, automatically created by Visual Studio

    public AttributeEditForm()

    {

        InitializeComponents()

    }

 

    // This is the constructor used in my code sample

    public AttributeEditForm(List<string> attribueNames) : this()

    {

         // Vwry likely, you use the attribute names passed in to 

         // set labels for each textbox/dropdown for

        // the attribute value field

    }

    ... ...

    ... ...

}

 

 

Norman Yuan

Drive CAD With Code

EESignature

Message 6 of 8
Anonymous
in reply to: norman.yuan

Thanks again, I really appreciate your help.

I have de code working till the messagebox pops up. This is in C#. I know I have to add my own form with the textboxes and/or comboboxes to fill the attribute value's in the block's.

But, as I mentioned before, I wanted to make this code in VB. Here's were I am stuck now. The method of coding for some parts is totally different in C#, see code below.

 

Private Shared Sub HookEvenHandlers()
            Dim docs = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager

            docs.DocumentActivated += Function(o, e)
                                          e.Document.Database.ObjectAppended += AddressOf Database_ObjectAppended
                                      End Function

            For Each d As Document In docs
                d.Database.ObjectAppended += AddressOf Database_ObjectAppended
            Next
        End Sub

 I searched the internet and tried different things but somehow it's not working in VB. I'm now at the point of considering to switch to C#  unless someone knows how to fix this?

 

Here's the link to the Autodesk documentation.

Handle DocumentCollection Events (.NET)

 

Message 7 of 8
norman.yuan
in reply to: Anonymous

In VB.NET, you would use statement "AddHandler..." to attach event handler. This this case, the code would look like:

 

Private Shared Sub HookEventHandlers()

  Dim docs As DocumentCollection = ....

  '' My original code was wrongly used DocumentActivated event. It should be DocumentCreated event

  AddHandler docs.DocumentCreated, AddressOf DocumentManager_DocumentCreated

  For Each doc As Document in docs

    AddEventHandler doc.Database.ObjectAppended, AddressOf Database_ObjectAppended

  Next

End Sub

 

Private Shared Sub DocumentManager_DocumentCreated(sender As Object, e As DocumentCollectionEventArgs)

  AddEventHandler e.Document.Database, AddressOf Database_ObjectAppended

End Sub

 

Private Shared Sub Database_ObjectAppended(sender As Object, e As ObjectEventArgs)

  If (IsTargetBlock(e.DBObject) Then

    EditBlockAttribute(DirectCast(e.DBObject, BlockReference))

  End If

End Sub

... ...

 

 

Norman Yuan

Drive CAD With Code

EESignature

Message 8 of 8
Anonymous
in reply to: norman.yuan

Thank you for your help Norman, it's working fine now. I have one little problem to fix but hopefully I can fix that by myself.

@ Dgorsman, thanks for your input. I thought about your solution, but for me it's best to have the same custom attribute editor for every block in my toolpalettes. That's because I have a lot of blocks on my toolpalettes and I add new ones from time to time. When I'm using a custom attribute editor I think I don't need to add block names to custom command's and/or modify their code.

Can't find what you're looking for? Ask the community or share your knowledge.

Post to forums  

AutoCAD Inside the Factory


Autodesk Design & Make Report