Revit API Forum
Welcome to Autodesk’s Revit API Forums. Share your knowledge, ask questions, and explore popular Revit API topics.
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

how to load a rvt file automatically when start the revit?

16 REPLIES 16
SOLVED
Reply
Message 1 of 17
DAVIX
3418 Views, 16 Replies

how to load a rvt file automatically when start the revit?

Hi, 

 

I wonder how can I load a revit file automatically when start the revit system. 

Since the UIControlledApplication is the only parameter of the OnStartup function of the IExternalApplication class, while the OpenAndActivateDocument is the function of the UIApplication but not of the UIControlledApplication

How can I invoke the UIApplication. OpenAndActivateDocument in OnStartup function? or is there other methods to address the problem?

Thx !

16 REPLIES 16
Message 2 of 17
jeremytammik
in reply to: DAVIX

Dear Davix,

 

The easiest way to start up Revit with a project file loaded is to use Process.Start:

 

http://thebuildingcoder.typepad.com/blog/2010/03/using-processstart-to-open-a-project-or-family.html

 

Once Revit is up and running, you can also use the UIApplication.OpenAndActivateDocument method:

 

http://thebuildingcoder.typepad.com/blog/2012/12/closing-the-active-document.html

 

You probably cannot do anything at all like this in the OnStartup method, because Revit is not yet fully started up and ready to process documents when that method is called.

 

You have to wait until later, for instance by temporarily subscribing to the Idling event in the OnStartup method, then unsubscribing from Idling in the Idling event handler, opening the document and doing whatever else you want at that point.

 

Cheers,

 

Jeremy



Jeremy Tammik
Developer Technical Services
Autodesk Developer Network, ADN Open
The Building Coder

Message 3 of 17
jeremytammik
in reply to: jeremytammik

Dear Davix,

 

I expanded a bit on my initial answer and published a summary of this thread on The Building Coder:

 

http://thebuildingcoder.typepad.com/blog/2015/02/family-instance-area-and-auto-loading-a-project-fil...

 

You might want to check out the enhanced answer there as well.

 

Thank you!

 

Cheers,

 

Jeremy



Jeremy Tammik
Developer Technical Services
Autodesk Developer Network, ADN Open
The Building Coder

Message 4 of 17
arnostlobel
in reply to: jeremytammik

Davix, And Jeremy:

 

Using the Idling event is not anymore the only solution for the problem as stated by Davix. Idling event might be the only work-around three years ago, but there is a better solution now. Since R2015 (if I recall correctly), a better way of opening a startup document is via the ApplicationInitialized event. Like with the Idling event, an application subscribes to it during the OnStartup call. Revit will then raise this event a bit later when the Revit application’s start-up has been completed. Remember, just with the Idling event, the OpenAndActivateDocument can be used only as long there is no active document in Revit yet.

Arnošt Löbel
Message 5 of 17
DAVIX
in reply to: jeremytammik

Dear Jeremy,

Thank you very much for your prompt and detail solution.

However, when I?test the?System.Diagnostics.Process.Start mechod, the revit file can be openned when start the Revit but disappear only straight away.

And I don't know how to test the idle event and how to?use the UIApplication.OpenAndActivateDocument method in onstart() since can not get the?UIApplication in the onstart().

Thx & Regards,

Davix

Message 6 of 17
arnostlobel
in reply to: DAVIX

Dear DAVIX,

As I tried to explain but failed, apparently, please do not use the Idling event. Use the ApplicationInitialized event instead. Subscribe to it during the onStartup method of your external application, then from within the event's handler invoke the OpenAndActivateDocument method.

Thank you.
Arnošt Löbel
Message 7 of 17
DAVIX
in reply to: arnostlobel

Dear Arnošt Löbel,

 

Thx! I'll try this solution.

 

Regards,

 

Davix

Message 8 of 17
DAVIX
in reply to: DAVIX

Dear Jeremy and Arnošt Löbel,

 

When I used the event ApplicationInitialized and the System.Diagnostics.Process.Start in the event handler, it works now. 

 

Thx for ur kindness direction !!

 

Regards,

 

Davix

 

Message 9 of 17
mattmason
in reply to: arnostlobel

Arnost,

 

Thanks for jumping in on the discussion - it's one I've had an ongoing interest in.

 

I'm not sure if I understand your suggestion to use the ApplicationInitialized event. While I agree that event is the right one to use for the timing of when it executes, it doesn't seem like we have access to the right contexts at the right time?

 

- If we register it during startup, we're registering it against the ControlledApplication class.

- When we are in the callback after, we're in the callback of the ControlledApplication class.

 

When we're in that callback - how would we have access to the UIApplication object so that we could call OpenAndActivate()?

 

 

Thanks,

Matt

Message 10 of 17
arnostlobel
in reply to: mattmason

Hello Matt,

 

I may be wrong, but I think it works differently than what you guessed. The object inside the OnStartup is indeed a ControlledApplication, but it ought to be an Application instance as the sender argument of the ApplicationInitialized even handler. With that you will be able to construct an instance of UIApplication and use its methods.  (Unfortunately, most of us New Englanders are working from their homes  today due to a storm, and I am trying to limit my debugging sessions to a minimum! If it turns out it is not working for you as I suggested, however, Ilet me know and ’ll debug it myself by tomorrow or Wednesday.)

 

Just as a side note: it does not matter whether an event handler subscribes to an event using ControlledApplication or Application. The repository of application event delegates are always with the Application instance (internally).

Arnošt Löbel
Message 11 of 17
jeremytammik
in reply to: arnostlobel

Dear Arnošt,

 

You make it sound so easy...

 

Here we are, an hour or two later:

 

class App : IExternalApplication
{
  const string _test_project_filepath
    = "Z:/a/rvt/CurvedWall.rvt";

  UIApplication _uiapp;

  public Result OnStartup( UIControlledApplication a )
  {
    // These attempts to access a UIApplication
    // or Application instance are all in vain:
    //
    //_uiapp = (UIApplication) a;
    //_uiapp = (UIApplication) a.ControlledApplication;
    //Application app = (Application) a;
    //Application app2 = (Application) a.ControlledApplication;
    //Application app3 = a.m_application;

    // Using Reflection works, though:

    Type type = a.GetType();

    // Not useful in this case, but interesting:

    MemberInfo[] publicMembers = type.GetMembers();
    MemberInfo[] nonPublicMembers = type.GetMembers( BindingFlags.NonPublic );
    MemberInfo[] staticMembers = type.GetMembers( BindingFlags.Static );

    // This is the call that finally yields useful results:

    BindingFlags flags = BindingFlags.Public 
      | BindingFlags.NonPublic 
      | BindingFlags.GetProperty 
      | BindingFlags.Instance;

    MemberInfo[] propertyMembers = type.GetMembers( 
      flags );

    // Note that the field "m_application" is listed
    // in the propertyMembers array, and also the 
    // method "getUIApp"... let's grab the field:

    string propertyName = "m_application";
    flags = BindingFlags.Public | BindingFlags.NonPublic 
      | BindingFlags.GetField | BindingFlags.Instance;
    Binder binder = null;
    object[] args = null;

    object result = type.InvokeMember(
        propertyName, flags, binder, a, args );

    _uiapp = (UIApplication) result;

    a.ControlledApplication.ApplicationInitialized
      += OnApplicationInitialized;

    return Result.Succeeded;
  }

  void OnApplicationInitialized( 
    object sender, 
    ApplicationInitializedEventArgs e )
  {
    UIApplication uiapp = sender as UIApplication;
    Application app = sender as Application;

    // uiapp is null, so this call will fail:

    if( null != uiapp )
    {
      // We never enter here...

      uiapp.OpenAndActivateDocument(
        _test_project_filepath );
    }

    // This call succeeds, though:

    _uiapp.OpenAndActivateDocument(
      _test_project_filepath );
  }

  public Result OnShutdown( UIControlledApplication a )
  {
    return Result.Succeeded;
  }
}

 

It works!

 

Is that what you intended?

 

🙂

 

Cheers,

 

Jeremy



Jeremy Tammik
Developer Technical Services
Autodesk Developer Network, ADN Open
The Building Coder

Message 12 of 17
mattmason
in reply to: jeremytammik

Arnost - 

Thanks! you are correct, the sender of the ApplicationInitialized event callback is the Application (not the controlled application). So my quest of a non-hacky way to transition between the ControlledApplication and the Application is finally solved!

 

As a fellow Bostonian, I'm also snowed in today. But if you want your sidewalk cleared, let me know - I am in your debt! 🙂

 

 

Jeremy - I'm not sure that the reflection was actually necessary? was that just exploration?

 

Best Regards,

Matt

 

 

 

Message 13 of 17
arnostlobel
in reply to: jeremytammik

Jeremy,

 

Perhaps I made it sound simple because it is in fact rather simple. Indeed, as Matt already noted, no reflection is necessary. In the OnStartup you get UIControlledApplication, from which you can get ControlledApplication (the latter always exists if the former does,)  and on that you subscribe to the ApplicationInitialized. Keep in mind you cannot cast a ControlledApplicaiton to Application – that is the ControlledApplicaiton’s very point of existence.

Then in the event handler the sender should be an instance of Application, which can be used to instantiate an UIApplication, on which the OpenAndActivateDocument method can be invoked. Like I said, quite simple. 😉 Each of the two methods is only a few lines of code.

 

Matt, it is trully a generous offer about you shoveling my sidewalk, but I sugest you sleep on it before we confirm for sure. There is a lot more snow still coming 🙂

Arnošt Löbel
Message 14 of 17
jeremytammik
in reply to: arnostlobel

Dear Arnošt and Matt,

 

Oh dear. What a waste.

 

Yes, of course, given the UIApplication constructor taking an Application argument, all is clear and the Reflection is not needed. I did not notice that, and what I described was the first alternative I could find  🙂 

 

Well, well, apparently all roads lead to Rome after all... but it saves effort taking the easiest path.

 

I wish you both lots of fun shovelling!

 

Thank you!

 

Cheers,

 

Jeremy



Jeremy Tammik
Developer Technical Services
Autodesk Developer Network, ADN Open
The Building Coder

Message 15 of 17
jeremytammik
in reply to: jeremytammik

For the sake of completeness and those that trust nothing but source code, here is the complete solution without using Reflection:

 

  class App : IExternalApplication
  {
    const string _test_project_filepath
      = "Z:/a/rvt/CurvedWall.rvt";

    public Result OnStartup( UIControlledApplication a )
    {
      a.ControlledApplication.ApplicationInitialized
        += OnApplicationInitialized;

      return Result.Succeeded;
    }

    void OnApplicationInitialized(
      object sender,
      ApplicationInitializedEventArgs e )
    {
      // This does not work, because the sender is
      // an Application instance, not UIApplication.

      //UIApplication uiapp = sender as UIApplication;

      // Sender is an Application instance:

      Application app = sender as Application;

      // However, UIApplication can be 
      // instantiated from Application.

      UIApplication uiapp = new UIApplication( app );

      uiapp.OpenAndActivateDocument(
        _test_project_filepath );
    }

    public Result OnShutdown( UIControlledApplication a )
    {
      return Result.Succeeded;
    }
  }

 

Cheers,

 

Jeremy



Jeremy Tammik
Developer Technical Services
Autodesk Developer Network, ADN Open
The Building Coder

Message 16 of 17
arnostlobel
in reply to: jeremytammik

That'll do, Jeremy. Thanks for summing it up.

 

It could also be noted, for the sake of completness, that it is the majority of application events of which the sender is the Application object. There is only a handful (if at all that much) of events which are raised by the UIApplication. Those are more like an exceptions to the rule, as documented in the SDK (the chm file.)  

Arnošt Löbel
Message 17 of 17
DAVIX
in reply to: arnostlobel

Dear Jeremy & Mattmason & Arnošt Löbel,

 

Thank you for your interests in the question I raised.

In fact, followed Jeremy  &  Arnošt Löbel' suggestion, I solved it like this, :

-------------------------------------------------------------------------------------------

public Result OnStartup(UIControlledApplication application) {
     try
     {
             // Register event.
             application.ControlledApplication.ApplicationInitialized += new EventHandler
             <Autodesk.Revit.DB.Events.ApplicationInitializedEventArgs>(TestAutomation);
     }
     catch (Exception)
     {
             return Result.Failed;
     }

     return Result.Succeeded;

}

 

public Result OnShutdown(UIControlledApplication application) {
         pplication.ControlledApplication.ApplicationInitialized -= new EventHandler
         <Autodesk.Revit.DB.Events.ApplicationInitializedEventArgs>(TestAutomation);
         return Result.Succeeded;
}

 

public void TestAutomation(object sender, ApplicationInitializedEventArgs args)
{
       System.Diagnostics.Process.Start(
       @"C:\BIMSamples\RoomsRenumbering\RoomsRenumbering\roomsRenumbering.rvt");
}

------------------------------------------------------------------------------------

 

Still, I cannot use the UIApplication in the codes aboved. And I'll try Jeremy's code latter.

 

Thx again for your attention and kind suggestion!

 

Regards,

 

Davix

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


Rail Community