TheSwamp

Code Red => .NET => Topic started by: T.Willey on June 04, 2007, 02:32:21 PM

Title: Tool palette, Object selection and Event
Post by: T.Willey on June 04, 2007, 02:32:21 PM
I have written a tool palette that gets populated when the user invokes the command, and then selects a block.  It will update the block with the new information typed into its combo boxes.  What I'm looking to do is have it floating around, and then if I select a block (no command invoked) it will populate the tool palette without having to invoke the command again.  I can't seem to find how to do this in the help files or on the net, so any guidance is appreciated.

Thanks in advance.
Title: Re: Tool palette, Object selection and Event
Post by: T.Willey on June 04, 2007, 02:49:54 PM
This looks like the class I need to use
Quote
AcEdSSGetFilter Class
Now to see how to use it.  :-D
Title: Re: Tool palette, Object selection and Event
Post by: LE on June 04, 2007, 03:12:56 PM
SelectionAddedEventHandler ?
Title: Re: Tool palette, Object selection and Event
Post by: T.Willey on June 04, 2007, 03:31:24 PM
SelectionAddedEventHandler ?
Yes.  But there seems to be a problem.  It calls the event before it adds the objects, so I need to see about another way.
Title: Re: Tool palette, Object selection and Event
Post by: T.Willey on June 04, 2007, 03:36:48 PM
My code seems to be crashing Acad with the second selection made.  I'm just drawing lines right now to test, as the code shouldn't do anything when selecting them.  I select a few, it shows the correct number of blocks (0).  Then I select again and get a fatal error.  Here is the code.
Code: [Select]
public void SelectionMade(object sender, SelectionAddedEventArgs e) {
ObjectId BlockId = ObjectId.Null;
BlockReference BlkRef = null;
int BlkCnt = 0;
SelectionSet ss = e.Selection;
using (Transaction Trans = AcadApp.DocumentManager.MdiActiveDocument.TransactionManager.StartTransaction()) {
for (int i = 0; i < ss.Count; ++i) {
BlkRef = Trans.GetObject(ss[i].ObjectId, OpenMode.ForRead) as BlockReference;
if (BlkRef != null) {
++BlkCnt;
BlockId = BlkRef.ObjectId;
}
}
}
MessageBox.Show(BlkCnt.ToString());
if (BlkCnt == 1) CreateControls(BlockId);
}
Any help is appreciated.  I'm off to see if I can find the answer.
Title: Re: Tool palette, Object selection and Event
Post by: LE on June 04, 2007, 03:54:20 PM
i wrap the function with try{} catch{}

then, if i just want to select one

ObjectId[] ids = e.AddedObjects.GetObjectIds();
if (e.AddedObjects.Count == 1)
{
ObjectId objid = ids[0];               
Entity ename = (Entity)tr.GetObject(objid, OpenMode.ForRead);
BlockReference br = (BlockReference)ename;
if (ename is BlockReference)
{
 MessageBox.Show("Is one BLOCK...", "Found", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
e.Remove(0);
}
e.Remove(0);
tr.Commit();
Title: Re: Tool palette, Object selection and Event
Post by: T.Willey on June 04, 2007, 04:28:04 PM
I put it in a try/catch, but it still doesn't work.  It seems like the objects, when being selected, are opened so that I can't do anything to them.  So I guess I have to have the selection event, put an object modified event on each object, and then after that object closed event (which I don't see one) will modify my tool palette.

Now to go back and look at how I did it in lisp.  :|
Title: Re: Tool palette, Object selection and Event
Post by: LE on June 04, 2007, 04:33:22 PM
I put it in a try/catch, but it still doesn't work.  It seems like the objects, when being selected, are opened so that I can't do anything to them.  So I guess I have to have the selection event, put an object modified event on each object, and then after that object closed event (which I don't see one) will modify my tool palette.

Now to go back and look at how I did it in lisp.  :|

i only have done very little with events in c#, and basically just to read data from blocks(doors) and pass it to a dialog, nothing about to modify...
Title: Re: Tool palette, Object selection and Event
Post by: T.Willey on June 04, 2007, 04:35:35 PM
This is very frustrating.  I tried using the CommandEnded event (like I did in Lisp) didn't work.  Then I tried using the ObjectModified event, didn't work.

Maybe after lunch an idea that will work will pop into my head.  Thanks for trying Luis.  It is appreciated.
Title: Re: Tool palette, Object selection and Event
Post by: LE on June 04, 2007, 04:42:20 PM
This is very frustrating.  I tried using the CommandEnded event (like I did in Lisp) didn't work.  Then I tried using the ObjectModified event, didn't work.

Maybe after lunch an idea that will work will pop into my head.  Thanks for trying Luis.  It is appreciated.

i know...

are you always using: OpenMode.ForRead

on your tests?.... how about ForWrite?

:)
Title: Re: Tool palette, Object selection and Event
Post by: T.Willey on June 04, 2007, 05:25:09 PM
This is very frustrating.  I tried using the CommandEnded event (like I did in Lisp) didn't work.  Then I tried using the ObjectModified event, didn't work.

Maybe after lunch an idea that will work will pop into my head.  Thanks for trying Luis.  It is appreciated.

i know...

are you always using: OpenMode.ForRead

on your tests?.... how about ForWrite?

:)
I use OpenMode.ForRead on all objects but the attributes, thos I use OpenMode.ForWrite.  I didn't think I had to open the block with OpenMode.ForWrite also.

Nothing came to me during lunch.  Oh well.  :-)
Title: Re: Tool palette, Object selection and Event
Post by: LE on June 04, 2007, 05:51:50 PM
I use OpenMode.ForRead on all objects but the attributes, thos I use OpenMode.ForWrite.  I didn't think I had to open the block with OpenMode.ForWrite also.

Nothing came to me during lunch.  Oh well.  :-)

if an object is going to be modified, you have to opened for write... (now, if you modify the attributes from a block, you do not open.write the block, and your routine works?)

to bad, i can played with code right now....  :-(
Title: Re: Tool palette, Object selection and Event
Post by: T.Willey on June 04, 2007, 06:00:51 PM
if an object is going to be modified, you have to opened for write... (now, if you modify the attributes from a block, you do not open.write the block, and your routine works?)
Yes.  It will work fine with picking the block through the routine, but not with the event.

to bad, i can played with code right now....  :-(
Yes.  :-)  If you want I can post the whole routine so you can test when you want, if you want.  Let me know.
Title: Re: Tool palette, Object selection and Event
Post by: LE on June 04, 2007, 06:03:53 PM
to bad, i can played with code right now....  :-(

that should said:

"To bad, I do not have time right now to play with code..."
Title: Re: Tool palette, Object selection and Event
Post by: T.Willey on June 04, 2007, 06:05:54 PM
to bad, i can played with code right now....  :-(

that should said:

"To bad, I do not have time right now to play with code..."
I knew what you meant.  :wink:
Title: Re: Tool palette, Object selection and Event
Post by: T.Willey on June 04, 2007, 06:45:22 PM
Okay.  I got that part to work correctly.  It had nothing to do with the event part of the code  :ugly:, I had to lock the document when I was creating the controls for the tool palette.  Now I just have to fine tune it.

Thanks for the conversation Luis.  :-)
Title: Re: Tool palette, Object selection and Event
Post by: LE on June 04, 2007, 06:57:56 PM
Okay.  I got that part to work correctly.  It had nothing to do with the event part of the code  :ugly:, I had to lock the document when I was creating the controls for the tool palette.  Now I just have to fine tune it.

Thanks for the conversation Luis.  :-)

I was going to mention that, but forgot... when you do any modification from a dialog, the doc must be lock..... sorry... glad you found the way :)

Code: [Select]
        static public void doorModify()
        {
            Database db = HostApplicationServices.WorkingDatabase;
            Document doc = acadApp.DocumentManager.MdiActiveDocument;
            Editor ed = doc.Editor;
            PromptEntityResult res = ed.GetEntity("\nSelect door to modify: ");
            if (res.Status != PromptStatus.OK) return;
            using (DocumentLock doclock = ed.Document.LockDocument())
            {
                using (Transaction tr = db.TransactionManager.StartTransaction())
                {
                    Entity ename = (Entity)tr.GetObject(res.ObjectId, OpenMode.ForWrite, false);
                    if (ename != null)
                    {
                        BlockReference block;
                        try
                        {
                            block = (BlockReference)ename;
                        }
                        catch { return; }
                        Boolean iDoorXrecValid = true;
                        Xrecord iDoorXRec = null;
                        DBDictionary extDict = null;
                        try
                        {
                            extDict = (DBDictionary)tr.GetObject(block.ExtensionDictionary, OpenMode.ForRead, false);
                        }
                        catch { iDoorXrecValid = false; }
                        try
Title: Re: Tool palette, Object selection and Event
Post by: T.Willey on June 04, 2007, 07:24:59 PM
I create the combo boxes on the fly, and I had to lock the document when I was creating the combo boxes (well not sure if it was just this, or when creating the layout of it).  But it seems to be working now.  I just need to update it so that it will only show the block selected per the current drawing.  Right now when you switch between drawings it will still show the old one selected, but it won't allow you to update it.

Here is the code if anyone is interested.


Edit:  Removed old code.
Title: Re: Tool palette, Object selection and Event
Post by: TonyT on June 05, 2007, 12:14:58 AM
Hi Tim.

You (and Luis) do understand that the SelectionAdded event fires
for all object selection, including object selection within
built-in commands; LISP programs; etc., right  ?

Also, do you also understand that SelectionAdded is fired once for
each "Select objects: " prompt, during object selection? 

E.g., if you start a command that prompts for multiple selection, and
you select one or more objects using a window/crossing box, then
the SelectionAdded event fires, and the 'Select objects: ' prompt
reappears. If you then add more objects to that same selection by
responding to the new 'Select objects: ' prompt, the SelectionAdded
event fires again.

IOW, In the context of SelectionAdded, each response to a
'Select objects: ' prompt is a 'selection'. And hence, this
event fires once for each 'Select objects: ' prompt that you
respond to by selecting one or more objects.

It seems that what you (and Luis) may be assuming is that this
event fires only once after the user has exited from multiple
object selection and all selection is completed. That's not the
case.

So, it would seem to me that your code is going to be running
inside of many commands, whenever they prompt for a selection.

I create the combo boxes on the fly, and I had to lock the document when I was creating the combo boxes (well not sure if it was just this, or when creating the layout of it).  But it seems to be working now.  I just need to update it so that it will only show the block selected per the current drawing.  Right now when you switch between drawings it will still show the old one selected, but it won't allow you to update it.

Title: Re: Tool palette, Object selection and Event
Post by: T.Willey on June 05, 2007, 01:47:42 AM
Hi Tony,

 Thanks for the responds.

  In my testing I noticed that the event fired twice per selection, single window or single crossing or selection of a single object, without a command active, and I did notice that it fired each time I made a window. I noticed that it even fired when I hit escape to deselect all objects.  I assumed that it would fire the same amount during a command also.

Maybe I can add some code to check to see if a command is issued, and if so ignore (or deactivate) my selection event.  Thats a good idea.

I think I will change the code to kick you out once you have more than one block in the selection set, no need to keep checking unless I make it a multi-tab palette, one per block name with the amount in parenthesis.  Just an idea.
Title: Re: Tool palette, Object selection and Event
Post by: TonyT on June 05, 2007, 05:26:12 AM
Hi Tim.

The reason why you noticed that the event fired twice (or more) is
most-likely because your code is adding the handler to the event
more than once, because that event does not fire more than once
for each selection.

From just a quick glance at your code, it seems that its adding the
event handler in the command method. But, it's never removed, so if
you execute that command 3 times, your event handler is added to
the event 3 times, and the event will fire 3 times for each selection.
If you execute the command 4 times, the event will fire 4 times for
each selection.

From another quick glance at it, your code seems to have much
bigger problems. You are caching references to DBobjects in the Tag
property of controls.  Umm, can't do that. 

A reference to a DBObject is only valid while the transaction it was
obtained from is active. Once that transaction ends, any DBObjects
obtained by calling GetObject() on the transaction, are no longer valid
and should not be used.

You never cache DBObjects for use at a later time, after the
transaction they were obtained from has ended. Doing that will
only lead to a fatal error.

ObjectId's are what you cache and use, not DBObjects. Try
storing the ObjectIds in a variable (or the tag property if you
wish), and then open the objects again using the ObjectId
when you need to access them.

Another problem your code has is that you are developing
it with an SDI mindset. As soon as you try opening more
than one document, then switching to another document
and clicking the Ok button on your tool, you will find that
your code is operating on the wrong document (not the
one containing the objects that you've previously cached
in the Control.Tag property), and kaboom.

Also, if your command method is run in multiple documents,
what do think is going to happen?

I'm afraid that developing an MDI-aware modeless user
interface is not as simple as it may at first appear from
afar.

Hi Tony,

 Thanks for the responds.

  In my testing I noticed that the event fired twice per selection, single window or single crossing or selection of a single object, without a command active, and I did notice that it fired each time I made a window. I noticed that it even fired when I hit escape to deselect all objects.  I assumed that it would fire the same amount during a command also.

Maybe I can add some code to check to see if a command is issued, and if so ignore (or deactivate) my selection event.  Thats a good idea.

I think I will change the code to kick you out once you have more than one block in the selection set, no need to keep checking unless I make it a multi-tab palette, one per block name with the amount in parenthesis.  Just an idea.
Title: Re: Tool palette, Object selection and Event
Post by: LE on June 05, 2007, 10:32:29 AM
Thank you Tony for your comments;

It is to much there for learning, I started into events but stop, the coding I been doing in C# it is just to keep me busy and to learn the language as much as I can, I have a lot of free time lately. :)
Title: Re: Tool palette, Object selection and Event
Post by: T.Willey on June 05, 2007, 11:03:50 AM
Thanks again Tony.  I didn't know that you should not cache the DBObjects.  I thought it was a quick way to get the reference again once the user hit the okay button.  I will use the ObjectId.

I know about the problem with MDI mode and my code, that is why I made sure you could edit the attribute, it you can't it will throw a message box saying it can't edit it.

You are right that I add the event more than once, didn't think about that while testing yesterday.  I will look into this as I think I know how to code it.

I'm afraid that developing an MDI-aware modeless user
interface is not as simple as it may at first appear from
afar.
But it will be a good learning experience.  Thanks again for you comments, I really appreciate the time people who know more than I take to point out mistakes I have made.
Title: Re: Tool palette, Object selection and Event
Post by: T.Willey on June 05, 2007, 02:00:07 PM
Man events are harder to work with than reactors in lisp.  I can't seem to find a why to check to see if one is loaded so that it won't get loaded more than once.  If anyone knows a way, or a direction to follow please let me know.  Thanks. 


Off to look in some new places.
Title: Re: Tool palette, Object selection and Event
Post by: TonyT on June 05, 2007, 03:37:36 PM
Tim - You don't need to find out if the event handler
was added.

The problem isn't that, the problem is that you add
event handlers in commands, which you shouldn't
do. If the event is document-specific, you add the
event handler when the document opens (e.g., in
the DocumentCollection's DocumentAdded event)

Man events are harder to work with than reactors in lisp.  I can't seem to find a why to check to see if one is loaded so that it won't get loaded more than once.  If anyone knows a way, or a direction to follow please let me know.  Thanks. 


Off to look in some new places.
Title: Re: Tool palette, Object selection and Event
Post by: T.Willey on June 05, 2007, 04:03:17 PM
Tim - You don't need to find out if the event handler
was added.

The problem isn't that, the problem is that you add
event handlers in commands, which you shouldn't
do. If the event is document-specific, you add the
event handler when the document opens (e.g., in
the DocumentCollection's DocumentAdded event)

Man events are harder to work with than reactors in lisp.  I can't seem to find a why to check to see if one is loaded so that it won't get loaded more than once.  If anyone knows a way, or a direction to follow please let me know.  Thanks. 


Off to look in some new places.
Tony,

This is just what I did.   :-)

After I couldn't find a way to see if it was loaded, I said to myself "why check?"  So I made three events, right now.  One for when a document is created, one for when it's to be destroyed, and one for when it becomes current.  It seems to be working well right now, but I want to add in the check for a command.  If a command is running, don't do anything.  Edit:  I also add the selection event to all open drawings when the command is issued for the first time.

Thanks again.  Your help pointed me in the right direction.

I will post the code when I figure out the last issue.  I think it's the last issue.
Title: Re: Tool palette, Object selection and Event
Post by: T.Willey on June 05, 2007, 06:28:38 PM
Okay so putting in the command and lisp checks are not as easy as I would have hoped.  I think it won't be until tomorrow or later until I figure them out.  :oops:
Title: Re: Tool palette, Object selection and Event
Post by: LE on June 05, 2007, 06:41:42 PM
Okay so putting in the command and lisp checks are not as easy as I would have hoped.  I think it won't be until tomorrow or later until I figure them out.  :oops:

relax my friend, take your time, there is more time than life.... (don't let your hair turn grey)
Title: Re: Tool palette, Object selection and Event
Post by: T.Willey on June 05, 2007, 06:51:27 PM
Okay so putting in the command and lisp checks are not as easy as I would have hoped.  I think it won't be until tomorrow or later until I figure them out.  :oops:

relax my friend, take your time, there is more time than life.... (don't let your hair turn grey)
:lol: Thanks.  8-)
Title: Re: Tool palette, Object selection and Event
Post by: T.Willey on June 05, 2007, 07:38:53 PM
Here is the code as is.  When switching between open drawings, when the tool palette is open, it will correct to tool palette to the current drawing.  I haven't figured out how to have the command/lisp events work correctly, but you will see ideas in the code that I was trying.  Comments/opinions/compliments ( :angel: ), all welcomed.


Edit:  Removed old code.
Title: Re: Tool palette, Object selection and Event
Post by: TonyT on June 05, 2007, 07:39:57 PM
Okay so putting in the command and lisp checks are not as easy as I would have hoped.  I think it won't be until tomorrow or later until I figure them out.  :oops:

That's probably the easiest part.   :wink:

There's the CMDACTIVE system variable,
and there's the CommandInProgress property
of the Document.

I'm not sure if they indicate if LISP is running
(I think CMDACTIVE might), but all you need
to do is check that before your Selection-
related event handlers do anything, and exit
if not.
Title: Re: Tool palette, Object selection and Event
Post by: T.Willey on June 05, 2007, 07:41:55 PM
Okay so putting in the command and lisp checks are not as easy as I would have hoped.  I think it won't be until tomorrow or later until I figure them out.  :oops:

That's probably the easiest part.   :wink:

There's the CMDACTIVE system variable,
and there's the CommandInProgress property
of the Document.

I'm not sure if they indicate if LISP is running
(I think CMDACTIVE might), but all you need
to do is check that before your Selection-
related event handlers do anything, and exit
if not.

Oh man!  Events have clouded my mind!  Thanks Tony I will see about these tomorrow, as it's time to go home, and I can't code there now.
Title: Re: Tool palette, Object selection and Event
Post by: T.Willey on June 06, 2007, 12:22:02 PM
Okay, here is the final code as I see it.  The event will fire, but nothing will happen when the palette is closed (not visible) or when there is a command/lisp active.  It will change the palette when the drawing is changed.  If anyone tries it, let me know how it works for you.  I'm adding it to my standard C# files that I load into Acad.

Thanks everyone for you help, it is very much appreciated.


Edit:  Removed old code.
Title: Re: Tool palette, Object selection and Event
Post by: FengK on June 06, 2007, 12:38:17 PM
I'm adding it to my standard C# files that I load into Acad.

Tim, how do you do that? Do you mean compile the code into .dll and netload? thanks.
Title: Re: Tool palette, Object selection and Event
Post by: LE on June 06, 2007, 01:07:58 PM
Tim;

It is working here, in the small testing I did, I like it!

minor stuff: once it is not docked, you can't docked again... if you select other entities and one block it will let you fill the data in the palette ...

Good one!
Title: Re: Tool palette, Object selection and Event
Post by: T.Willey on June 06, 2007, 01:17:48 PM
I'm adding it to my standard C# files that I load into Acad.

Tim, how do you do that? Do you mean compile the code into .dll and netload? thanks.

Kelie,

I put all my real code into one project (combine) and compile it into one dll.  I then load that one dll in acad with the registry.  Thanks to Glenns's post here. (http://www.theswamp.org/index.php?topic=16184.msg196725#msg196725)  This doesn't really get loaded until one of the commands is issued.  Kind of like the autoload feature in lisp.

Hope that makes sense Kelie.

Tim;

It is working here, in the small testing I did, I like it!
Thanks for testing it Luis.  Glad someone besides me likes it.  :-)

minor stuff: once it is not docked, you can't docked again...
I think that is because I tell it not to dock here.
Code: [Select]
ps.DockEnabled = Autodesk.AutoCAD.Windows.DockSides.None;
ps.Dock = Autodesk.AutoCAD.Windows.DockSides.None;
but I was really trying to get it to float when first opened, but couldn't figure it out.  I think comment these out, then it would allow you to dock it again.  I will do some research on this, and get back to you.

if you select other entities and one block it will let you fill the data in the palette ...
I wanted it like this incase you just select a bunch of things.  It's just easier, IMO.
Title: Re: Tool palette, Object selection and Event
Post by: LE on June 06, 2007, 03:39:44 PM
 but I was really trying to get it to float when first opened, but couldn't figure it out.

You can add the following on your code in your CreateMyPalette():

Code: [Select]
            try { ps.AutoRollUp = true; }
            catch { }


            ps.Location = new System.Drawing.Point(0, 100); // i think this line is not needed
            ps.Dock = Autodesk.AutoCAD.Windows.DockSides.None;
Title: Re: Tool palette, Object selection and Event
Post by: T.Willey on June 06, 2007, 05:48:41 PM
Thanks Luis.  Been busy today with 'real' work, so no time to play.  We see how this works when I get a minute.
Title: Re: Tool palette, Object selection and Event
Post by: FengK on June 06, 2007, 06:56:14 PM
Kelie,

I put all my real code into one project (combine) and compile it into one dll.  I then load that one dll in acad with the registry.  Thanks to Glenns's post here. (http://www.theswamp.org/index.php?topic=16184.msg196725#msg196725)  This doesn't really get loaded until one of the commands is issued.  Kind of like the autoload feature in lisp.

Hope that makes sense Kelie.

Thanks Tim. Do you know compared with using NETLOAD, what is the benefit of using registry to load dll?
Title: Re: Tool palette, Object selection and Event
Post by: T.Willey on June 06, 2007, 06:58:57 PM
Kelie,

I put all my real code into one project (combine) and compile it into one dll.  I then load that one dll in acad with the registry.  Thanks to Glenns's post here. (http://www.theswamp.org/index.php?topic=16184.msg196725#msg196725)  This doesn't really get loaded until one of the commands is issued.  Kind of like the autoload feature in lisp.

Hope that makes sense Kelie.

Thanks Tim. Do you know compared with using NETLOAD, what is the benefit of using registry to load dll?
The benefits I see is you don't have to use 'netload'.  All you do is type the command, and the command will work.  I now only use netload to load files I'm working on, so this program is now loaed when I type the command name (since I added it to my list of commands in my registry, any my main dll) without having to go through netload.
Title: Re: Tool palette, Object selection and Event
Post by: TonyT on June 06, 2007, 07:08:16 PM
Okay, here is the final code as I see it......

Tim - In the 20 or so years I've been doing this, if
there is one thing I've learned, it is that there is
no such thng as 'the final code'   :-)

So moving along, there are other problems that you
don't see yet. The first is that your UserControl class
uses a non-static command method.

When a command method is non-static, the AutoCAD
managed runtime creates a new instance of the class
that declares the method, for each document that the
coimmand is invoked in, and caches them.

When you invoke the commad a second time in the
same document, the cached instance of the class that's
associated with that document is the instance which
the method is invoked on.

Your "MyUcPalette" command method is a non-static
member of UserControl1. That means that to invoke
that method, there must be an instance of UserControl1
that already exists, which is the instance that AutoCAD
creates when you issue the command in a document the
first time.

Your command method is then creating another instance
of UserControl1, when the command is invoked. But the
problem (which is not easily seen), is that subsequent
invocations of the command, causes the non-static
command method to be invoked not on the instance of
UserControl1 that your command creates, but rather on
the cached instance AutoCAD createed for you, the first
time you issue the command in each document.

In otherwords, if you have 3 documents open, and you
issue the MyUcPalette command in each, there will be
3 instances of UserControl1 created, one for each open
document the command was issued in. Your code as it
is written doesn't even know about them.

Title: Re: Tool palette, Object selection and Event
Post by: T.Willey on June 06, 2007, 07:35:20 PM
Tony, thanks again for your input, I find it invaluable.

Some of what you say makes sense to me, but some has me scratching my head.  I knew I didn't know much about C#, but know I'm finding I know a whole lot less than I thought I did.  I will do some research and see if I can solve this problem, and maybe in doing so I will be able to see if there are any other problems.
Title: Re: Tool palette, Object selection and Event
Post by: LE on June 06, 2007, 11:38:08 PM
OK;

After following Tony advice, here is the code updated, hope that is right if not somebody else did it.

Code: [Select]
/*
 * Created by SharpDevelop.
 * User: Tim Willey
 * Date: 6/1/2007
 * Time: 2:55 PM
 *
 * To change this template use Tools | Options | Coding | Edit Standard Headers.
 */

using System;
using System.ComponentModel;
using System.Drawing;
using System.IO;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using System.Collections;
using System.Data;
using System.Data.OleDb;

using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.GraphicsInterface;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Windows.ToolPalette;

using AcadApp = Autodesk.AutoCAD.ApplicationServices.Application;

[assembly: CommandClass(typeof(Test.UserControl1))]

namespace Test
{
    /// <summary>
    /// Description of UserControl1.
    /// </summary>
    public class UserControl1 : System.Windows.Forms.UserControl
    {
        public UserControl1()
        {
            //
            // The InitializeComponent() call is required for Windows Forms designer support.
            //
            InitializeComponent();

            //
            // TODO: Add constructor code after the InitializeComponent() call.
            //
        }

        #region Windows Forms Designer generated code
        /// <summary>
        /// This method is required for Windows Forms designer support.
        /// Do not change the method contents inside the source code editor. The Forms designer might
        /// not be able to load this method if it was changed manually.
        /// </summary>
        private void InitializeComponent()
        {
            //
            // BlankUserControl
            //
            this.Name = "BlankUserControl";
            this.Size = new System.Drawing.Size(232, 408);
        }
        #endregion

        private static int counter = 0; //test counter

        private static Autodesk.AutoCAD.Windows.PaletteSet ps;
        private static UserControl1 uc;
        private static System.Windows.Forms.Button OkBut;
        private static bool FirstLoad = true;
        private static bool cmdStart = false;
        private static bool lspStart = false;
        [CommandMethod("MyUcPalette")]
        public [color=blue]static [/color] void CreateMyPalette()
        {
            Document doc = AcadApp.DocumentManager.MdiActiveDocument;
            Editor Ed = doc.Editor;
            Ed.WriteMessage("\nCounter value is: " + counter++); //when switch to a new document or in the active it will continue with the next value not from 0


            if (ps == null)
            {
                ps = new Autodesk.AutoCAD.Windows.PaletteSet("My Attribute Palette");
                ps.Style = Autodesk.AutoCAD.Windows.PaletteSetStyles.ShowPropertiesMenu |
                    Autodesk.AutoCAD.Windows.PaletteSetStyles.ShowAutoHideButton |
                    Autodesk.AutoCAD.Windows.PaletteSetStyles.ShowCloseButton;
                ps.Opacity = 90;
                ps.Size = new System.Drawing.Size(250, 400);
                ps.MinimumSize = new System.Drawing.Size(225, 400);
                ps.DockEnabled = Autodesk.AutoCAD.Windows.DockSides.None;
                ps.Dock = Autodesk.AutoCAD.Windows.DockSides.None;
                ps.Text = "Edit attributes";
            }
            if (ps.Count > 0) ps.Remove(0);
            //ObjectId ObjId = SelectBlock();
            //if (!ObjId.IsNull) CreateControls(ObjId);
            ps.Visible = true;
            try { ps.AutoRollUp = true; }
            catch { }
            if (FirstLoad)
            {
                foreach (Document Doc in AcadApp.DocumentManager)
                {
                    Doc.Editor.SelectionAdded += new SelectionAddedEventHandler(SelectionMade);
                    //Doc.LispWillStart += new LispWillStartEventHandler(onLispStart);
                    //Doc.CommandWillStart += new CommandEventHandler(onCommandStart);
                    //Doc.CommandCancelled += new CommandEventHandler(onCommandDone);
                    //Doc.CommandEnded += new CommandEventHandler(onCommandDone);
                    //Doc.CommandFailed += new CommandEventHandler(onCommandDone);
                    //Doc.LispCancelled += new EventHandler(onLispDone);
                    //Doc.LispEnded += new EventHandler(onLispDone);
                }
                AcadApp.DocumentManager.DocumentCreated += new DocumentCollectionEventHandler(onDocCreated);
                AcadApp.DocumentManager.DocumentToBeDestroyed += new DocumentCollectionEventHandler(onDocToBeDestroyed);
                AcadApp.DocumentManager.DocumentBecameCurrent += new DocumentCollectionEventHandler(onDocBecameCurrent);
                FirstLoad = false;
            }
        }

        public [color=blue]static [/color] void CreateControls(ObjectId ObjId)
        {
            using (DocumentLock DocLock = AcadApp.DocumentManager.MdiActiveDocument.LockDocument())
            {
                AttributeDefinition AttDef = null;
                Document Doc = AcadApp.DocumentManager.MdiActiveDocument;
                Point StPt = new System.Drawing.Point(2, 30);
                uc = new UserControl1();
                using (Transaction Trans = AcadApp.DocumentManager.MdiActiveDocument.TransactionManager.StartTransaction())
                {
                    BlockTable BlkTbl = (BlockTable)Trans.GetObject(Doc.Database.BlockTableId, OpenMode.ForRead);
                    BlockReference BlkRef = (BlockReference)Trans.GetObject(ObjId, OpenMode.ForWrite);
                    BlockTableRecord BlkTblRec = (BlockTableRecord)Trans.GetObject(BlkRef.BlockTableRecord, OpenMode.ForRead);
                    Autodesk.AutoCAD.DatabaseServices.AttributeCollection AttCol = BlkRef.AttributeCollection;
                    foreach (ObjectId id in AttCol)
                    {
                        AttributeReference AttRef = (AttributeReference)Trans.GetObject(id, OpenMode.ForRead);
                        foreach (ObjectId tempId in BlkTblRec)
                        {
                            AttDef = Trans.GetObject(tempId, OpenMode.ForRead) as AttributeDefinition;
                            if (AttDef != null && string.Compare(AttDef.Tag, AttRef.Tag) == 0)
                            {
                                CreateComboBoxAndLabel(AttDef.Prompt, AttRef.TextString, AttRef.ObjectId, StPt, uc);
                                break;
                            }
                        }
                        if (AttDef == null) CreateComboBoxAndLabel(AttRef.Tag, AttRef.TextString, AttRef.ObjectId, StPt, uc);
                        AttDef = null;
                        StPt = new System.Drawing.Point(StPt.X, StPt.Y + 30);
                    }
                }
                OkBut = new System.Windows.Forms.Button();
                OkBut.Text = "Apply to block";
                OkBut.Name = "Okbutton";
                OkBut.BackColor = System.Drawing.Color.Silver;
                OkBut.ForeColor = System.Drawing.Color.Navy;
                OkBut.Location = new System.Drawing.Point(5, 0);
                OkBut.Size = new System.Drawing.Size(220, 25);
                OkBut.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right | System.Windows.Forms.AnchorStyles.Top)));
                OkBut.Click += new System.EventHandler(OkayButtonClick);
                uc.Controls.Add(OkBut);
                uc.Resize += new System.EventHandler(FormResized);
                uc.AutoScroll = true;
                uc.AutoScrollMinSize = new System.Drawing.Size(0, 400);
                uc.VScroll = true;
                uc.HScroll = false;
                if (ps.Count > 0) ps.Remove(0);
                ps.Add("Test", uc);
            }
        }

        public [color=blue]static [/color] void CreateComboBoxAndLabel(string cbName, string cbValue, object Obj, Point pt, UserControl1 uc)
        {
            ComboBox cb = new System.Windows.Forms.ComboBox();
            cb.BackColor = System.Drawing.Color.Silver;
            cb.ForeColor = System.Drawing.Color.Navy;
            cb.Name = cbName;
            cb.Text = cbValue;
            cb.Location = pt;
            cb.Size = new System.Drawing.Size(150, 25);
            cb.DropDownStyle = System.Windows.Forms.ComboBoxStyle.Simple;
            cb.Tag = Obj;

            Label lb = new System.Windows.Forms.Label();
            lb.Name = cbName;
            lb.Text = cbName;
            lb.Height = 20;
            lb.Size = new System.Drawing.Size(200, 25);
            lb.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
            lb.Location = new System.Drawing.Point(pt.X + 5 + cb.Size.Width, pt.Y);

            uc.Controls.Add(cb);
            uc.Controls.Add(lb);
        }

        public [color=blue]static [/color] void OkayButtonClick(object sender, System.EventArgs e)
        {
            Document Doc = AcadApp.DocumentManager.MdiActiveDocument;
            using (DocumentLock DocLock = Doc.LockDocument())
            {
                ControlCollection CtrlCol = uc.Controls;
                using (Transaction Trans = Doc.TransactionManager.StartTransaction())
                {
                    foreach (Control Ctrl in CtrlCol)
                    {
                        try
                        {
                            if (Ctrl.Tag != null)
                            {
                                ObjectId ObjId = (ObjectId)Ctrl.Tag;
                                AttributeReference AttRef = Trans.GetObject(ObjId, OpenMode.ForWrite) as AttributeReference;
                                if (string.Compare(AttRef.TextString, Ctrl.Text) != 0)
                                    AttRef.TextString = Ctrl.Text;
                            }
                        }
                        catch { MessageBox.Show("Could not update attribute value."); }
                    }
                    Trans.Commit();
                }
            }
        }

        public [color=blue]static [/color] void FormResized(object sender, System.EventArgs e)
        {
            OkBut.Size = new System.Drawing.Size(uc.Width - 15, 25);
        }

        // Not used.
        public ObjectId SelectBlock()
        {
            Document Doc = AcadApp.DocumentManager.MdiActiveDocument;
            Editor Ed = Doc.Editor;
            PromptEntityOptions Opts = new PromptEntityOptions("\n Select block: ");
            Opts.SetRejectMessage("\n Entity not a block.");
            Opts.AddAllowedClass(typeof(BlockReference), false);
            PromptEntityResult Rslt = Ed.GetEntity(Opts);
            return Rslt.ObjectId;
        }

        public [color=blue]static  [/color] void SelectionMade(object sender, SelectionAddedEventArgs e)
        {
            if (!ps.Visible || string.Compare(AcadApp.GetSystemVariable("CmdActive").ToString(), "0") != 0) return;
            if (e.Selection.Count == 0 && e.AddedObjects.Count != 0)
            {
                FillInControl(e.AddedObjects.GetObjectIds());
            }
            else if (ps.Count > 0) ps.Remove(0);
        }

        public [color=blue]static [/color] void FillInControl(ObjectId[] ObjIdArray)
        {
            ObjectId BlkId = ObjectId.Null;
            int BlkCnt = 0;
            using (Transaction Trans = AcadApp.DocumentManager.MdiActiveDocument.TransactionManager.StartTransaction())
            {
                foreach (ObjectId ObjId in ObjIdArray)
                {
                    BlockReference BlkRef = Trans.GetObject(ObjId, OpenMode.ForRead) as BlockReference;
                    if (BlkRef != null && BlkRef.AttributeCollection.Count > 0)
                    {
                        ++BlkCnt;
                        BlkId = ObjId;
                        if (BlkCnt > 1) break;
                    }
                }
            }
            if (BlkCnt == 1) CreateControls(BlkId);
            else if (ps.Count > 0 && BlkCnt != 1) ps.Remove(0);
        }

        public [color=blue]static [/color] void onDocCreated(object sender, DocumentCollectionEventArgs e)
        {
            Document newDoc = e.Document;
            newDoc.Editor.SelectionAdded += new SelectionAddedEventHandler(SelectionMade);
        }

        public [b]static [/b] void onDocToBeDestroyed(object sender, DocumentCollectionEventArgs e)
        {
            Document Doc = e.Document;
            Doc.Editor.SelectionAdded -= new SelectionAddedEventHandler(SelectionMade);
        }

        public [color=blue]static  [/color] void onDocBecameCurrent(object sender, DocumentCollectionEventArgs e)
        {
            if (!ps.Visible) return;
            PromptSelectionResult psr = e.Document.Editor.SelectImplied() as PromptSelectionResult;
            if (psr == null) return;
            SelectionSet ss = psr.Value as SelectionSet;
            if (ss != null && ss.Count > 0) FillInControl(ss.GetObjectIds());
            else if (ps.Count > 0) ps.Remove(0);
        }
    }
}
Title: Re: Tool palette, Object selection and Event
Post by: T.Willey on June 07, 2007, 10:56:26 AM
Thanks Luis!  I don't know how long it would have taken to try that.  I was trying to find a way to make the 'CommandMethod' static, in stead of the functions that are used within the CommandMethod.  Now to go back and reread Tony's comments.

This is getting more exciting.  :-)
Title: Re: Tool palette, Object selection and Event
Post by: T.Willey on June 07, 2007, 12:39:59 PM
Luis,

After putting the static modifier in the calls to the methods of the UserControl1 class, I had to change some of the calls within the calls.  In the book that Glenn referred to me "Pro C-sharp 2005 and the dotNet2.0 Platform" it states
Quote from: CHAPTER 3 ■ C# LANGUAGE FUNDAMENTALS, Page 84
■Note Allow me to repeat myself. Static members can operate only on static class members. If you attempt to
make use of nonstatic class members (also called instance data) within a static method, you receive a compiler error.

Edit:  Removed old code.
Title: Re: Tool palette, Object selection and Event
Post by: LE on June 07, 2007, 12:45:30 PM
Did you tested the code of yours modified by me, with the static calls?

I remember seeing something about this in Kean blog... (forgot the name sorry)


And wait for Tony.
Title: Re: Tool palette, Object selection and Event
Post by: T.Willey on June 07, 2007, 12:51:29 PM
Did you tested the code of yours modified by me, with the static calls?

I remember seeing something about this in Kean blog... (forgot the name sorry)


And wait for Tony.
I didn't test the code you put, but I changed my code to add the static calls like you showed, and it wouldn't compile.  That is when I turned to the book for guidance, and found the quote shown plus an example.

edit:  I also found out how to make it so it's not docked when called.  I had to change the Dock property after the call to make it visible.  In the code I posted I still make it so it can't be docked, which I like, so to change that just comment out the part for 'DockEnabled'.
Title: Re: Tool palette, Object selection and Event
Post by: LE on June 07, 2007, 12:53:11 PM
ok, I don;t have the solution here with me, and for me works/compile as I posted... :)
Title: Re: Tool palette, Object selection and Event
Post by: FengK on June 07, 2007, 12:54:53 PM
Tim, excuse my newbie question. what do i need to do if i want to test it? i created a windows application project in #D and got an error saying the program "does not contain a static 'Main' method suitable for an entry point" when trying to compile it. Thanks.
Title: Re: Tool palette, Object selection and Event
Post by: T.Willey on June 07, 2007, 01:14:21 PM
Tim, excuse my newbie question. what do i need to do if i want to test it? i created a windows application project in #D and got an error saying the program "does not contain a static 'Main' method suitable for an entry point" when trying to compile it. Thanks.
I don't think you can use this as a windows application because it has to reference two acad dlls.  Attached is a pic that shows the Acad dll references you need.
Title: Re: Tool palette, Object selection and Event
Post by: T.Willey on June 07, 2007, 01:18:46 PM
ok, I don;t have the solution here with me, and for me works/compile as I posted... :)
It compiled for me too.  I guess I didn't see all you changed.  Let me see if I can find out what was different from what I did, and and what you posted.  Thanks Luis.  Off to study.  :-)
Title: Re: Tool palette, Object selection and Event
Post by: LE on June 07, 2007, 01:19:50 PM
for Kelie ( and any one out there  :-P )

1. You start a new project of a "Class Library"
2. Make two references to acdbmgd.dll and acmgd.dll (using the browse and go to your autocad support installation)
3. Copy the whole code and open the Class.cls and paste the new code in there (remove whatever was created there before)
4. Compile your project
Title: Re: Tool palette, Object selection and Event
Post by: FengK on June 07, 2007, 01:42:54 PM
Thanks Tim and LE. It is working now. Neat stuff. :-)
Title: Re: Tool palette, Object selection and Event
Post by: LE on June 07, 2007, 01:45:55 PM
Thanks Tim and LE. It is working now. Neat stuff. :-)

Por nada(for nothing), it is all Tim fault  :-)
Title: Re: Tool palette, Object selection and Event
Post by: T.Willey on June 07, 2007, 01:47:39 PM
Thanks Tim and LE. It is working now. Neat stuff. :-)
Glad you got it to work.  Watch out with that type of language, you might get hooked also.

Thanks Tim and LE. It is working now. Neat stuff. :-)

Por nada(for nothing), it is all Tim fault  :-)
Na.  You gave better instructions.  :-D And got it to work properly first.
Title: Re: Tool palette, Object selection and Event
Post by: TonyT on June 07, 2007, 03:51:43 PM
Hi Tim.

It's not really abou knowing C#, its more about AutoCAD
and MDI, which is something you generally don't have to
contend with when using LISP.

I think you might want to test how your code works when
you switch to a document that has a command already
running in it. E.g., start the LINE command or some other
AutoCAD command, then while it's waiting for input, switch
to another document, then switch back to the one that
has the running command.

Tony, thanks again for your input, I find it invaluable.

Some of what you say makes sense to me, but some has me scratching my head.  I knew I didn't know much about C#, but know I'm finding I know a whole lot less than I thought I did.  I will do some research and see if I can solve this problem, and maybe in doing so I will be able to see if there are any other problems.
Title: Re: Tool palette, Object selection and Event
Post by: T.Willey on June 07, 2007, 05:47:48 PM
Tony,

I just did test it, and it worked fine.  I'm not sure why unless there is no current selection for the 'SelectImplied' method of the 'Editor' object.  I tested it with two drawings open, one issued the line command and the other i issued the erase command.  I switched back and forth between them around four times.  I see what you are saying with it though, and I have changed my code to make sure that when switching between existing drawings if a command is running it will return nothing (or exit).

Hi Tim.

It's not really abou knowing C#, its more about AutoCAD
and MDI, which is something you generally don't have to
contend with when using LISP.

I think you might want to test how your code works when
you switch to a document that has a command already
running in it. E.g., start the LINE command or some other
AutoCAD command, then while it's waiting for input, switch
to another document, then switch back to the one that
has the running command.

Tony, thanks again for your input, I find it invaluable.

Some of what you say makes sense to me, but some has me scratching my head.  I knew I didn't know much about C#, but know I'm finding I know a whole lot less than I thought I did.  I will do some research and see if I can solve this problem, and maybe in doing so I will be able to see if there are any other problems.
Title: Re: Tool palette, Object selection and Event
Post by: TonyT on June 07, 2007, 08:50:27 PM
Hi Tim.

Have you tried while the STRECH command is running?

Tony,

I just did test it, and it worked fine.  I'm not sure why unless there is no current selection for the 'SelectImplied' method of the 'Editor' object.  I tested it with two drawings open, one issued the line command and the other i issued the erase command.  I switched back and forth between them around four times.  I see what you are saying with it though, and I have changed my code to make sure that when switching between existing drawings if a command is running it will return nothing (or exit).

Hi Tim.

It's not really abou knowing C#, its more about AutoCAD
and MDI, which is something you generally don't have to
contend with when using LISP.

I think you might want to test how your code works when
you switch to a document that has a command already
running in it. E.g., start the LINE command or some other
AutoCAD command, then while it's waiting for input, switch
to another document, then switch back to the one that
has the running command.

Tony, thanks again for your input, I find it invaluable.

Some of what you say makes sense to me, but some has me scratching my head.  I knew I didn't know much about C#, but know I'm finding I know a whole lot less than I thought I did.  I will do some research and see if I can solve this problem, and maybe in doing so I will be able to see if there are any other problems.
Title: Re: Tool palette, Object selection and Event
Post by: FengK on June 08, 2007, 03:19:19 AM
i'm wondering should the editted block be de-selected once you hit "apply change" button? otherwise, i have to hit "ESC" to edit another block. i thought the purpose of of having modeless palette is so that user can continously edit multiple blocks. please enlighten me. thanks.
Title: Re: Tool palette, Object selection and Event
Post by: T.Willey on June 08, 2007, 11:17:17 AM
Hi Tim.

Have you tried while the STRECH command is running?
With the code now (added a check for commands when switching documents) it works fine with the stretch command invoked.  With the old code it seems to work also.  The only difference is this line.
Old
Code: [Select]
if (!ps.Visible) return;New
Code: [Select]
if (!ps.Visible || string.Compare(AcadApp.GetSystemVariable("CmdActive").ToString(), "0") != 0) return;Within this piece of code
Code: [Select]
public static void onDocBecameCurrent (object sender, DocumentCollectionEventArgs e) {
// if (!ps.Visible || string.Compare(AcadApp.GetSystemVariable("CmdActive").ToString(), "0") != 0) return;
if (!ps.Visible) return;
PromptSelectionResult psr = e.Document.Editor.SelectImplied() as PromptSelectionResult;
if (psr == null) return;
SelectionSet ss = psr.Value as SelectionSet;
if (ss != null && ss.Count > 0) UserControl1.FillInControl(ss.GetObjectIds());
else if (ps.Count > 0) ps.Remove(0);
}

i'm wondering should the editted block be de-selected once you hit "apply change" button? otherwise, i have to hit "ESC" to edit another block. i thought the purpose of of having modeless palette is so that user can continously edit multiple blocks. please enlighten me. thanks.
I think this could be a good idea, but I'm questioning it because the code would have to deselect all objects in the selection set, but that might not be a bad idea.  Let me look into this Kelie.
Title: Re: Tool palette, Object selection and Event
Post by: FengK on June 08, 2007, 12:24:16 PM
Tim, if you're not sure whether to implement it or not, how about adding a checkbox next to the button that says "De-select block after edit". something like this. and save user's choice in registry or somewhere, so the setting will be remembered next time when he/she uses this command.  is this palette made for editing block attributes? if so, what's the purpose of keeping the selectionset with multiple blocks? Thanks!
Title: Re: Tool palette, Object selection and Event
Post by: T.Willey on June 08, 2007, 01:18:03 PM
Tim, if you're not sure whether to implement it or not, how about adding a checkbox next to the button that says "De-select block after edit". something like this. and save user's choice in registry or somewhere, so the setting will be remembered next time when he/she uses this command.  is this palette made for editing block attributes? if so, what's the purpose of keeping the selectionset with multiple blocks? Thanks!
Kelie,

You make a good point, and I think it should be implemented, but I can't find any way to deselect the selection set.  I will continue to look, and post back when I find what I'm looking for.
Title: Re: Tool palette, Object selection and Event
Post by: FengK on June 08, 2007, 07:04:14 PM
Kelie,

You make a good point, and I think it should be implemented, but I can't find any way to deselect the selection set.  I will continue to look, and post back when I find what I'm looking for.

Thanks Tim. Can Application's Sendkeys function be used as an ugly fix? In lisp, it would something like this: (vla-eval (vlax-get-acad-object)  "Sendkeys \"{ESC}\"")  i don't know C#. this is just a guess.
Title: Re: Tool palette, Object selection and Event
Post by: LE on June 08, 2007, 11:22:24 PM
Master Tim;

Have you tried by adding:
Code: [Select]
public static void SelectionMade(object sender, SelectionAddedEventArgs e)
        {
            if (!ps.Visible || string.Compare(AcadApp.GetSystemVariable("CmdActive").ToString(), "0") != 0) return;
            if (e.Selection.Count == 0 && e.AddedObjects.Count != 0)
            {
                FillInControl(e.AddedObjects.GetObjectIds());
                e.Remove(0); //<<<===
            }
            else if (ps.Count > 0) ps.Remove(0);
        }

Might help...

Also, why is needed to keep the data on the palette, once the changes are applied? - maybe using something like:

Code: [Select]
        public static void OkayButtonClick(object sender, System.EventArgs e)
        {
            Document Doc = AcadApp.DocumentManager.MdiActiveDocument;
            using (DocumentLock DocLock = Doc.LockDocument())
            {
                ControlCollection CtrlCol = uc.Controls;
                using (Transaction Trans = Doc.TransactionManager.StartTransaction())
                {
                    foreach (Control Ctrl in CtrlCol)
                    {
                        try
                        {
                            if (Ctrl.Tag != null)
                            {
                                ObjectId ObjId = (ObjectId)Ctrl.Tag;
                                AttributeReference AttRef = Trans.GetObject(ObjId, OpenMode.ForWrite) as AttributeReference;
                                if (string.Compare(AttRef.TextString, Ctrl.Text) != 0)
                                    AttRef.TextString = Ctrl.Text;
                            }
                        }
                        catch { MessageBox.Show("Could not update attribute value."); }
                    }
                    Trans.Commit();
                }

                CtrlCol.Clear(); //<<<===

            }
        }
Title: Re: Tool palette, Object selection and Event
Post by: T.Willey on June 10, 2007, 12:31:19 PM
Thanks for the suggestions Kelie and Luis.  I will try them on Monday when I have the ability to.
Title: Re: Tool palette, Object selection and Event
Post by: T.Willey on June 11, 2007, 01:49:43 PM
Kelie,

I don't see any 'SendKeys' with .Net for AutoCAD.  There is a 'SendStringToExecute' but that didn't work with what you have, and I don't have the time right now to look into this further.

Luis,

With removing it from the selection set that way, it wouldn't remove the selection set when updating the block once you change from one document to the other.  So I need to look for a different way using the selection set class, but I haven't seen any yet.  Real work is calling, so I can't spend time on this right now.
Title: Re: Tool palette, Object selection and Event
Post by: T.Willey on June 13, 2007, 11:38:51 AM
Thanks to Paul R. here (http://www.theswamp.org/index.php?topic=17008.msg206020#msg206020) for finding a suitable work around till I understand the option that Glenn posted.

Now for the code.  Comments/suggestions/advice all welcomed.

One thing I hope to get working is the scroll ability in the palette.  I have some blocks that I work on where this options would be really helpful.  I tried putting a mouse event (wheel) on the user control, but that didn't seem to work.  I will see what I can find when I have more time to look.

Thanks all for the help and suggestions!!


Edit:  Removed old code.
Title: Re: Tool palette, Object selection and Event
Post by: LE on June 13, 2007, 12:02:56 PM
Muy bien Tim;

I will test your routine, later at home... looks good (it is not hard as appears the coding in C# no?)

One question is the PICKFIRST sysvar value changed? and put it back as it was?
Title: Re: Tool palette, Object selection and Event
Post by: T.Willey on June 13, 2007, 12:10:26 PM
Muy bien Tim;
Thanks Luis.  :-)

I will test your routine, later at home... looks good (it is not hard as appears the coding in C# no?)
Not really, but then again at the same time yes.  I think it is just the amount of research that you have to do because the langague is more powerful than lisp (which I'm used to using).

One question is the PICKFIRST sysvar value changed? and put it back as it was?
That is what I was thinking, but it worked when testing.  I don't really have time to research why it worked, as 'real' work is starting to come quickly and in bunches now.  Got big piles on my desk, which I like because the day goes faster.
Title: Re: Tool palette, Object selection and Event
Post by: T.Willey on June 14, 2007, 01:11:55 PM
Here is the code I'm happy with.  I added a context menu so that when you have a long list of attributes you can right click on the palette anywhere but a combo box and either apply to block or toggle the de-select option.

Thanks for all the help, and all the comments.

Code: [Select]
/*
 * Created by SharpDevelop.
 * User: Tim Willey
 * Date: 6/1/2007
 * Time: 2:55 PM
 *
 * To change this template use Tools | Options | Coding | Edit Standard Headers.
 * v0.2 6/7/07 Changed the command method call and all method calls to static, per Tony T.'s recommendation
 *   and Luis E.'s example
 * v0.3 6/13/07 Changed the code per Kelie's and Luis E.'s request to have the option of de-select the objects once the
 *   apply button is pressed.  Thanks to Paul R. for the code to de-select the objects.
 *   Changed the code per Tony T.'s suggestions, so that it won't load up the tool palette when a command is active.
 * V0.4 6/13/07 Used Glenn R.'s suggestion for de-selection.
 * v0.5 6/14/07 Added a context menu to apply to block and toggle the de-selection option, it also displays what
 *   the option is currently.
 */

using System;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.IO;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using System.Collections;
using System.Data;
using System.Data.OleDb;

using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.GraphicsInterface;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Windows.ToolPalette;

using AcadApp = Autodesk.AutoCAD.ApplicationServices.Application;

[assembly: CommandClass(typeof(AutoCAD3M.UserControl1))]

namespace AutoCAD3M
{
/// <summary>
/// Description of UserControl1.
/// </summary>
public class UserControl1 : System.Windows.Forms.UserControl
{
public UserControl1()
{
//
// The InitializeComponent() call is required for Windows Forms designer support.
//
InitializeComponent();

//
// TODO: Add constructor code after the InitializeComponent() call.
//
}

#region Windows Forms Designer generated code
/// <summary>
/// This method is required for Windows Forms designer support.
/// Do not change the method contents inside the source code editor. The Forms designer might
/// not be able to load this method if it was changed manually.
/// </summary>
private void InitializeComponent() {
//
// BlankUserControl
//
this.Name = "BlankUserControl";
this.Size = new System.Drawing.Size(232, 408);
}
#endregion

private static Autodesk.AutoCAD.Windows.PaletteSet ps;
private static UserControl1 uc;
private static System.Windows.Forms.Button OkBut;
private static System.Windows.Forms.CheckBox DeSelCkBox;
private static System.Windows.Forms.ContextMenu MyContextMenu;

private static bool FirstLoad = true;
private static bool IsDeSelChecked = true;
private static ObjectId BlockInForm = ObjectId.Null;
[DllImport("acad.exe", CallingConvention = CallingConvention.Cdecl, EntryPoint = "acedSSSetFirst")]
private static extern int acedSSSetFirst(long[] pset, long[] unused);
[CommandMethod("MyAttPalette")]
public static void CreateMyPalette()
{
if (ps == null) {
ps = new Autodesk.AutoCAD.Windows.PaletteSet("My Attribute Palette");
ps.Style = Autodesk.AutoCAD.Windows.PaletteSetStyles.ShowPropertiesMenu |
Autodesk.AutoCAD.Windows.PaletteSetStyles.ShowAutoHideButton |
Autodesk.AutoCAD.Windows.PaletteSetStyles.ShowCloseButton;
ps.Opacity = 90;
ps.Size = new System.Drawing.Size(250, 400);
ps.MinimumSize = new System.Drawing.Size(225, 400);
ps.DockEnabled = Autodesk.AutoCAD.Windows.DockSides.None;
ps.Text = "Edit attributes";
try { ps.AutoRollUp = true; }
catch {}
}
if (ps.Count > 0) ps.Remove(0);
//ObjectId ObjId = SelectBlock();
//if (!ObjId.IsNull) CreateControls(ObjId);
ps.Visible = true;
ps.Dock = Autodesk.AutoCAD.Windows.DockSides.None;
if (FirstLoad) {
foreach (Document Doc in AcadApp.DocumentManager) {
Doc.Editor.SelectionAdded += new SelectionAddedEventHandler(UserControl1.SelectionMade);
}
AcadApp.DocumentManager.DocumentCreated += new DocumentCollectionEventHandler(UserControl1.onDocCreated);
AcadApp.DocumentManager.DocumentToBeDestroyed += new DocumentCollectionEventHandler(UserControl1.onDocToBeDestroyed);
AcadApp.DocumentManager.DocumentBecameCurrent += new DocumentCollectionEventHandler(UserControl1.onDocBecameCurrent);
FirstLoad = false;
}
}

public static void CreateControls (ObjectId ObjId) {
//MessageBox.Show("Creating controls.");
using (DocumentLock DocLock = AcadApp.DocumentManager.MdiActiveDocument.LockDocument()) {
AttributeDefinition AttDef = null;
Document Doc = AcadApp.DocumentManager.MdiActiveDocument;
uc = new UserControl1();
Point StPt = new System.Drawing.Point(2, 45);
bool FoundAtt = false;
using (Transaction Trans = AcadApp.DocumentManager.MdiActiveDocument.TransactionManager.StartTransaction()) {
BlockTable BlkTbl = (BlockTable) Trans.GetObject(Doc.Database.BlockTableId, OpenMode.ForRead);
BlockReference BlkRef = (BlockReference) Trans.GetObject(ObjId, OpenMode.ForWrite);
BlockTableRecord BlkTblRec = (BlockTableRecord) Trans.GetObject(BlkRef.BlockTableRecord, OpenMode.ForRead);
Autodesk.AutoCAD.DatabaseServices.AttributeCollection AttCol = BlkRef.AttributeCollection;
foreach (ObjectId id in AttCol) {
AttributeReference AttRef = (AttributeReference) Trans.GetObject(id, OpenMode.ForRead);
foreach (ObjectId tempId in BlkTblRec) {
AttDef = Trans.GetObject(tempId, OpenMode.ForRead) as AttributeDefinition;
if (AttDef != null  && string.Compare(AttDef.Tag, AttRef.Tag) == 0) {
if (string.Equals(AttDef.Prompt, string.Empty))
UserControl1.CreateComboBoxAndLabel(AttRef.Tag, AttRef.TextString, AttRef.ObjectId, StPt, uc);
else UserControl1.CreateComboBoxAndLabel(AttDef.Prompt, AttRef.TextString, AttRef.ObjectId, StPt, uc);
FoundAtt = true;
break;
}
}
if (!FoundAtt) UserControl1.CreateComboBoxAndLabel(AttRef.Tag, AttRef.TextString, AttRef.ObjectId, StPt, uc);
else FoundAtt = false;
StPt = new System.Drawing.Point(StPt.X, StPt.Y + 30);
}
}
OkBut = new System.Windows.Forms.Button();
OkBut.Text = "Apply to block";
OkBut.Name = "Okbutton";
OkBut.BackColor = System.Drawing.Color.Silver;
OkBut.ForeColor = System.Drawing.Color.Navy;
OkBut.Location = new System.Drawing.Point(5, 0);
OkBut.Size = new System.Drawing.Size(220, 25);
OkBut.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right | System.Windows.Forms.AnchorStyles.Top)));
OkBut.Click += new System.EventHandler(UserControl1.OkayButtonClick);
uc.Controls.Add(OkBut);
DeSelCkBox = new System.Windows.Forms.CheckBox();
DeSelCkBox.Text = "De-Select objects after apply?";
DeSelCkBox.Size = new System.Drawing.Size(220, 20);
DeSelCkBox.Checked = IsDeSelChecked;
DeSelCkBox.Location = new System.Drawing.Point(5, 25);
DeSelCkBox.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Top)));
uc.Controls.Add(DeSelCkBox);
uc.Resize += new System.EventHandler(UserControl1.FormResized);
uc.MouseWheel += new MouseEventHandler(UserControl1.WheelMoved);
MyContextMenu = new System.Windows.Forms.ContextMenu();
MyContextMenu.Popup += new System.EventHandler(UserControl1.MyPopupMenu);
uc.ContextMenu = MyContextMenu;
uc.AutoScroll = true;
uc.AutoScrollMinSize =  new System.Drawing.Size(0, 400);
if (ps.Count > 0) ps.Remove(0);
ps.Add("Test", uc);
BlockInForm = ObjId;
}
}

public static void CreateComboBoxAndLabel (string cbName, string cbValue, object Obj, Point pt, UserControl1 uc) {
ComboBox cb = new System.Windows.Forms.ComboBox();
cb.BackColor = System.Drawing.Color.Silver;
cb.ForeColor = System.Drawing.Color.Navy;
cb.Name = cbName;
cb.Text = cbValue;
cb.Location = pt;
cb.Size = new System.Drawing.Size(150,25);
cb.DropDownStyle = System.Windows.Forms.ComboBoxStyle.Simple;
cb.Tag = Obj;

Label lb = new System.Windows.Forms.Label();
lb.Name = cbName;
lb.Text = cbName;
lb.Height = 20;
lb.Size = new System.Drawing.Size(200, 25);
lb.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
lb.Location = new System.Drawing.Point(pt.X + 5 + cb.Size.Width, pt.Y);

uc.Controls.Add(cb);
uc.Controls.Add(lb);
}

public static void OkayButtonClick (object sender, System.EventArgs e) {
Document Doc = AcadApp.DocumentManager.MdiActiveDocument;
using (DocumentLock DocLock = Doc.LockDocument()) {
ControlCollection CtrlCol = uc.Controls;
using (Transaction Trans = Doc.TransactionManager.StartTransaction()) {
foreach (Control Ctrl in CtrlCol) {
try {
if (Ctrl.Tag != null) {
ObjectId ObjId = (ObjectId) Ctrl.Tag;
AttributeReference AttRef = Trans.GetObject(ObjId, OpenMode.ForWrite) as AttributeReference;
if (string.Compare(AttRef.TextString, Ctrl.Text) != 0)
AttRef.TextString = Ctrl.Text;
}
}
catch { MessageBox.Show("Could not update attribute value."); }
}
Trans.Commit();
}
if (DeSelCkBox.Checked) {
acedSSSetFirst(null, null);
IsDeSelChecked = true;
}
else IsDeSelChecked = false;
}
AcadApp.UpdateScreen();
BlockInForm = ObjectId.Null;
}

public static void FormResized (object sender, System.EventArgs e) {
OkBut.Size = new System.Drawing.Size(uc.Width - 15, 25);
}

public static void WheelMoved (object sender, MouseEventArgs e) {
MessageBox.Show(e.Delta.ToString());
}

public static void ToggleDeSelect (object sender, System.EventArgs e) {
if (DeSelCkBox.Checked) {
DeSelCkBox.Checked = false;
IsDeSelChecked = false;
}
else {
DeSelCkBox.Checked = true;
IsDeSelChecked = true;
}
}

public static void MyPopupMenu (object sender, System.EventArgs e)
{
string tempStr = "Disabled";
if (DeSelCkBox.Checked) tempStr = "Enabled";
System.Windows.Forms.Menu.MenuItemCollection mic = MyContextMenu.MenuItems;
mic.Clear();
mic.Add("De-Select option is:  " + tempStr);
System.Windows.Forms.MenuItem mi1 = new System.Windows.Forms.MenuItem("  &Apply to block.");
mi1.Click += new EventHandler(OkayButtonClick);
mic.Add(mi1);
mi1.Enabled = new EventHandler(OkayButtonClick) != null;
System.Windows.Forms.MenuItem mi2 = new System.Windows.Forms.MenuItem("  &Toggle De-Select.");
mi2.Click += new EventHandler(ToggleDeSelect);
mic.Add(mi2);
mi2.Enabled = new EventHandler(ToggleDeSelect) != null;
}

// Not used.
public ObjectId SelectBlock () {
Document Doc = AcadApp.DocumentManager.MdiActiveDocument;
Editor Ed = Doc.Editor;
PromptEntityOptions Opts = new PromptEntityOptions("\n Select block: ");
Opts.SetRejectMessage("\n Entity not a block.");
Opts.AddAllowedClass(typeof (BlockReference), false);
PromptEntityResult Rslt = Ed.GetEntity(Opts);
return Rslt.ObjectId;
}

public static void SelectionMade (object sender, SelectionAddedEventArgs e) {
//MessageBox.Show("Selection fired.");
if (!ps.Visible || string.Compare(AcadApp.GetSystemVariable("CmdActive").ToString(), "0") != 0) return;
if (e.Selection.Count == 0 && e.AddedObjects.Count != 0)
UserControl1.FillInControl(e.AddedObjects.GetObjectIds());
else if (ps.Count > 0) ps.Remove(0);
}

public static void FillInControl (ObjectId[] ObjIdArray) {
ObjectId BlkId = ObjectId.Null;
int BlkCnt = 0;
using (Transaction Trans = AcadApp.DocumentManager.MdiActiveDocument.TransactionManager.StartTransaction()) {
foreach (ObjectId ObjId in ObjIdArray) {
BlockReference BlkRef = Trans.GetObject(ObjId, OpenMode.ForRead) as BlockReference;
if (BlkRef != null && BlkRef.AttributeCollection.Count > 0) {
++BlkCnt;
BlkId = ObjId;
if (BlkCnt > 1) break;
}
}
}
if (BlkCnt == 1 && (BlockInForm != BlkId || ps.Count == 0)) CreateControls(BlkId);
else if (ps.Count > 0 && BlkCnt != 1 && !object.Equals(BlockInForm, ObjectId.Null)) ps.Remove(0);
}

public static void onDocCreated (object sender, DocumentCollectionEventArgs e) {
Document newDoc = e.Document;
newDoc.Editor.SelectionAdded += new SelectionAddedEventHandler(SelectionMade);
}

public static void onDocToBeDestroyed (object sender, DocumentCollectionEventArgs e) {
Document Doc = e.Document;
Doc.Editor.SelectionAdded -= new SelectionAddedEventHandler(SelectionMade);
}

public static void onDocBecameCurrent (object sender, DocumentCollectionEventArgs e) {
BlockInForm = ObjectId.Null;
if (!ps.Visible || string.Compare(AcadApp.GetSystemVariable("CmdActive").ToString(), "0") != 0) return;
PromptSelectionResult psr = e.Document.Editor.SelectImplied() as PromptSelectionResult;
if (psr == null) return;
SelectionSet ss = psr.Value as SelectionSet;
if (ss != null && ss.Count > 0) UserControl1.FillInControl(ss.GetObjectIds());
else if (ps.Count > 0) ps.Remove(0);
}
}
}
Title: Re: Tool palette, Object selection and Event
Post by: TonyT on June 14, 2007, 09:14:52 PM
Here is the code I'm happy with. 

Thanks for all the help, and all the comments.

Code: [Select]

     if (!ps.Visible || string.Compare(AcadApp.GetSystemVariable("CmdActive").ToString(), "0") != 0) return;


Hi Tim.

The above is not how to compare objects with integers (perhaps you got it from Luis?).

Code: [Select]

      if(  ! AcadApp.GetSystemVariable("CMACTIVE").Equals(0) )
           return;


Title: Re: Tool palette, Object selection and Event
Post by: LE on June 14, 2007, 10:20:43 PM
     if (!ps.Visible || string.Compare(AcadApp.GetSystemVariable("CmdActive").ToString(), "0") != 0) return;
Hi Tim.

The above is not how to compare objects with integers (perhaps you got it from Luis?).

nope, was not me.... :)

Title: Re: Tool palette, Object selection and Event
Post by: TonyT on June 15, 2007, 04:55:39 AM
Sorry Luis I thought I saw it on some code posted by you, but I guess
it was Tim's.

     if (!ps.Visible || string.Compare(AcadApp.GetSystemVariable("CmdActive").ToString(), "0") != 0) return;
Hi Tim.

The above is not how to compare objects with integers (perhaps you got it from Luis?).

nope, was not me.... :)


Title: Re: Tool palette, Object selection and Event
Post by: T.Willey on June 15, 2007, 11:03:40 AM
Here is the code I'm happy with. 

Thanks for all the help, and all the comments.

Code: [Select]

     if (!ps.Visible || string.Compare(AcadApp.GetSystemVariable("CmdActive").ToString(), "0") != 0) return;


Hi Tim.

The above is not how to compare objects with integers (perhaps you got it from Luis?).

Code: [Select]

      if(  ! AcadApp.GetSystemVariable("CMACTIVE").Equals(0) )
           return;



Thanks Tony.  Yea it was all me.  I tried different ways, but couldn't get it to fire correctly.  I will make that change.  Learned something new also.  :-)

Edit: When I do it this way it always returns false even when 'CmdActive' returns 0.  I tried to convert it to an integer, but that doesn't work either "Specified cast is not valid".  Unless you know another way, I have to do it the way I did, as I don't see another way to get the correct results.
Title: Re: Tool palette, Object selection and Event
Post by: Paul Richardson on June 15, 2007, 06:16:41 PM
Here is the code I'm happy with. 

Thanks for all the help, and all the comments.

Code: [Select]

     if (!ps.Visible || string.Compare(AcadApp.GetSystemVariable("CmdActive").ToString(), "0") != 0) return;


Hi Tim.

The above is not how to compare objects with integers (perhaps you got it from Luis?).

Code: [Select]

      if(  ! AcadApp.GetSystemVariable("CMACTIVE").Equals(0) )
           return;



Thanks Tony.  Yea it was all me.  I tried different ways, but couldn't get it to fire correctly.  I will make that change.  Learned something new also.  :-)

Edit: When I do it this way it always returns false even when 'CmdActive' returns 0.  I tried to convert it to an integer, but that doesn't work either "Specified cast is not valid".  Unless you know another way, I have to do it the way I did, as I don't see another way to get the correct results.

Quote
if(  ! AcadApp.GetSystemVariable("CMACTIVE").Equals(0) )
           return;

"CMACTIVE"?
Title: Re: Tool palette, Object selection and Event
Post by: T.Willey on June 15, 2007, 06:33:55 PM
"CMACTIVE"?
Typo.  :-)
Title: Re: Tool palette, Object selection and Event
Post by: Paul Richardson on June 15, 2007, 07:06:53 PM
"CMACTIVE"?
Typo.  :-)
Was that the problem or just a typo here?
Title: Re: Tool palette, Object selection and Event
Post by: T.Willey on June 15, 2007, 07:33:29 PM
"CMACTIVE"?
Typo.  :-)
Was that the problem or just a typo here?
Just a typo here.  I didn't copy/paste Tony's code, I just made the change he suggested.
Title: Re: Tool palette, Object selection and Event
Post by: TonyT on June 16, 2007, 05:13:30 AM
Hi Tim. I didn't check what type GetVariable() returns for CMDACTIVE,
so I'll guess that its a short.

If it's a short, then just cast the literal 0 to a short, like this:

   if( ! AcadApp.GetSystemVariable("CMDACTIVE").Equals( (short) 0 ) )
      ...

IMHO, it was a big screw up for Autodesk to not promote all
ordinal values returned by GetVariable() to integers, because
of this very issue.
     

"CMACTIVE"?
Typo.  :-)
Was that the problem or just a typo here?
Just a typo here.  I didn't copy/paste Tony's code, I just made the change he suggested.
Title: Re: Tool palette, Object selection and Event
Post by: Chuck Gabriel on June 16, 2007, 09:20:06 AM
It definitely is a short.  I had to cast it to short in my HotKeys program, though I was using operator== for the comparison.
Title: Re: Tool palette, Object selection and Event
Post by: T.Willey on June 18, 2007, 11:08:21 AM
Hi Tim. I didn't check what type GetVariable() returns for CMDACTIVE,
so I'll guess that its a short.

If it's a short, then just cast the literal 0 to a short, like this:

   if( ! AcadApp.GetSystemVariable("CMDACTIVE").Equals( (short) 0 ) )
      ...

IMHO, it was a big screw up for Autodesk to not promote all
ordinal values returned by GetVariable() to integers, because
of this very issue.
     

"CMACTIVE"?
Typo.  :-)
Was that the problem or just a typo here?
Just a typo here.  I didn't copy/paste Tony's code, I just made the change he suggested.
Thanks Tony!  That was the problem.

It definitely is a short.  I had to cast it to short in my HotKeys program, though I was using operator== for the comparison.
Thanks Chuck for the conformation.

How did you guys know it was a short?  Is there a way to test what base class an object is, without knowing for sure?  Or is this just experience to know it's one or the other?
Title: Re: Tool palette, Object selection and Event
Post by: Chuck Gabriel on June 18, 2007, 11:17:37 AM
How did you guys know it was a short?  Is there a way to test what base class an object is, without knowing for sure?  Or is this just experience to know it's one or the other?

Glenn R told me. :-)
Title: Re: Tool palette, Object selection and Event
Post by: T.Willey on June 18, 2007, 11:19:55 AM
How did you guys know it was a short?  Is there a way to test what base class an object is, without knowing for sure?  Or is this just experience to know it's one or the other?

Glenn R told me. :-)
Nice!  :lmao:
Title: Re: Tool palette, Object selection and Event
Post by: TonyT on June 19, 2007, 08:10:03 AM


How did you guys know it was a short?  Is there a way to test what base class an
object is, without knowing for sure?  Or is this just experience to know it's one or
the other?


Object.GetType() returns the actual type.

You can also see types in the debugger's watch and locals windows.

Title: Re: Tool palette, Object selection and Event
Post by: T.Willey on June 19, 2007, 11:04:51 AM


How did you guys know it was a short?  Is there a way to test what base class an
object is, without knowing for sure?  Or is this just experience to know it's one or
the other?


Object.GetType() returns the actual type.
I thought I had tried the Object.GetType() before and it just said object, but I guess I am remembering wrong as that worked.  Thanks Tony.

You can also see types in the debugger's watch and locals windows.
Another reason to learn more about the debugger.  I will learn it one day.  :-)
Title: Re: Tool palette, Object selection and Event
Post by: gswang on June 18, 2010, 09:20:01 PM
Tim Willey, what's the final code?
thank you very much.
Title: Re: Tool palette, Object selection and Event
Post by: T.Willey on June 22, 2010, 12:33:50 PM
Tim Willey, what's the final code?
thank you very much.

I haven't used this code in awhile, but this is the latest one on my system.
Title: Re: Tool palette, Object selection and Event
Post by: gswang on June 23, 2010, 09:22:53 PM
Thank you, Tim Willey, i'll try it.. :-)
Title: Re: Tool palette, Object selection and Event
Post by: murrdpirate on June 27, 2010, 04:52:47 PM
I've found an alternative way to do this.  It seems a lot easier to implement, but I am not sure if it is more efficient, reliable, etc, so I will leave that up to more knowledgeable people to discuss.

The techniques used in this thread seemed too beyond me, so I thought maybe instead of going too deep into the AutoCAD API, I could use the Windows API to first detect if the left mouse button was clicked, then use the AutoCAD API to see if any objects are selected.  It is slightly more involved than normal to detect a mouse click outside your form/control, but after a bit of searching I found an easy method that works.  Here is what I did:

1)  Declare function "GetAsyncKeyState" from the user32 library
2)  Add a timer to my control
3)  Within the Timer1_Tick sub, use GetAsyncKeyState to see if the left-mouse button is down.
4)  If the left mouse button is down, see if objects are selected, see if any of the objects are of the type I care about, display properties, etc.

Here's the code:

Code: [Select]
Imports Spaces.SpaceClass

Public Class SpaceControlForm

    Private Declare Function GetAsyncKeyState Lib "user32" (ByVal vKey As Long) As Integer
    Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
        If GetAsyncKeyState(1) = 0 Then
            ' Label1.Text = "Left mouse button up"
        Else
            ' Label1.Text = "Left mouse button down"
            MouseOverControl()
        End If
    End Sub

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Timer1.Enabled = True
    End Sub

End Class

The MouseOverControl sub just checks what, if any, entities are selected (using myEditor.SelectImplied) and then displays some properties of the entities I care about. 

Title: Re: Tool palette, Object selection and Event
Post by: murrdpirate on June 28, 2010, 11:30:50 AM
Actually, I'm not sure using a timer is such a good idea.  I'm now using an AutoCAD event handler as Tim Wiley used.  I think I'm doing something very similar to his code, but here it is:

I want to use the event "ImpliedSelectionChanged," which fires whenever the list of currently selected entities changes, obviously.  To use events, you have to reference the AutoCAD.Interop library and assign the event to a method.

Here's some info on using events:  http://docs.autodesk.com/ACD/2011/ENU/filesMDG/WS73099cc142f48755-5c83e7b1120018de8c0-2465.htm

Code: [Select]
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Dim acDoc As Document = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument
        AddHandler acDoc.ImpliedSelectionChanged, AddressOf GetSelectedObjectIDs
End Sub

Shared Function GetSelectedObjectIDs()
        Dim myDB As Database = HostApplicationServices.WorkingDatabase
        Dim myEditor As Editor = Application.DocumentManager.MdiActiveDocument.Editor
        Dim PossibleSelectionSet As PromptSelectionResult = myEditor.SelectImplied
        Dim mySelectionSet As SelectionSet = Nothing
        Dim myObjectIDs As New List(Of ObjectId)

        If PossibleSelectionSet.Status = PromptStatus.OK Then
            Using myTrans As Transaction = myDB.TransactionManager.StartTransaction
                mySelectionSet = PossibleSelectionSet.Value
                For Each mySelObj As SelectedObject In mySelectionSet
                   myObjectIDs.Add(mySelObj.ObjectId)
                Next
            End Using
        End If
        Return myObjectIDs
End Function