Execute External Command via Button on a Form

Execute External Command via Button on a Form

Anonymous
Not applicable
4,042 Views
12 Replies
Message 1 of 13

Execute External Command via Button on a Form

Anonymous
Not applicable

Hi, I want to modiy the thickness of an object so naturally I need to do it with a Transaction and so on, so I need to do an External Command which I have defined here:

using Autodesk.Revit.Attributes;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using Toolbar.Commands.Base;
using Toolbar.UI;

using Autodesk.Revit;
using Autodesk.Revit.ApplicationServices;
using Application = Autodesk.Revit.ApplicationServices.Application;

namespace Toolbar.Commands
{
    [Autodesk.Revit.Attributes.Transaction(Autodesk.Revit.Attributes.TransactionMode.Manual)]
    class ExternalCommandFloorThickness : ExternalCommandBase, 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;

            InitializeMembers(commandData);
            FloorThickness formFloor = new FloorThickness(revitApplication, revitActiveDocument);

            // Retrieve elements from database
            FilteredElementCollector collector = new FilteredElementCollector(doc).WhereElementIsElementType().OfClass(typeof(FloorType));

            var query = from element in collector
                        where element.Name == "Generic 150mm"
                        select element;

            // Modify document within a transaction
            using (Transaction tx = new Transaction(doc))
            {
                tx.Start("Transaction ModifyFloorThickness");

                double width = UnitUtils.ConvertToInternalUnits(100, DisplayUnitType.DUT_MILLIMETERS);

                foreach (Element e in query)
                {
                    FloorType floorType = e as FloorType;

                    CompoundStructure compoundStructure = floorType.GetCompoundStructure();
                    compoundStructure.SetLayerWidth(0, width);
                    floorType.SetCompoundStructure(compoundStructure);
                }
                tx.Commit();
            }
            return Result.Succeeded;
        }
    }
}

But now the problem is that I want to run/execute this code from the click of a button in a Form. My best idea so far is doing this:

 private void button2_Click(object sender, EventArgs e)
        {
            ExternalCommandFloorThickness extCommFT = new ExternalCommandFloorThickness();
            extCommFT.Execute();
        }

But obviously this doesn't work because I will need to pass the parameters to the .Execute() function, but I cannot pass it a commandData because I'm inside the code of a Form not an External Command and so on.

So any ideas are highly appreciated it! 

Many thanks in advance! 

0 Likes
4,043 Views
12 Replies
Replies (12)
Message 2 of 13

Anonymous
Not applicable

Hi.

You can transfer the code to a separate class, which can be run both from the command and using the button.
Required data (revitApplication, revitActiveDocument) must first be passed to the form when it is created, and the form can pass it on

0 Likes
Message 3 of 13

jeremytammik
Autodesk
Autodesk

The only valid way to implement this scenario is to do so using an external event:

 

https://thebuildingcoder.typepad.com/blog/about-the-author.html#5.28

 



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

Message 4 of 13

Anonymous
Not applicable

Okay, thanks a lot, I just have one question, I tried changing the code to an external event by doing this:

 public class ExternalCommandFloorThickness : IExternalEventHandler
    {
        public Result Execute()
        {

            UIApplication uiapp = ExternalCommandData.Application;
            UIDocument uidoc = uiapp.ActiveUIDocument;
            Application app = uiapp.Application;
            Document doc = uidoc.Document;

but I get the error:

 

in the line: UIApplication uiapp = ExternalCommandData.Application;

0 Likes
Message 5 of 13

Anonymous
Not applicable

I just saw that the screenshot did not attach, so here is the error:

Capture.PNG

"A clas contains reference to Application and View which are needed by external command.

An object reference is required for the non-static field, method, or property 'ExternalCommandData.Application'"

0 Likes
Message 6 of 13

Anonymous
Not applicable

I have a similar problem, but I'm sure @jeremytammik can help all of us! 

0 Likes
Message 7 of 13

lmolina6V6K7
Contributor
Contributor

Hi all,

Same exact problem. Did you guys solve the issue. Would you share the beans please?

Thanks a lot.

0 Likes
Message 8 of 13

lukaskohout
Advocate
Advocate

Well, the easiet way is to execute only the Form:

 

public Autodesk.Revit.UI.Result Execute(ExternalCommandData commandData,
            ref string message, Autodesk.Revit.DB.ElementSet elements)
{
    UIApplication uiapp = commandData.Application;
    using (MainForm form = new MainForm(uiapp))
    {
        form.ShowDialog();
    }
    return Autodesk.Revit.UI.Result.Succeeded;
}

 

 

And then having your code as separate class (e.g. FloorThickness) and caling it in the button click action:

 

private void button2_Click(object sender, EventArgs e)
{
      FloorThickhness ft = new FLoorThickness(uiapp);
      ft.SetThickness; 
}

 

 

You can choose if the form will be modal or modeless.

 

I am using this all the time in my simple addons and it works perfectly. This way you can also have many buttons in the form and each of them can do somehing totally different. Furthermore you can easily pass some parameters from the dialog to your actions (text value, name filter and so on)

 


Hitting Accepted Answer is a Community Contribution from me as well as from you.
======================================================================
Message 9 of 13

J450NP13
Advisor
Advisor

@lukaskohout 

 

Have you fired a a function from a form button?

0 Likes
Message 10 of 13

lukaskohout
Advocate
Advocate

Yes, you should be able to do that.


Hitting Accepted Answer is a Community Contribution from me as well as from you.
======================================================================
0 Likes
Message 11 of 13

J450NP13
Advisor
Advisor

@lukaskohout 

 

Not working for me.

0 Likes
Message 12 of 13

RPTHOMAS108
Mentor
Mentor

If it is modeless it shouldn't work because your add-in has already completed the context before you press a button on the form. For this purpose you should use external events,

 

If it is modal then that is fine because it stops the process from escaping the context, so you can still execute within it.

 

However the question is a bit vague so I'm assuming you want to interact with Revit using the function and not just turn on the food blender in the kitchen.

Message 13 of 13

J450NP13
Advisor
Advisor

@RPTHOMAS108 

 

Im still getting use to the api.  It’s definitely a little different than what I’m use to so I’m doing things that I would normally do and it’s working but hackish....

 

I’m calling a file open dialog to import a json file (if you remember) and it’s working great.  But I wanted to add a custom tab and button.....got that going, but by that button it’s firing the command.  I want it to wait for the file open dialogue to finish its process and be able to cancel if needed.

 

I’ll need to learn the model less vs model so I’m not just turning the food processor on....yes.

 

But, I do have json coming in and am able to generate the models.  😀

0 Likes