Pass Variable from Ribbon to Variable

Pass Variable from Ribbon to Variable

aguterHFKHP
Contributor Contributor
627 Views
9 Replies
Message 1 of 10

Pass Variable from Ribbon to Variable

aguterHFKHP
Contributor
Contributor

I found this question here, https://forums.autodesk.com/t5/revit-api-forum/pass-value-from-ribbon-pushbutton-to-function/m-p/68... ,but I must be newer to the Revit api than this person, I am still lost.

 

I want to pass an int from a revit ribbon button selection in my app.cs file, to my main command.cs file. Sample view of the ribbon:

 

image editor.png

I want to pass an int = 3 if the user selected bend #3 and and pass int 4 if the user selects "bend #4". Is there an easy way to do this with the app.cs file? Or should I just make a whole bunch of differing Command Files that changes the value of the int? It seems like the more elegant way to handle this is to pass the variable from the app.cs file but I am not sure if this is possible. Here is the bit of code that relies on the single value in the command.cs file:

 

 

 

        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;

            // Access current selection
            Selection sel = uidoc.Selection;
            // Initialize a list of points
            IList<XYZ> selectedPoints = new List<XYZ>();

            // Hitting Escape will exit out of the loop for selecting points
            bool value = true;
            while (value)
            {
                try
                {
                    XYZ point1 = uidoc.Selection.PickPoint("Select a point");
                    selectedPoints.Add(point1);
                }
                catch (Exception exp)
                {
                    value = false;
                }
            }
            //THIS VALUE NEEDS TO BE UPDATED BASED ON USER SELECTED BTN
            int bar_size_chosen = 4;
            //crate line function creates the first main curve, from which all other lines will be created

 

 

 

Thank you for your help!

0 Likes
Accepted solutions (1)
628 Views
9 Replies
Replies (9)
Message 2 of 10

AGGilliam
Collaborator
Collaborator

Is the button supposed to execute some other code that references that int value or is it just setting that value for another button to reference later?

 

For the first scenario, you could create a method for your code that requires an integer as an input parameter and both of the buttons just execute that method while passing in the specific integer for each button.

 

For the second scenario you'll just need to find a place to store that value for reference later. That could be a global parameter, a project info parameter, or you could use Extensible Storage. There are probably other options I'm missing as well.

0 Likes
Message 3 of 10

Kennan.Chen
Advocate
Advocate

You need to create the Ribbon UI with lower level Ribbon APIs defined in AdWindows.dll which allows you to bind Command and CommandParameter(pass the integer 3 here) to clickable UI elements. In your command, use Revit external event to run Revit API code with the command parameter.

 

The documentation for the lower level Ribbon API is here

0 Likes
Message 4 of 10

aguterHFKHP
Contributor
Contributor

@AGGilliam wrote:

Is the button supposed to execute some other code that references that int value or is it just setting that value for another button to reference later?


It is the first one you posed, the button is supposed to execute some other code that references the int value.

 


@AGGilliam wrote:

For the first scenario, you could create a method for your code that requires an integer as an input parameter and both of the buttons just execute that method while passing in the specific integer for each button.


How can I pass the specific integer that I want though? I am not sure how to get the integer input parameter in the method you mention to be related to the button.

 

Hopefully that makes sense.

0 Likes
Message 5 of 10

aguterHFKHP
Contributor
Contributor

Thanks for info, I will have to do some reading on this. I am not familiar with the command and commandparameter.

0 Likes
Message 6 of 10

AGGilliam
Collaborator
Collaborator
Accepted solution

Take all of the code from your Execute method and move it to another method in a separate class you create, like so:

public class ClassName
{
   public static void MethodName(int number)
   {
      // insert code here
   }
}

Then, since each button should be connected to its own class and Execute method (and if not, create a separate one for each), you can reference your custom method and enter a 3 for the first button and a 4 for the other, like so:

public Result Execute(ExternalCommandData data, ref string message, ElementSet elements)
{
   ClassName.MethodName(3);
   return Result.Succeeded;
}

This is pretty simplified, but that's the concept anyway.

0 Likes
Message 7 of 10

Kennan.Chen
Advocate
Advocate

I created a small project to show how to do this.

0 Likes
Message 8 of 10

aguterHFKHP
Contributor
Contributor

Thank you for all the help. I have solved this with classes and some sloppy code.

 

Kannan, I will have to find some more time research your solution, it looks very slick, just have to find the time to dedicate to it.

 

I did a quick write up on my blog and my code can be found on my github if you want to hop in and review. Thanks again!

 

https://re-tug.com/post/revit-rebar-bender-new-and-improved/11

0 Likes
Message 9 of 10

Kennan.Chen
Advocate
Advocate

I went through your code and found something that can be optimized.

 

I noticed that you created a bunch of commands starting with "nu". The logic in those commands are almost the same. The only difference is the value of "bar_size_chosen".

 

I believe the code can be well reused by involving a base class.

 

[Transaction(TransactionMode.Manual)]
public abstract class BaseNUCommand : IExternalCommand
{
    protected abstract int GetBarSize();
    // here starts all the calling of functions and stuff
    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;

        // Access current selection
        Selection sel = uidoc.Selection;
        // Initialize a list of points
        IList<XYZ> selectedPoints = new List<XYZ>();

        // Hitting Escape will exit out of the loop for selecting points
        bool value = true;
        while (value)
        {
            try
            {
                XYZ point1 = uidoc.Selection.PickPoint("Select a point");
                selectedPoints.Add(point1);
            }
            catch (Exception exp)
            {
                value = false;
            }
        }


        int bar_size_chosen = this.GetBarSize();
        //crate line function creates the first main curve, from which all other lines will be created

        List<Double> b_offsets = global_rebar.createOffsetrebar(selectedPoints, bar_size_chosen);
        List<Curve> mainCurve = global_rebar.createLine(selectedPoints, b_offsets, bar_size_chosen);

        CurveLoop rebarLoop = new CurveLoop();
        List<CurveLoop> profileLoops = new List<CurveLoop>();

        foreach (Curve e in mainCurve)
        {
            rebarLoop.Append(e);
        }
        profileLoops.Add(rebarLoop);

        // find solid fill type in our revit list
        FilteredElementCollector fillRegionTypes = new FilteredElementCollector(doc).OfClass(typeof(FilledRegionType));
        var patterns = new FilteredElementCollector(doc).OfClass(typeof(FilledRegionType)).FirstElement();
        foreach (Element elem in fillRegionTypes)
        {
            if (elem.Name == "Solid Black")
            {
                patterns = elem;
            }
        }
        View view = doc.ActiveView;

        using (Transaction tx = new Transaction(doc))
        {
            tx.Start("Transaction Name");
            FilledRegion filledRegion = FilledRegion.Create(doc, patterns.Id, view.Id, profileLoops);
            tx.Commit();
        }
        return Result.Succeeded;
    }
}

And one of your command can be like this:

public class nu18 : BaseNUCommand
{
	protected override int GetBarSize()
	{
		return 18;
	}
}

 

0 Likes
Message 10 of 10

Kennan.Chen
Advocate
Advocate

Or, you can also reuse the code by using combination rather than inheritance.

public class RebarManager
{
	// I don't know exactly what you are doing. Just name it "CreateRebar"
	public static void CreateRebar(UIDocument uidoc, int barSize)
	{
		Document doc = uidoc.Document;
        // Access current selection
        Selection sel = uidoc.Selection;
        // Initialize a list of points
        IList<XYZ> selectedPoints = new List<XYZ>();

        // Hitting Escape will exit out of the loop for selecting points
        bool value = true;
        while (value)
        {
            try
            {
                XYZ point1 = uidoc.Selection.PickPoint("Select a point");
                selectedPoints.Add(point1);
            }
            catch (Exception exp)
            {
                value = false;
            }
        }

        //crate line function creates the first main curve, from which all other lines will be created

        List<Double> b_offsets = global_rebar.createOffsetrebar(selectedPoints, barSize);
        List<Curve> mainCurve = global_rebar.createLine(selectedPoints, b_offsets, barSize);

        CurveLoop rebarLoop = new CurveLoop();
        List<CurveLoop> profileLoops = new List<CurveLoop>();

        foreach (Curve e in mainCurve)
        {
            rebarLoop.Append(e);
        }
        profileLoops.Add(rebarLoop);

        // find solid fill type in our revit list
        FilteredElementCollector fillRegionTypes = new FilteredElementCollector(doc).OfClass(typeof(FilledRegionType));
        var patterns = new FilteredElementCollector(doc).OfClass(typeof(FilledRegionType)).FirstElement();
        foreach (Element elem in fillRegionTypes)
        {
            if (elem.Name == "Solid Black")
            {
                patterns = elem;
            }
        }
        View view = doc.ActiveView;

        using (Transaction tx = new Transaction(doc))
        {
            tx.Start("Transaction Name");
            FilledRegion filledRegion = FilledRegion.Create(doc, patterns.Id, view.Id, profileLoops);
            tx.Commit();
        }
	}
}

 

And your command could be like this:

[Transaction(TransactionMode.Manual)]
public class nu18 : IExternalCommand
{
    public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
    {
		RebarManager.CreateRebar(commandData.Application.ActiveUIDocument, 18);
		return Result.Succeeded;
	}
}
0 Likes