Calling a C# routine from another

Calling a C# routine from another

Kevin.Bell
Advisor Advisor
2,363 Views
11 Replies
Message 1 of 12

Calling a C# routine from another

Kevin.Bell
Advisor
Advisor

Hi,

 

I have written some code which creates a new Element Filter for Revit - I'm very happy with the result. Currently, the routine is called by clicking on a toolbar I created - all works well.

 

 

But I've now cross some code (with the help of this forum!) which allows the user to replace an existing Revit toolbar button with a custom routine and I'd like to do this.

 

I've got it working by duplicating the code, but really I'd like to start the original routine, but I'm unsure how to run the code.

 

The original routine starts with this:

 

namespace DetailedFilter
{

    [Transaction(TransactionMode.Manual)]
    public class Command : IExternalCommand
    {
        public Result Execute(
          ExternalCommandData commandData,
          ref string message,
          ElementSet elements)
        {
            UIApplication uiapp = commandData.Application;
            UIDocument uidoc = uiapp.ActiveUIDocument;
            Autodesk.Revit.ApplicationServices.Application app = uiapp.Application;
            Document doc = uidoc.Document;

etc etc

So to run this routine would I type:

 

DetailedFilter.command.Execute(??, ??, ??)

 

I'm unsure what to put in the ??s...

 

I'd appreciate some pointers - thanks.

0 Likes
Accepted solutions (1)
2,364 Views
11 Replies
Replies (11)
Message 2 of 12

MarryTookMyCoffe
Collaborator
Collaborator

i'm not sure what you what to do, but runing one Execute from another sounds like bad ide.
You schould use this class for buttons.

 

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

Kevin.Bell
Advisor
Advisor
Well I guess it's not another code I'm calling it from, rather it's another part of the overall app...
0 Likes
Message 4 of 12

BardiaJahan
Advocate
Advocate

 

I am a little confused. You could not call execute method unless you create a new instance of that class. But I guess what you would want to have is a static method returning the object you would want to use.

 

 

0 Likes
Message 5 of 12

Anonymous
Not applicable
Accepted solution

Hello Kevin,

 

If I understood correctly you want to activate that C# routine when you press that button right?

 

In your routine, when you created (or reused) a ribbon panel, you could do something like this:

 

 

 // Create Panel
RibbonPanel ribbonPanel = application.CreateRibbonPanel("NameOfTheRibbon");

// Create a push button to trigger a command add it to the ribbon panel string thisAssemblyPath = Assembly.GetExecutingAssembly().Location;
//Assign a function to that button PushButtonData buttonData = new PushButtonData("cmdMenu", "NameOfTheButton", thisAssemblyPath, "DetailedFilter.Command");

//Add the button to the ribbon
PushButton pushButton = ribbonPanel.AddItem(buttonData) as PushButton;

 

 

// Parameters of PushButtonData:
// name: The internal name of the new button.
// text: The user visible text seen on the new button.
// assemblyName: The assembly path of the button.
// className: The name of the class containing the implementation for the command.

 

So, in order to call your routine, in the 4th field of the push button data (the class name), you need to paste the full path for your code, which I've assumed as DetailedFilter.Command. It should run your code by doing that.

 

Cheers

Ruben

0 Likes
Message 6 of 12

Kevin.Bell
Advisor
Advisor

Sorry all, I've obviously made a mess of explaining the issue. I'll try again.

 

So, I've written a load of routines for Revit which do various things and all are accessible via a ribbon.

 

The ribbon calls the routines, this is an example of the Detail Element Filter button code.

 

            PushButtonData p4b4Data = new PushButtonData(
                "cmdDetailFilter",
                "Detail" + System.Environment.NewLine + " Element Filter",
                thisAssemblyPath,
                "DetailedFilter.Command");

            PushButton p4b4 = ribbonPanel4.AddItem(p4b4Data) as PushButton;
            p4b4.ToolTip = "Allows detailed selection filtering.";

            BitmapImage p4b4Image = new BitmapImage(new Uri("pack://application:,,,/TPBRevitRibbon2017;component/Commands/DetailedFilter/DetailFilter_Icon.png"));

            p4b4.LargeImage = p4b4Image;

All of this works well.

 

I found that I can replace a Revit command on the standard Revit ribbon, from this post:

 

https://forums.autodesk.com/t5/revit-api-forum/replacing-a-revit-command/m-p/7783097#M28698

 

So I'd like to replace the standard Revit Element filter command with my version - Detail Element Filter - which the above ribbon button code calls.

 

To replace a command I need to add a call into this event:

 

void binding_Executed(object sender, Autodesk.Revit.UI.Events.ExecutedEventArgs e)
{

}

 

Now rather than duplicating the Detail Element Filter code within binding_Executed, I'd rather simply call the code for the original routine.

 

This is the start of the original routine:

 

namespace DetailedFilter
{

    [Transaction(TransactionMode.Manual)]
    public class Command : IExternalCommand
    {
        public Result Execute(
          ExternalCommandData commandData,
          ref string message,
          ElementSet elements)
        {
            UIApplication uiapp = commandData.Application;
            UIDocument uidoc = uiapp.ActiveUIDocument;
            Autodesk.Revit.ApplicationServices.Application app = uiapp.Application;
            Document doc = uidoc.Document;
 etc

So I'm thinking I can call the routine thus:

 

void binding_Executed(object sender, Autodesk.Revit.UI.Events.ExecutedEventArgs e)
{
DetailedFilter.Command.Execute();
}

But that doesn't work, and I'm not sure whats required.

 

Just to be clear, the Detail Element Filter, the ribbon bar and the replacement command are all compiled into one DLL and so it doesn't need to call anything externally.

 

I hope that all makes sense...!

 

Thanks for your help.

 

 

 

0 Likes
Message 7 of 12

BardiaJahan
Advocate
Advocate

You need to have an instance of the Command class before calling the execute method. Also, you need to pass the required arguments. So you may want to register your handler to BeforeExecuted event.

 

Command command = new Command();
command.Execute(commandData, ref message, elements);

Although I would not do that. Instead, create another method - even possibly a static method - in Command class by copying what Execute method does. you could call that method from Execute and also Executed event handler.

0 Likes
Message 8 of 12

Kevin.Bell
Advisor
Advisor

Ok, thanks.

 

But I'm unsure what pass for 

commandData, ref message, elements

Regarding your suggestion about creating another method, can you point me to somewhere which can give some pointers on this, I need to so some reading on this.

 

Thanks for your help. 

0 Likes
Message 9 of 12

BardiaJahan
Advocate
Advocate

I am not sure about what to pass if you want to call execute but I am suggesting to create another method - ExecCommand - method in your Command class and call it from Execute method and also Executed event handler. You still need to create an instance of Command Class in the event handler though.

 

namespace DetailedFilter
{
    [Transaction(TransactionMode.Manual)]
    public class Command : IExternalCommand
    {
        public Result ExecCommand(Document doc)
        {
            Autodesk.Revit.ApplicationServices.Application app = doc.Application;
            
//copy everything from Execute method.... } public Result Execute( ExternalCommandData commandData, ref string message, ElementSet elements) { UIApplication uiapp = commandData.Application; UIDocument uidoc = uiapp.ActiveUIDocument; Autodesk.Revit.ApplicationServices.Application app = uiapp.Application; Document doc = uidoc.Document; return Run(doc); }
0 Likes
Message 10 of 12

Kevin.Bell
Advisor
Advisor

Oh, I see.

 

I was trying to avoid copying the code as that would mean that I have two lumps of code that I would have to maintain, though I have set up something like this and it worked fine.

 

I thought it would be more 'elegant' to call the same code...

 

Cheers.

0 Likes
Message 11 of 12

BardiaJahan
Advocate
Advocate

You wouldn't have two lumps of code. Just one but it would be in ExecCommand method instead of Execute method.

0 Likes
Message 12 of 12

Kevin.Bell
Advisor
Advisor

oh right. I'll try that out.

 

Thanks.

0 Likes