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

How to handle multiple open documents gracefully

14 REPLIES 14
Reply
Message 1 of 15
jspark
840 Views, 14 Replies

How to handle multiple open documents gracefully

I have a .NET app that is loaded with the NETLOAD command. I have a single command method that loads a custom control into a palette, and displays it. Whenever my code needs a reference to "ThisDrawing", "ThisAcad", "ThisDB" etc... it is gotten from a function that returns the needed reference. That said I have a few questions:

Why do my event handlers (the app in general) only become active after I type the command for my command method? Why are they not functional after the NETLOAD command? Is my application object (the class that contains my command method and my withevents member declarations) only instantiated when a command method is called?

Why does my app stop working when a new drawing is opened if the AcadApp, Document, Editor, Database etc.. references are gotten from a function? Example:

Dim WithEvents ThisDrawing as Document = GetDoc()

I think I am incorrectly assuming that each time my code uses ThisDrawing, it's the same as calling GetDoc(). Maybe I should explicitly set ThisDrawing = GetDoc() each time a new drawing becomes active?

Any other tips on gracefully handling the transition from active document to active document will be much appreciated as well.

TIA
14 REPLIES 14
Message 2 of 15
pavlos.katsonis
in reply to: jspark

Concerning the event handlers, these must be initialized in the entrypoint of your app, not in the command method. The command method runs only when you call the corresponding command. The entrypoint runs when your app is loaded. That is the only thing that runs when an app is loaded.
Message 3 of 15
Anonymous
in reply to: jspark

I suppose that if you've been using VBA and its
'ThisDrawing' object, you might become confused
by what you take for granted.

In VBA, 'ThisDrawing' looks like a variable, but is
in reality, more like a function that always returns
the Active document in the editor.

So in .NET, rather than assigning a variable to
the result of your GetDoc() function (which I
presume returns the active document), you must
call the GetDoc() function when want the Active
document (or to make it easier, you can add a
property to your class called 'ThisDrawing', and
in the 'getter' for it, just return the active doc).

When you're working with palettes, you should
never cache a document object in a variable. You
should always reference the MdiActiveDocument
property of the DocumentCollection directly, when
an operation begins, and then use that value only
for the duration of the operation. An 'operation'
means when the user clicks a button on your
user interface, and in response, you access the
active document to do something.

What is also not obvious about VBA's 'ThisDrawing',
is that when you handle an event of 'ThisDrawing',
the event is fired for every open document, not
just the one that was active when the event was
assigned.

In .NET, things are not as simple or automatic as
they are in VBA.

In .NET a Document object represents a single
Document open in the editor, that has its own
events. When you add a handler for a Document
event to a Document, the handler only receives
notification for the event in the Document that
you added the handler to. So, to handle the same
document event in every document, you must
add the handler for the event to every document
manually.

In order to do that, you handle the events of the
DocumentCollection (Application.DocumentManager),
like DocumentAdded, and DocumentToBeDestroyed,
and in the handlers for those events, you must add
or remove your document event handlers to the
newly added, or about-to-be closed document.

If your app is not loaded at startup, then you also
have to iterate over the collection of currently open
documents, and add document events handlers to
each of them.

There's sample code showing how to do this on my
website, but its in C#. There may be someone here
that has converted it to VB.NET.


--
http://www.caddzone.com

AcadXTabs: MDI Document Tabs for AutoCAD 2008
Supporting AutoCAD 2000 through 2008
http://www.acadxtabs.com

wrote in message news:5738738@discussion.autodesk.com...
I have a .NET app that is loaded with the NETLOAD command. I have a single command method that loads a custom control into a palette, and displays it. Whenever my code needs a reference to "ThisDrawing", "ThisAcad", "ThisDB" etc... it is gotten from a function that returns the needed reference. That said I have a few questions:

Why do my event handlers (the app in general) only become active after I type the command for my command method? Why are they not functional after the NETLOAD command? Is my application object (the class that contains my command method and my withevents member declarations) only instantiated when a command method is called?

Why does my app stop working when a new drawing is opened if the AcadApp, Document, Editor, Database etc.. references are gotten from a function? Example:

Dim WithEvents ThisDrawing as Document = GetDoc()

I think I am incorrectly assuming that each time my code uses ThisDrawing, it's the same as calling GetDoc(). Maybe I should explicitly set ThisDrawing = GetDoc() each time a new drawing becomes active?

Any other tips on gracefully handling the transition from active document to active document will be much appreciated as well.

TIA
Message 4 of 15
jspark
in reply to: jspark

Thank you both for your time. It has been very enlightening. A few more questions with some sample code this time…

In a nutshell, this is “MyApp” object:

Imports Autodesk.AutoCAD.ApplicationServices
Imports Autodesk.AutoCAD.Interop

Public Class MyApp

‘Private Members
Private WithEvents mThisAcad as AcadApplication = Ctype(ThisAcad.AcadApplication, AcadApplication)
Private WithEvents mThisDrawing as AcadDocument = Ctype(ThisDrawing.AcadDocument, AcadDocument)

‘Public Properties
Public Shared ReadOnly Property ThisAcad as Application
Get
Return Application.AcadApplication
End Get
End Property

Public Shared ReadOnly Property ThisDrawing as Document
Get
Return Application.DocumentManager.MdiActiveDocument
End Get
End Property

‘Methods
(Autodesk.AutoCAD.Runtime.CommandMethod("Start", "Start", _ Autodesk.AutoCAD.Runtime.CommandFlags.Modal)> _
Public Sub Start()
‘Create a new PaletteSet and a Palette. Add Palette to PaletteSet.
‘Set PaletteSet.Visible = True
EndSub

‘Events
Private Sub mThisDrawing_ObjectAdded(ByVal Obj As Object) Handles _ mThisDrawing.ObjectAdded
‘Do Stuff
End Sub

End Class

If I were to reset mThisDrawing = Ctype(ThisDrawing.AcadDocument, AcadDocument) each time a new Document becomes the active document, would my ObjectAdded event now only apply to the new active document?

IIRC, my ObjectAdded event will not fire until my command method has been executed from the command prompt. Why is that? It's almost as if "MyApp" is not created until the command method is executed.

I want “MyApp” object to be a single instance. Should I declare it as: Public Shared Class Myapp?

Overall, I want a single MyApp object and a single PaletteSet object to handle any active document the user throws at it. What should I be (not be) doing to make this so? (I should probably not be declaring a NEW PaletteSet in my command method.)
Message 5 of 15
Anonymous
in reply to: jspark

In order for your event handler to be fired,
there needs to be an instance of the class
the handler is declared in.

Have you wondered how an instance of your
class is being created?

--
http://www.caddzone.com

AcadXTabs: MDI Document Tabs for AutoCAD 2008
Supporting AutoCAD 2000 through 2008
http://www.acadxtabs.com

wrote in message news:5739156@discussion.autodesk.com...
Thank you both for your time. It has been very enlightening. A few more questions with some sample code this time…

In a nutshell, this is “MyApp” object:

Imports Autodesk.AutoCAD.ApplicationServices
Imports Autodesk.AutoCAD.Interop

Public Class MyApp

‘Private Members
Private WithEvents mThisAcad as AcadApplication = Ctype(ThisAcad.AcadApplication, AcadApplication)
Private WithEvents mThisDrawing as AcadDocument = Ctype(ThisDrawing.AcadDocument, AcadDocument)

‘Public Properties
Public Shared ReadOnly Property ThisAcad as Application
Get
Return Application.AcadApplication
End Get
End Property

Public Shared ReadOnly Property ThisDrawing as Document
Get
Return Application.DocumentManager.MdiActiveDocument
End Get
End Property

‘Methods
(Autodesk.AutoCAD.Runtime.CommandMethod("Start", "Start", _ Autodesk.AutoCAD.Runtime.CommandFlags.Modal)> _
Public Sub Start()
‘Create a new PaletteSet and a Palette. Add Palette to PaletteSet.
‘Set PaletteSet.Visible = True
EndSub

‘Events
Private Sub mThisDrawing_ObjectAdded(ByVal Obj As Object) Handles _ mThisDrawing.ObjectAdded
‘Do Stuff
End Sub

End Class

If I were to reset mThisDrawing = Ctype(ThisDrawing.AcadDocument, AcadDocument) each time a new Document becomes the active document, would my ObjectAdded event now only apply to the new active document?

IIRC, my ObjectAdded event will not fire until my command method has been executed from the command prompt. Why is that? It's almost as if "MyApp" is not created until the command method is executed.

I want “MyApp” object to be a single instance. Should I declare it as: Public Shared Class Myapp?

Overall, I want a single MyApp object and a single PaletteSet object to handle any active document the user throws at it. What should I be (not be) doing to make this so? (I should probably not be declaring a NEW PaletteSet in my command method.)
Message 6 of 15
jspark
in reply to: jspark

Yes, I have been wondering, and am unclear on when exactly "MyApp" is created. I would guess that NETLOAD does not create an instance of "MyApp". In order to execute the command method, an instance of "MyApp" is created... If thats the case then I would assume a second instance of "MyApp" is NOT created when the command is ran for a second time. So I dont need to worry about multiple instances of "MyApp" object being created. What about resetting mThisDrawing each time a new document becomes the active document? Will that make the same event handler work for the new active doc? (I guess I could do some tests to figure that out, but it sounds logical...) Am I on the right track here?
Message 7 of 15
caddie75
in reply to: jspark

Hi,

In the beginning I also struggled how to do it..look into the following:

1. Best is to let the Assembly (dll) autoload into AutoCAD, this requires a registry key.

2. Use a "Autodesk.AutoCAD.Runtime.IExtensionApplication" in you're app. As soon as the app gets loaded (NETLOAD or AutoLoad) then this class gets Initialized.

On the "Initialize" you can create a Shared instance of the custom class that handles the documents. (including events)

3. In you're Custom Class (let's name it: "acEvents_Manager" or so)
In this class there have to be the Application Reference for handling events raised by the Application (ACAD), this depends on what events you will need.
You also need a DocumentCollection Reference(instance)
This one DocumentBecameCurrent, DocumentCreated etc....

4. Form the events of the DocumentCollection you'll be able to react, depending on you're goals.

5. You can then event "listen" to database events. If a object changes, you can eval it and possibly update information displayed on a Palette.

Samples etc, of these can be found in this NG.
Search for the following:
"Autoload dll"
"IExtensionApplication"
"DocumentCollection"

ps. You should also download the "ObjectARX SDK (2008)"
There samples and documentation regarding .NET in it.
It helped me a lot.
(i You need it I can upload a sample in VB.net)

I use the following config:
AutoCAD 2008, VS2005, WinXP sp2

Good luck,
A. Caddie
Message 8 of 15
jspark
in reply to: jspark

That is very helpful, thank you. I will search the NG using your suggestions. I did assume I would need to handle the DocumentCollection events in order to keep "mThisDrawing" up to date with the active document. Will my application class need to "Inherit" IExtensionApplication? I am not sure what you mean by "Use "Autodesk.AutoCAD.Runtime.IExtensionApplication" in you're app". I will look into the IExtensionAppliciation. You also suggested that I create a new class for handling events. Is it "ok" to handel events within my main application class?
Message 9 of 15
Anonymous
in reply to: jspark

What a nice professional response. You must have had some good action last
night 🙂

Davis
"Tony Tanzillo" wrote in message
news:5739091@discussion.autodesk.com...
I suppose that if you've been using VBA and its
'ThisDrawing' object, you might become confused
by what you take for granted.

In VBA, 'ThisDrawing' looks like a variable, but is
in reality, more like a function that always returns
the Active document in the editor.

So in .NET, rather than assigning a variable to
the result of your GetDoc() function (which I
presume returns the active document), you must
call the GetDoc() function when want the Active
document (or to make it easier, you can add a
property to your class called 'ThisDrawing', and
in the 'getter' for it, just return the active doc).

When you're working with palettes, you should
never cache a document object in a variable. You
should always reference the MdiActiveDocument
property of the DocumentCollection directly, when
an operation begins, and then use that value only
for the duration of the operation. An 'operation'
means when the user clicks a button on your
user interface, and in response, you access the
active document to do something.

What is also not obvious about VBA's 'ThisDrawing',
is that when you handle an event of 'ThisDrawing',
the event is fired for every open document, not
just the one that was active when the event was
assigned.

In .NET, things are not as simple or automatic as
they are in VBA.

In .NET a Document object represents a single
Document open in the editor, that has its own
events. When you add a handler for a Document
event to a Document, the handler only receives
notification for the event in the Document that
you added the handler to. So, to handle the same
document event in every document, you must
add the handler for the event to every document
manually.

In order to do that, you handle the events of the
DocumentCollection (Application.DocumentManager),
like DocumentAdded, and DocumentToBeDestroyed,
and in the handlers for those events, you must add
or remove your document event handlers to the
newly added, or about-to-be closed document.

If your app is not loaded at startup, then you also
have to iterate over the collection of currently open
documents, and add document events handlers to
each of them.

There's sample code showing how to do this on my
website, but its in C#. There may be someone here
that has converted it to VB.NET.


--
http://www.caddzone.com

AcadXTabs: MDI Document Tabs for AutoCAD 2008
Supporting AutoCAD 2000 through 2008
http://www.acadxtabs.com

wrote in message news:5738738@discussion.autodesk.com...
I have a .NET app that is loaded with the NETLOAD command. I have a single
command method that loads a custom control into a palette, and displays it.
Whenever my code needs a reference to "ThisDrawing", "ThisAcad", "ThisDB"
etc... it is gotten from a function that returns the needed reference. That
said I have a few questions:

Why do my event handlers (the app in general) only become active after I
type the command for my command method? Why are they not functional after
the NETLOAD command? Is my application object (the class that contains my
command method and my withevents member declarations) only instantiated when
a command method is called?

Why does my app stop working when a new drawing is opened if the AcadApp,
Document, Editor, Database etc.. references are gotten from a function?
Example:

Dim WithEvents ThisDrawing as Document = GetDoc()

I think I am incorrectly assuming that each time my code uses ThisDrawing,
it's the same as calling GetDoc(). Maybe I should explicitly set ThisDrawing
= GetDoc() each time a new drawing becomes active?

Any other tips on gracefully handling the transition from active document to
active document will be much appreciated as well.

TIA
Message 10 of 15
pavlos.katsonis
in reply to: jspark

It would be better to download the SDK and read everything concerning the entrypoint of an application. The method is simple enough and the examples are good.
The entrypoint is just a method of one of your classes that is executed during load time. You just have to declare it in a certain way. It's simple enough after you see the examples.
After you implement it, you can decide whether you want to store your variables in static variables and create a new instance of your class for every drawing or whatever.
Message 11 of 15
jspark
in reply to: jspark

I have already downloaded the SDK but have not read much of the documentation yet. Thank you all so much. I believe I have enough homework to keep me busy for a while.
Message 12 of 15
jspark
in reply to: jspark

That was almost too easy. 😃
Message 13 of 15
NathTay
in reply to: jspark

You might find some of the info in this post useful.

http://discussion.autodesk.com/thread.jspa?messageID=5538160
Message 14 of 15
Anonymous
in reply to: jspark

"CADJunkie" wrote:

>> What a nice professional response.

No, that's simply how all 'non-charletans'
are treated.

--
http://www.caddzone.com

AcadXTabs: MDI Document Tabs for AutoCAD 2008
Supporting AutoCAD 2000 through 2008
http://www.acadxtabs.com
Message 15 of 15
Anonymous
in reply to: jspark

>> So I dont need to worry about multiple instances
>> of "MyApp" object being created.

Well, not quite.

The way it works is that if your command method is
non-static (not shared), as is the case in your code,
AutoCAD creates a seperate instance of your class,
for each open document. So, if there are 3 open
documents, there will be three instances of your
"MyApp" class.

That may be what is leading you to think that VB is
automatically switching the events every time you
assign a non-static/shared member variable that has
the 'WithEvents', to another document.

In fact, what you don't realize is that there is more
than one instance of your class, and each of them is
being used with a different document, so it gives the
illusion that the event handlers are automatically
added to the document assigned to the variable each
time the variable's value is changed, but that's not
what's going on at all.


--
http://www.caddzone.com

AcadXTabs: MDI Document Tabs for AutoCAD 2008
Supporting AutoCAD 2000 through 2008
http://www.acadxtabs.com

wrote in message news:5739332@discussion.autodesk.com...
Yes, I have been wondering, and am unclear on when exactly "MyApp" is created. I would guess that NETLOAD does not create an instance of "MyApp". In order to execute the command method, an instance of "MyApp" is created... If thats the case then I would assume a second instance of "MyApp" is NOT created when the command is ran for a second time. So I dont need to worry about multiple instances of "MyApp" object being created. What about resetting mThisDrawing each time a new document becomes the active document? Will that make the same event handler work for the new active doc? (I guess I could do some tests to figure that out, but it sounds logical...) Am I on the right track here?

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

Post to forums  

Autodesk DevCon in Munich May 28-29th


Autodesk Design & Make Report

”Boost