DocumentCreated event won't trigger

DocumentCreated event won't trigger

AGGilliam
Collaborator Collaborator
5,152 Views
19 Replies
Message 1 of 20

DocumentCreated event won't trigger

AGGilliam
Collaborator
Collaborator

I have an External Application that subscribes to the DocumentCreated event in order to execute a command I created for every new document. But, for whatever reason, the event handler (ExecuteCommands) is never triggered. I have a similar setup for a different Application that works just fine so I don't understand what I could be missing.

 

Any ideas? The code for the application is pretty short so I added it below for reference:

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Autodesk.Revit.Attributes;
using Autodesk.Revit.DB;
using Autodesk.Revit.DB.Events;
using Autodesk.Revit.UI;

namespace NewDocApplication
{
    public class NewDoc : IExternalApplication
    {
        public Result OnStartup(UIControlledApplication uiConApp)
        {
            uiConApp.ControlledApplication.DocumentCreated += ExecuteCommands;
            return Result.Succeeded;
        }

        public Result OnShutdown(UIControlledApplication uiConApp)
        {
            uiConApp.ControlledApplication.DocumentCreated -= ExecuteCommands;
            return Result.Succeeded;
        }

        public void ExecuteCommands(object sender, DocumentCreatedEventArgs args)
        {
            UIApplication uiapp = (UIApplication)sender;
            var command = new PracticeMenu.Main();
            command.Execute(uiapp);
        }
    }
}

 

0 Likes
Accepted solutions (1)
5,153 Views
19 Replies
Replies (19)
Message 2 of 20

RPTHOMAS108
Mentor
Mentor

Are you saying that you have stepped into OnStartup to ensure the handler is added and you've also added a breakpoint within the ExecuteCommands function that is never hit?

0 Likes
Message 3 of 20

AGGilliam
Collaborator
Collaborator

That is correct, I added 2 breakpoints: one in the OnStartup method and one in ExecuteCommands. The breakpoint in OnStartup is hit but the one in ExecuteCommands is not.

0 Likes
Message 4 of 20

rnilay81
Enthusiast
Enthusiast

I think the syntax for adding the handler is a bit different. In my case it is working with code as below . Of course it is for DocumentOpened but you can try by changing along similar lines for your method  ..   Application_DocumentOpened is the method similar to your ExecuteCommands... 

 

uiApp.ControlledApplication.DocumentOpened
+= new EventHandler<Autodesk.Revit.DB.Events.DocumentOpenedEventArgs>(Application_DocumentOpened);

Message 5 of 20

MarryTookMyCoffe
Collaborator
Collaborator

It should work and documentation confirm it too. I thing I have similar problem when I had some critical error in event, I couldn't even make step in to event, but I don't see anything like that here.

Did you make new document with API or as user?

-------------------------------------------------------------
--------------------------------|\/\/|------------------------
do not worry it only gonna take Autodesk 5 years to fix bug
0 Likes
Message 6 of 20

AGGilliam
Collaborator
Collaborator

The syntax I've used has worked successfully in my other application, but I'll give it a shot and see if anything changes.

0 Likes
Message 7 of 20

AGGilliam
Collaborator
Collaborator

The document was created as a user from the Revit home screen, would that make a difference though?

0 Likes
Message 8 of 20

AGGilliam
Collaborator
Collaborator

@rnilay81 I tried swapping to your suggested syntax, but the ExecuteCommands method is still not triggered. Thank you for the suggestion though.

0 Likes
Message 9 of 20

RPTHOMAS108
Mentor
Mentor

Note that DocumentCreated event has a sender which is of type Autodesk.Revit.ApplicationServices.Application.

 

UIApplication derives from Object, so the line you have in the handler should throw an exception on that basis?

 

Code is optimized so sometimes a breakpoint on a certain line will not hit with this optimisation, you can turn optimisation off and check again.

 

 

Message 10 of 20

AGGilliam
Collaborator
Collaborator

Sorry, I misclicked the solution button.

 

Thanks for the heads up, I'll make sure to change that. I'll look into that optimisation option as well.

0 Likes
Message 11 of 20

RPTHOMAS108
Mentor
Mentor

I think you'll have to get UIApplication from somewhere else if you need it, such as Execute method of IExternalEventHandler. Document you can get from the event args.

 

From what I've checked today in 2021 this event triggers from wherever a document is created.

0 Likes
Message 12 of 20

AGGilliam
Collaborator
Collaborator

I made the change to treat the sender as an Application, but it still didn't work. I also tried looking into the setting you mentioned and couldn't find it so I commented out the code in ExecuteCommands and the debugger finally hit the breakpoint.

 

Do you know what the name of that setting in Visual Studio might be called?

 

Also, where else would I get UIApplication from? Is that method not considered the Event Handler? (btw, in case it wasn't clear, PracticeMenu is an ExternalCommand I'm trying to execute upon document creation)

0 Likes
Message 13 of 20

RPTHOMAS108
Mentor
Mentor

In C# if you go into the project properties and the 'Build' section you'll see a checkbox for 'Optimize code' under General. 

 

An external event is something you make the request for with Revit and then when it is ready (in a state it can respond) it gives you a valid context similar to IExternalCommand.  It is not really the same as a standard programming event you add handler to etc. There is a lot of information available regarding setting up external events in Revit.

 

Alternatively the idling event has a sender of UIApplication and would be called at some point so you could use this to get UIApplication. However why does the ExternalCommand need to be called this way and why do you need UIApplication?

Message 14 of 20

AGGilliam
Collaborator
Collaborator

I guess I should have added some more background in the original post. The whole goal of this is to register a DocumentCreatedEvent so that, when a document is created, a window pops up automatically allowing the user to enter some project info. I've already created this as an ExternalCommand so the user can run it at any point and change the info, but I didn't want to rewrite the code if I can execute it directly through the Application.

 

I did finally manage to find the error description, and it appears to be an issue with connecting to said ExternalCommand. "Could not load file or assembly PracticeMenu...The system cannot find the file specified." Which tells me I'm probably going about this the wrong way.

 

I thought I understood how the event handlers work but it seems I need to do some more learning.

0 Likes
Message 15 of 20

RPTHOMAS108
Mentor
Mentor

Yes consider also that the DocumentCreated event will not cover the case where the file already exists but the project information hasn't been entered. If you use also DocumentOpened event then you could do a quick check of this information entry and then prompt to add it if that hasn't been done yet.

 

What you are aiming to do sounds feasible but maybe you are overthinking it.

All you need to do is create a static NamedMethod that is called from the external command or the event.

Set up the IExternalCommand in the usual way, get the active document from command data*** and pass that to the NamedMethod(Document)

Set up a handler for DocumentCreated(s as object, e as DocumentCreatedEventArgs)

Pass document to NamedMethod(e.Document)

The document created event states that the document can be modified but you need to check 'Status' field in event args (e.Status).

 

**When getting active document from command data (commandData.Application.ActiveUIDocument.Document) always check if UIDocument is null i.e. zero document state and exit if so.

 

I don't think you need UIApplication for this task (from the event handler)?

0 Likes
Message 16 of 20

AGGilliam
Collaborator
Collaborator

I really appreciate that explanation. The reason for using the External Application is to register to the Document Created event on startup. If it didn't register until someone ran the command, that would kind of defeat the purpose.

0 Likes
Message 17 of 20

RPTHOMAS108
Mentor
Mentor

You register that event during OnStartup of IExternalApplication, you don't need UIApplication beyond that point i.e. you don't need it from the event handler.

0 Likes
Message 18 of 20

AGGilliam
Collaborator
Collaborator

Oh! I'm sorry, I see what you're saying now (still waking up). That's currently how I have the ExternalCommand (PracticeMenu) set up: a NamedMethod that grabs UIApplication (it could use Document as that's the only purpose for UIApplication anyhow), and the usual Execute method that then passes the UIApplication into the NamedMethod.

 

The Application registers to the Event on Startup and the Event is supposed to call the NamedMethod. However, the Event never calls this method. Would it have something to do with them being in separate projects? Currently I just have PracticeMenu added as a reference. That was my understanding of the error I mentioned but I'm still looking into it.

 

P.S. Thank you so much for your patience, I really do appreciate it.

0 Likes
Message 19 of 20

AGGilliam
Collaborator
Collaborator

Just moved everything to be in the same project and it works just fine... Thank you so much for your help, I guess I don't fully understand how that project structure works quite yet.

0 Likes
Message 20 of 20

RPTHOMAS108
Mentor
Mentor
Accepted solution

The IExternalApplication interface is used for creating the ribbon buttons etc. and as part of that you give the assembly file location and class of the IExternalCommand for each button during that execution. This means the IExternalCommand can be in the same assembly or a different assembly to IExternalApplication.

 

Events such as DocumentCreated are generally registered during OnStartup so usually have to be created in the assembly with class implementation of IExternalApplication. They can then call methods from other assemblies to handle those events via those assemblies being referenced in the assembly with class implementation of IExternalApplication.

 

However if you've decided to separate the assemblies for IExternalApplication and IExternalCommand (referencing one from the other for the handling of events) then you've decided to deal with all the issues associated with resolving assembly locations. The location of Revit being where things are initially looked for not the location of your assembly doing the looking. To avoid these complications I'd put everything in the one assembly if you can and leave the resolving of assemblies to things you can't avoid such as third party assemblies. 

 

There are many ways of doing things an infinite number of possibilities but start with the well document approaches and then see how you can adapt them.