I am occasionally developing with ObjectARX 2013. The last week I stumbled on a problem that does not seem to have many (elegant) solutions. I thought I should try to engage the community in having it discussed. Thanks in advance for having a look.
The problem: A command being executed from a document needs to focus on another document. I am doing that as:
Application.DocumentManager.MdiActiveDocument = aGeneratedDrawing;
After this line, the focus is taken by the other document. But the command execution just stops without producing any visible error or catchable exception. Apparently, the document focus cannot be changed during execution of a command.
A solution: What worked in the end was displaying a .NET form inside the command, like:
Then, performing the very same set of actions on a button click works flawlessly.
The question is: can using the form as a mediator be avoided? It is redundant there. I tried hooking to CommandEnded, executing the code as a separate command via Application.DocumentManager.MdiActiveDocument.Send
Solved! Go to Solution.
Code needs to be run in the 'session' or 'application' context to avoid being stopped when you switch documents. This is by design. One way to make your command run in the 'session' context is to use the Session CommandFlag in your CommandMethod attribute:
<CommandMethod("MyGroup", "MyCommandGlobal", "MyCommandLocal", CommandFlags.Session)>
Also take a look at DocumentCollection.ExecuteInApplicationContext
Remember to lock your documents when running code in the session context.
Gee, thanks man. I've got it running just fine with the session flag.
Let me put a few more words, since I found out I needed this implemented for a particular construct. Right now I am having an ObjectOverrule instance that catches when an element is erased in the drawing A, and takes appropriate actions in the drawing B. Since I have not found a way to attach the session attribute to the overridden Erase(DBObject, bool) method, I made that method call a command that has the session flag. I am calling it as:
For now, that seems to be working fine. However, I hope for a correction in case this would not be an entirely safe approach.
You must be reading Kean's blog a lot.
SendStringToExecute() is the worst possible way to solve a problem like this one.
How to best solve it depends on details, e.g., what exactly are the 'appropriate actions in the drawing B', which is most-likely not the active drawing when the entity in another drawing is erased.
You can manipulate the database of a drawing that's not the active document direclty via the API, except that there is a problem with graphics not updating, and currently there is no way to solve that one in purely managed code. The solution requires native code, and specifically a couple of calls to the AcApDocManager::setCurDocument(). API.
That API must be called and passed the AcApDocument containing the objects you will be modifying, and once you've finished modifying that document's database, you must call the same API again, and pass it the AcApDocument representing the active document. I'm still not sure why Autodesk hasn't exposed this API since this is a very long-standing problem that they've been made aware of more times than I care to recall.
If you don't want to take the native approach to solving that problem you can still avoid the SendStringToExecute kludge-o-rama by just setting a flag in your code, and then checking it from a handler for the DocumentActived event. In that event handler, when the passed in document is the one that requires changes, first clear the flag, and then add a handler to the Application.Idle event. When the handler for the Idle event is called, remove the handler from that event, lock the document, and then make your changes.
Most of the problems that we see Kean attempting to solve using the SendStringToExecute kludge, can be solved much more easily and reliably using the Application.Idle event.
Actually, I had not gotten chance to try out in the wild what you suggesed, but you had a Kudo for a new point of view. I am hoping to come again to the topic and try the new approach.
Fyi, the change in another document is about changing contents of a text object (text from "2" to "3" and such), but could as well be removing everything and redrawing the whole drawing. The problem I faced there is that erasing something in the main drawing triggers those changes in other drawings. And I haven't found a way to add the Session flag to the method in the overruling object.