Accessing the document from c# Form (ExternalCommandData Issue)

Accessing the document from c# Form (ExternalCommandData Issue)

RickyBell
Enthusiast Enthusiast
4,179 Views
4 Replies
Message 1 of 5

Accessing the document from c# Form (ExternalCommandData Issue)

RickyBell
Enthusiast
Enthusiast

My application launches a form with parameter results of what was selected.  From the form, I want to write back to the components.  I'm using their InstanceID numbers to reference them.

 

I just can't seem to find a way to reference the document from the form's "System.Windows.Forms.Form" code.  Is there a way to reference the ExternalCommandData from outside of the IExternalCommand class?

0 Likes
Accepted solutions (1)
4,180 Views
4 Replies
Replies (4)
Message 2 of 5

Anonymous
Not applicable

Hmm I tried replying earlier but it didn't work for some reason. Anyway my reply was incorrect, so ignore it if it turns up.

 

Here are a few suggestions:

 

1.

If your command is part of an external application, set up a public static field in the main application class that holds a reference to the current document. Then at the beginning of every external command the first thing you do is update that reference with the current document. You can then access the document from wherever you want.

 

2.

You could pass a reference to the document into an overloaded constructor of your Form class, and store it as a field.

 

3.

Get a little more complicated and set up a struct that holds an ElementId and details of the updated parameters. Keep a public list of these in the form class and then once you close the form, depending on the value of DialogResult you either access the list from the external command method and perform the updates or do nothing if the user cancelled the form.

 

 

I personally use method 3 with the added step of first passing in a list containing all the relevent data to be displayed and manipulated. I then use flags to indicate which parameters have been changed. As a rule, I keep my form code free of API calls.

0 Likes
Message 3 of 5

RickyBell
Enthusiast
Enthusiast

Hey, thanks for the guidance.  I'm trying out method number 1.  When creating the static field, what data type should it be?  I have it error-free as a string, but I think a string won't help me when referencing the document.  Maybe it will, you tell me.  Here's what I have so far.

 

public static string DocumentRef(ExternalCommandData commandData)
    {
        UIApplication uiApp = commandData.Application;
        UIDocument uiDoc = uiApp.ActiveUIDocument;
        Document doc = uiDoc.Document;
        return doc.ToString();
    }

 

If this is correct, how would I then call the static method from the form?  Thanks!

0 Likes
Message 4 of 5

Anonymous
Not applicable
Accepted solution

I'm not sure where you are going with the ToString idea, here's a run-down on what I was getting at.

 

As part of your main application class you want something like:

 

public class MyApp : Autodesk.Revit.UI.IExternalApplication
{
public static Autodesk.Revit.DB.Document DbDoc; // The current database document

// other code goes here...
}

 

Then at the biginning of each command that runs in your application you want to store away the current document like so:

 

 

public class MyCommand : IExternalCommand
{
    public Autodesk.Revit.UI.Result Execute(ExternalCommandData commandData, ref String message, ElementSet elements)
    {
        MyApp.DbDoc = commandData.Application.ActiveUIDocument.Document; // Update the static field to hold current database document

// Your code here... } }

 

 

Now, wherever you are in your code you can reference the current document using MyApp.DbDoc as long as it was first updated when the command was executed.

 

I must stress though that the above example is quite simplistic and depending on who you ask it is also bad software design as it is basically a global variable that could be corrupted accidentally by any part of your code. That said, I use a more sophisticated and safer version of the above in my addins without issue. It is much more friendly than the alternative which involves passing the the DB.Document into every method that you write if it is even remotely possible that the method might need to either use it directly or call another method that needs it.

 

Having the DB.Document object cached in this way also makes it simple to access the rest of the API from other parts of your code without having to directly cache them. A few examples are:

 

UI.Document uiDoc =  new UIDocument(MyApp.DbDoc);

Creation.Document createDoc = MyApp.DbDoc.Create;

ApplicationServices.Application servicesApp = MyApp.DbDoc.Application;

Creation.Application createApp = MyApp.DbDoc.Application.Create;

 

For bonus points you can create static properties that return the above objects using the cached Document object (MyApp.UiDoc, MyApp.CreateDoc, etc).

Message 5 of 5

RickyBell
Enthusiast
Enthusiast

Great Scott!

 

Thanks so much.  I was able to get it working using these lines in my main application:

 

public static Autodesk.Revit.DB.Document DbDoc;

DbDoc = uiDoc.Document;

 

And then referring to it as I need it with this line in my form:

 

UIDocument uiDoc = new UIDocument(MyApp.DbDoc);

 

Works great, thanks!

0 Likes