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: 

Event to run a IExternalCommand

17 REPLIES 17
SOLVED
Reply
Message 1 of 18
miketurpin_innovatingfutures
4907 Views, 17 Replies

Event to run a IExternalCommand

Hi All,

Wondering if you can assist with an issue i'm having that i just cant seem to solve.

Would be nice just to know if what i am trying to do is possible or not.

 

I have been playing around with the events within an ExternalApplication and i have got these to work fine (i.e. using the DocumentCreated event to flash up a "HelloWorld" task dialog when a document is created)

I have also written a few basic ExternalCommands with buttons on the addin ribbon that work fine.

 

My issue is..... how do i get an event to fire off an ExternalCommand instead of having to use a button?

 

I am basically trying to get the event to trigger off the command and make some changes to the document and so i need the current document which i dont believe i can access within the ExternalApplication.

 

I have read all of the event samples in the SDK but still cant work it out and im sure it should be really simple.

 

Thanks

17 REPLIES 17
Message 2 of 18

Hi Mike,

I'm pretty sure that's what PostCommand is for: http://www.revitapidocs.com/2017/b0df464d-1733-ea9e-ac40-399fa9c9a037.htm

 

Give it a test and report back!

 

-Matt


Cheers,

-Matt
_______________________________________________________________________________
Marking a post as a 'solution' helps the community. Giving a post 'Kudos' is as good as saying thanks. Why not do both?
Message 3 of 18

matthew.taylors response is correct and valid for all buttons in Revit (almost), but if you created the externalcommand, you can just create an instance of the class and run the execute-method. Thats even more simple.

Erik Eriksson
White
Message 4 of 18

Hi Erik,

I am trying to do what you suggest "you can just create an instance of the class and run the execute-method. Thats even more simple" but thats where i am getting stuck.

In my externalapp i am trying to execute the command using 

                Command cmd = new Command();
                cmd.Execute();

however that understandably gives me the error
Error CS7036 There is no argument given that corresponds to the required formal parameter 'commandData' of 'Command.Execute(ExternalCommandData, ref string, ElementSet)'

 

Could you please expand on how i would use the execute method from an IExternalApplication?

 

Thanks

Mike

Message 5 of 18

Mike, you need a handler for the event, and the IExternaCommand.Execute method does not have the same parameters.

You can fake the the parameters (commanddata, etc) using reflection and a adapter. but that seems awkward.

My suggestion is just to implement a method to handle the event you are after. After all, the sender is usually the application.

Message 6 of 18

Hi Mike,

I think @erikeriksson5686 was suggesting that if you wrote the external command, you could call the same function that you call in the external command.

 

PostCommand would be the best fit, if you can apply it. Why don't you tell us exactly what you're trying to do?

 

-Matt


Cheers,

-Matt
_______________________________________________________________________________
Marking a post as a 'solution' helps the community. Giving a post 'Kudos' is as good as saying thanks. Why not do both?
Message 7 of 18

Hi Mike,


maybe I read your message a bit fast. I missed the fact that you were in a IExternalApplication context, I automatically thought you were in IExternalCommand, then you could jus pass the ExternalCommandData object forward.
But to solve your problem you could just refactor your code a bit to get an overload for the Execute()-method that takes a UIApplication object. The Execute-method in the IExternalCommand interface seems abit obsolete anyway.

Also, another thing to bear in mind here is that you should subscribe to the ApplicationInitialized event if you are to do anything with documents.

Here is an example code snippet:

 

 

 

  public class Command : IExternalCommand
    {
        public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
        {

           return Execute(commandData.Application);


        }
        public Result Execute(UIApplication uiapp)
        {
            //Do all sorts of shiny stuff with your command. 

            return Result.Succeeded;

        }
    }
    public class RevitStartup : IExternalApplication
    {
        public Result OnShutdown(UIControlledApplication application)
        {
            return Result.Succeeded;
        }

        public Result OnStartup(UIControlledApplication application)
        {
            application.ControlledApplication.ApplicationInitialized += ControlledApplication_ApplicationInitialized;

            return Result.Succeeded;
        }

        private void ControlledApplication_ApplicationInitialized(object sender, Autodesk.Revit.DB.Events.ApplicationInitializedEventArgs e)
        {
            var command = new Command();

            //I never remember if the sender is Application or UIApplication
            if (sender is UIApplication)
                command.Execute(sender as UIApplication);
            else
                command.Execute(new UIApplication(sender as Application));



        }
    }

This will also work even if you dont register a button.

And to Finish off, like Mike said: tell us why you want to achieve and maybe we can find an even easier way of doing it 😃

 

/Erik

 

Erik Eriksson
White
Message 8 of 18

Hi All,

 

Many many thanks for all your replies.

Although none of them answered the question they did help me realise that what I was trying to do was the wrong way to approach things and that I actually didn't need the ExternalCommand.

 

My reason for thinking I needed the external command was trying to get the "Document" but thanks to Eriks post I found I could get the UIApplication from the sender and that this then let me access the document. So now I am able to run all of my code in the external application!

 

Again many thanks for all your assistance.

 

To finalise my end result was to register a dialog event on startup and shutdown and then:

 

        public void application_new(object sender, DialogBoxShowingEventArgs args)
        {
            if (args.DialogId == "Dialog_Revit_NewProject")
            {
                UIApplication uiapp = sender as UIApplication;
                Application app = uiapp.Application;

//etc etc etc
Message 9 of 18

Dear Mike, Matt, Erik and Gonçalo,

 

Thank you very much for raising this issue and helping to solve it.

 

I think this discussion is fruitful, illuminating, and well worth preserving, so I published an edited version on the blog:

 

http://thebuildingcoder.typepad.com/blog/2016/11/using-other-events-to-execute-add-in-code.html

 

I hope that you agree with this and like it.

 

Please let me know if you would like me to modify, add or correct anything whatsoever.

 

Thank you!

 

Cheers,

 

Jeremy



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

Message 10 of 18

Hey guys,

 

Please note another cool approach described by David Echols to load and execute assembly code on the fly in an Idling event handler by subscribing to that event in the application OnStartup method: "I have used the following code in the last four versions of Revit for overnight batch processing of PDF and DWG exports and sheet lists across multiple workstations. This is not the most elegant way to do this, but it does show how I load the assembly on the fly and execute the command that does the processing...":

 

http://thebuildingcoder.typepad.com/blog/2016/11/using-other-events-to-execute-add-in-code.html#2

 

Cheers,

 

Jeremy



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

Message 11 of 18

so i used that part of the code and it worked out, however in the part where you comment (enter your code here) one can not use "

UIDocument uidoc = commandData.Application.ActiveUIDocument;

 

                Document doc = uidoc.Document;" since CommandData is not referenced.

can you suggest any solution?

Message 12 of 18
maroun.waked
in reply to: jeremytammik

hey Jeremy,

 

I am trying to reach you out.

i am writing a code that i would like to share with you and need a bit of help in it.

i would appreciate your help and reply

Message 13 of 18
jeremytammik
in reply to: maroun.waked

Hi.

 

I am glad to reply.

 

Please read and use the existing samples.

 

Then your problem will go away.

 

Do not fight against the system, go with the flow. Make life easy for yourself.

 

Good luck and have fun, 

  

Jeremy

  



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

Message 14 of 18
maroun.waked
in reply to: jeremytammik

Thank you very much for your reply.

so i am working on something that needs to run an external command in a Revit application.

i guess the problem is that my command code is not running and i don't know why.

 

namespace nocom
{
[TransactionAttribute(TransactionMode.Manual)]
public class DoorsCode : IExternalCommand
{
public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
{
return Execute(commandData.Application);
}

public Result Execute(UIApplication app)
{

Document doc = app.ActiveUIDocument.Document;
FilteredElementCollector collector = new FilteredElementCollector(doc);

ElementCategoryFilter filter = new ElementCategoryFilter(BuiltInCategory.OST_Doors);

IList<Element> doors = collector.WherePasses(filter).WhereElementIsNotElementType().ToElements();

TaskDialog.Show("Doors", doors.Count + "doors found");
return Result.Succeeded;

}
}
public class nocom : IExternalApplication
{

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

public Result OnStartup(UIControlledApplication app)
{
RibbonPanel ribbonPanel = app.CreateRibbonPanel("ribbon");
TextBoxData textData = new TextBoxData("Text Box");

TextBox tBox = ribbonPanel.AddItem(textData) as TextBox;
tBox.PromptText = "Enter A Question";
tBox.ToolTip = "Ask me a question";

tBox.EnterPressed += new EventHandler<Autodesk.Revit.UI.Events.TextBoxEnterPressedEventArgs>(ProcessText);

return Result.Succeeded;
}

void ProcessText(object sender, Autodesk.Revit.UI.Events.TextBoxEnterPressedEventArgs args)
{

TextBox tBox = sender as TextBox;
string strText = tBox.Value as string;

if (strText == ("how many doors"))
{

var DoorsCode = new DoorsCode();
if (sender is UIApplication)
DoorsCode.Execute(sender as UIApplication);
else
DoorsCode.Execute(new UIApplication(sender as Application));


}

}


}

}

 

Message 15 of 18
jeremytammik
in reply to: maroun.waked

Start with a working sample, such as the SDK modeless event samples, e.g., ModelessDialog/ModelessForm_ExternalEvent.

 



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

Message 16 of 18

Hey Guys, 

 

This post is a bit old, but I'm trying to implement the code.  It goes well, until in this part:

private void ControlledApplication_ApplicationInitialized(object sender, Autodesk.Revit.DB.Events.ApplicationInitializedEventArgs e)
        {
            var command = new Command();
            command.Execute(sender as UIApplication);
        }

 

The sender is null.  So the application is not passed to the command.Execute() method.  And Revit crashes. What am I doing wrong? 

Message 17 of 18

Dear Lucas,

    

This may not be a good idea. This thread and discussion is a bit weird. There may well be a better way.

  

Actually, I will repeat my advice from above for you as well:

  

Please read and use the existing samples. Then your problem will go away. Do not fight against the system, go with the flow. Make life easy for yourself. Start with a working sample, such as the SDK modeless event samples, e.g., ModelessDialog/ModelessForm_ExternalEvent.

  

Cheers

  

Jeremy

  

Jeremy Tammik, Developer Advocacy and Support, The Building Coder, Autodesk Developer Network, ADN Open
Message 18 of 18
ricaun
in reply to: lucas.dejongPTZ3P

I am pretty sure the ApplicationInitialized sender is not UIApplication.

 

Here are some Revit API references to confirm that the sender is ControlledApplication: https://help.autodesk.com/view/RVT/2022/ENU/?guid=Revit_API_Revit_API_Developers_Guide_Advanced_Topi...

 

Usually, a better approach should be to use External Events, intending of trying to execute something directly in the Revit Event: https://help.autodesk.com/view/RVT/2022/ENU/?guid=Revit_API_Revit_API_Developers_Guide_Advanced_Topi...

 

 

Luiz Henrique Cassettari

ricaun.com - Revit API Developer

AppLoader EasyConduit WireInConduit ConduitMaterial CircuitName ElectricalUtils

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