Can I have multiple commands in a single class?

Can I have multiple commands in a single class?

Anonymous
Not applicable
1,750 Views
10 Replies
Message 1 of 11

Can I have multiple commands in a single class?

Anonymous
Not applicable

Hi!

 

I'm still new to Autodesk plugins and since I didn't find an answer to my question I wanted to know if I could have 2 or more external commands in a single class?

 

I'm trying to connect Revit and SAP PLM and my goal is to create commands for Material upload, download and update. Since I'm more of a Java person I'm used to creating a class and class/object related methods in that class. I guess what I really want to know is that if I can use class methods as commands? Or should I just create multiple classes in a single .cs file and make each class implement IExternalCommand?

 

If I didn't phrase my question well enough try to be understanding because English is not my first language. Also if you have any questions about what I'm talking here don't hesitate to ask them in the comments.

0 Likes
1,751 Views
10 Replies
Replies (10)
Message 2 of 11

ollikat
Collaborator
Collaborator

Hi

 

Briefly, You cannot represent commands with methods within a single class.

 

But actually you don't need to implement IExternalCommand interface over and over again either. I would encourage you to investigate an approach where you have a base class that implements IExternalCommand. Within the Excute() method of this base class, you would call some (of your own made) virtual methods which are overriden in the deriving classes. The behaviour of certain command depends from the implementation of these methods.

 

So for example something like follows:

class BaseCommand : IExternal command
{
  public virtual Result Execute(...)
  {
    this.DoSomething();
  }
  
  protected abstract bool DoSomething();
}

class Upload : BaseCommand
{
  protected override bool DoSomething()
  {
    // Uploading stuff...
  }
}

class Download : BaseCommand
{
  protected override bool DoSomething()
  {
    // Downloading stuff...
  }
}

 

This is something similar what is also called as a "Template method". See more from Template method pattern in wiki.

Message 3 of 11

Anonymous
Not applicable

That's about the same conclusion I arrived on. Thanks for your input.

0 Likes
Message 4 of 11

MiguelVJC82W
Enthusiast
Enthusiast

I keep getting the error not all code paths return a value.

 

Also isn't the "this.xxx" only meant for Macros?

 

And shouldn't it be an abstract class if it contains an abstract bool?

0 Likes
Message 5 of 11

ollikat
Collaborator
Collaborator
- The first one is simply a generic error from the compiler and tries to tell you that with some conditions (if / else) the code execution never gets to any return statement although function should return something
- using "this" in front of member- variable/property/method is a standard C++/C# syntax, not to do especially with macros
- At least C# doesn't force you to use "abstract" in front of class, but it is probably recommended to have it explicitly.
Message 6 of 11

MiguelVJC82W
Enthusiast
Enthusiast

I still cant seem to get the code to compile without errors

 

using Autodesk.Revit.UI;
using Autodesk.Revit.DB;
using System;
using Autodesk.Revit.Attributes;

namespace Blank
{
    [Transaction(TransactionMode.Manual)]
    [Regeneration(RegenerationOption.Manual)]


     abstract class CmdCombo : IExternalCommand
      {
           public virtual Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
           {
             DoSomething();

              return Result.Succeeded;
           }

         protected abstract bool DoSomething();
       }

 

     class Upload : CmdCombo
       {
           protected override bool DoSomething()
             {
             //Uploading stuff...

               UIApplication uiapp = commandData.Application;

              // Built-in Revit commands are listed in the
             // PostableCommand enumeration

              RevitCommandId id_built_in
               = RevitCommandId.LookupPostableCommandId(
              PostableCommand.ExportCADFormatsDXF);

              uiapp.PostCommand(id_built_in);
             }
        }

 

        class Download : CmdCombo
         {
            protected override bool DoSomething()
                   {
                   // Downloading stuff...
                  Autodesk.AutoCAD.Interop.AcadApplication a = new Autodesk.AutoCAD.Interop.AcadApplication();

                   a.Visible = true;

                   Autodesk.AutoCAD.Interop.AcadDocument doc
                  = a.Documents.Application.ActiveDocument;

                  double[] stpoint = new double[3];
                  double[] enpoint = new double[3];
                 stpoint[0] = 5;
                 stpoint[1] = 5;
                 stpoint[2] = 0;
                 enpoint[0] = 12;
                  enpoint[1] = 3;
                   enpoint[2] = 0;

                 doc.ModelSpace.AddLine(stpoint, enpoint);

                   doc.SaveAs("C:/tmp/testline.dwg");

                  a.Quit();
                   }
           }

}

 

0 Likes
Message 7 of 11

mhannonQ65N2
Collaborator
Collaborator

The DoSomething method doesn't have a commandData parameter. You need to modify the abstract method definition and the definitions of the overrides to add that parameter and pass that parameter to where you call it in the Execute method.

Message 8 of 11

MiguelVJC82W
Enthusiast
Enthusiast

Do you mean by adding it in between the brackets like so? I've gotten rid of the compiling error with CommandData for the Upload Class but It's still saying not all paths return a value though. 

 

using Autodesk.Revit.UI;
using Autodesk.Revit.DB;
using System;
using Autodesk.Revit.Attributes;

namespace Blank
{
    [Transaction(TransactionMode.Manual)]
    [Regeneration(RegenerationOption.Manual)]


     abstract class CmdCombo : IExternalCommand
      {
           public virtual Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
           {
             DoSomething(commandData);

              return Result.Succeeded;
           }

         protected abstract bool DoSomething(ExternalCommandData commandData);
       }

 

     class Upload : CmdCombo
       {
           protected override bool DoSomething(ExternalCommandData commandData)
             {
             //Uploading stuff...

               UIApplication uiapp = commandData.Application;

              // Built-in Revit commands are listed in the
             // PostableCommand enumeration

              RevitCommandId id_built_in
               = RevitCommandId.LookupPostableCommandId(
              PostableCommand.ExportCADFormatsDXF);

              uiapp.PostCommand(id_built_in);
             }
        }

 

        class Download : CmdCombo
         {
            protected override bool DoSomething(ExternalCommandData commandData)
                   {
                   // Downloading stuff...
                  Autodesk.AutoCAD.Interop.AcadApplication a = new Autodesk.AutoCAD.Interop.AcadApplication();

                   a.Visible = true;

                   Autodesk.AutoCAD.Interop.AcadDocument doc
                  = a.Documents.Application.ActiveDocument;

                  double[] stpoint = new double[3];
                  double[] enpoint = new double[3];
                 stpoint[0] = 5;
                 stpoint[1] = 5;
                 stpoint[2] = 0;
                 enpoint[0] = 12;
                  enpoint[1] = 3;
                   enpoint[2] = 0;

                 doc.ModelSpace.AddLine(stpoint, enpoint);

                   doc.SaveAs("C:/tmp/testline.dwg");

                  a.Quit();
                   }
           }

}

0 Likes
Message 9 of 11

mhannonQ65N2
Collaborator
Collaborator

You need to add `return true;` to the end of each of your DoSomething methods.

0 Likes
Message 10 of 11

MiguelVJC82W
Enthusiast
Enthusiast

Ok I get it to compile now. Everything builds correctly but I'm getting an error when I try to launch the command from my Custom Button within Revit. 

 

"Revit cannot run the external command "Combo". Contact the ...

 

System.MissingMethodException 

 

Constructor on Type 'Bank.Combo' not found "

0 Likes
Message 11 of 11

ollikat
Collaborator
Collaborator

The following...

"Bank.Combo"

Seems to have multiple typos / differences when compared to code above:

Bank"-> Blank
Combo -> CmdCombo"

0 Likes