1

Can anybody tell me how (if it is possible) to implement a class that I've already written pushing a button in a form that is showed when clicking a button in a Revit Addin Ribbon? Attached is the link to the image of what I've achieved so far.

I'm using C# language inside Visual Studio implementing ExternalApplication class.

Thanks

            namespace PEASA_TOOLS_2021
            {
                public class PEASA_TOOLS_2021 : IExternalApplication
                {
                    static void AddRibbonPanel(UIControlledApplication application)
                        {
                          //Create panel
                          RibbonPanel ribbonPannel4 = application.CreateRibbonPanel(tabName, "Pruebas");
                          //Button for execute Form.
                          PushButtonData pbFormdata = new 
                          PushButtonData("cmdFormData","Extracción de Data", thisAssemblyPath, "PEASA_TOOLS_2021.DATA_EXTRACTION.DataExtractionButton");
                          PushButton pbForm = ribbonPannel4.AddItem(pbFormdata) as PushButton;
                          BitmapImage pruebasImage = new BitmapImage(new Uri("pack://application:,,,/PEASA_TOOLS_2021;component/RECURSOS/PRUEBAS.png"));
                          pbForm.LargeImage = pruebasImage;
                         }
                 }
             }

1

DavidMena
  • 19
  • 6

1 Answers1

1

I have been there, and I know your struggle. here is what I have got to so far and it is working for me, it may not be the best solution, but it is the only one I have.

First, you need to add these Variables to your Form's partial class

[Transaction(TransactionMode.Manual)] 
[Regeneration(RegenerationOption.Manual)]
public partial class Form1 : System.Windows.Forms.Form
{
    private UIApplication uiapp;
    private UIDocument uidoc;
    private Document doc;
    private ExternalCommandData commandData;
    private string message;
    private ElementSet elements;

Then, you will have to edit your form constructor to be like this:

public Form1(ExternalCommandData commandData,ref string message, ElementSet elements)
    {
        InitializeComponent();
        this.commandData = commandData;
        this.elements = elements;
        uiapp = commandData.Application;
        uidoc = uiapp.ActiveUIDocument;
        doc = uidoc.Document;
    }

Then you will create a function under the Form partial class, this function is the one you write your command in:

and it will be like this:

public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
    {
     write your code here
     return Result.Succeeded;
     }

then you just simply call the Execute Function under the Button1_Click function

protected internal  void Button1_Click(object sender, EventArgs e)
    {
        Execute(commandData, ref message, elements);       
    }

Now for the class that calls the Form after pushing the PushButton:

Class DataExtractionButton : IExternalCommand
{
public Result Execute (ExternalCommandData commandData, ref string message, ElementSet elements)
{
        UIApplication uiapp = commandData.Application;
        UIDocument uidoc = uiapp.ActiveUIDocument;
        Application app = uiapp.Application;
        Document doc = uidoc.Document;
        ExternalCommandData revit = commandData;
var window = new Form1(commandData, ref message, elements);
window.ShowDialog();
return Result.Succeeded;
    }
}

that should be the way to do it.

I hope this can help you, it worked with my case.

  • Thank you Mostafa! I'll check it out as soon as I have time and mark your answer as solution if it works for me. – DavidMena Jun 09 '21 at 22:07
  • @DavidMena my pleasure, will be waiting for your confirmation that the solution works, and if there are any problems I will do my best to help. – Mostafa Tarek Yassien Jun 12 '21 at 22:36
  • 1
    Actually I got a problem: It compiled without issues but inside Revit the Button gives this error: "Could not run the add-in because it does not have the Transaction attribute assigned". I'm not doing any transaction within Revit, the only thing I'm trying to do by now is to display a Task Dialog with a Hello World message. I preciate if you can help with this. – DavidMena Jun 14 '21 at 18:52
  • @DavidMena This is a really simple error, Revit API needs to have some attributes assigned before the Class for it to operate even if you will not make a transaction, opening a command is some kind of a transaction it self – Mostafa Tarek Yassien Jun 15 '21 at 19:32
  • you can add the following code before defining the class `[Transaction(TransactionMode.Manual)] [Regeneration(RegenerationOption.Manual)] public partial class Form1 : System.Windows.Forms.Form {` – Mostafa Tarek Yassien Jun 15 '21 at 19:33
  • @DavidMena I have edited the code within the answer - the first sample code- and added these attributes to it. – Mostafa Tarek Yassien Jun 15 '21 at 19:37
  • 1
    Hello Mustafa. Thank you very much! But I'm still getting an error when trying to execute the form inside Revit. It gives me this: "System.MissingMethodException". I'm using this: "PushButtonData pbFormdata = new PushButtonData("cmdFormData","Extracción de Data", thisAssemblyPath, "PEASA_TOOLS_2021.DATA_EXTRACTION.DataExtractionButton");" Where "PEASA_TOOLS_2021.DATA_EXTRACTION.DataExtractionButton" is the route to my Form. What am I missing or doing wrong? :/ – DavidMena Jun 16 '21 at 16:35
  • Can you edit the main question and add the main hierarchy of the code? mainly how your code flows from a point to a point, I don't need the exact source code, just the headlines. – Mostafa Tarek Yassien Jun 17 '21 at 17:26
  • 1
    Ready! There you can see how I created an ExternalApplication, then a AddRibbonPanel, the PushButtpon and "PEASA_TOOLS_2021.DATA_EXTRACTION.DataExtractionButton" is the path of my Form Class. Sorry if my programming language is not the best. I'm an architect navigating strange waters hehe.. – DavidMena Jun 17 '21 at 20:23
  • From what i understood from the code in the question: you have a `PushButton` in the ribbon that calls the `Class` `DataExtractionButton`, now what should happen is the `DataExtractionButton` must implement `IExternalCommand` then inside this class you Should call your form constructor. – Mostafa Tarek Yassien Jun 18 '21 at 14:04
  • After you initialize a new instance of your form, you use `Form.ShowDialog()` – Mostafa Tarek Yassien Jun 18 '21 at 14:05
  • I edited my answer and added a piece of code at the end that should help you open your form correctly. – Mostafa Tarek Yassien Jun 18 '21 at 14:14
  • And if you can also add the code for the class `DataExtractionButton`, that will be great and help us identify the problem. – Mostafa Tarek Yassien Jun 18 '21 at 14:16
  • Thank you for your time Mostafa!. I think I'll do it all again step by step. Because actually DataExtractionButton is my Form Class :/ So, I think I have a real mess with my code. Let me try again and I'll give my results. Cheers! – DavidMena Jun 18 '21 at 17:42
  • 1
    Good Luck, and as a small hint, the code should be divided into parts ( the First Part: is the `Class` that implements `IExternalApplication` and adds the `Ribbon` `PushButton`, the second `Class` will implement `IExternal Command` which you'll use to open your form - notice that this class will be the one called by the `PushButton` in the `Ribbon`, the Third part is your Form which you can divide as explained in the answer). Good Luck and will be waiting for your feedback0 – Mostafa Tarek Yassien Jun 18 '21 at 22:57
  • 1
    Hello Mostafa! Yes, finally I put some order in my code and precisely the order of the parts that you mentioned worked at last. Thank you very much for your help! I'll mark your answer as solution :) – DavidMena Jun 21 '21 at 15:26