Passing Arguments in Revit Ribbon Elements

Passing Arguments in Revit Ribbon Elements

Anonymous
Not applicable
3,651 Views
14 Replies
Message 1 of 15

Passing Arguments in Revit Ribbon Elements

Anonymous
Not applicable

I am currently trying to do two things:

 

1.)  Pass the contents of a Revit Textbox to a class.

2.)  Pass the name of the selected Revit Combobox to a class.

 

Some background.  I have a Ribbon Toolbar DLL that makes several buttons.  I have a second DLL that contains a separate class designated for each button.  That works fine.

 

However, I don't want to have a hundred buttons and a hundred classes.  I want to have one class that uses arguments to change the code.   So I successfully made a combobox that has all the iterations of the code.  I want the user to pick the element in the combobox, then it will execute one class but use its name or value as an argument to differentiate.  Also, I want the class to read the contents of the Revit Textbox, but I cannot figure out how to pass that string as well.  

 

Any help would be greatly appreciated.  

 

 

0 Likes
3,652 Views
14 Replies
Replies (14)
Message 2 of 15

Anonymous
Not applicable

I have not tried using a combobox in a Revit Toolbar context. I tried once and immediately bounced off, so I went somewhere else. Maybe this following idea that will work. I'm currently trying to make something else out of this concept. If you can get some unique string about the selected combobox box item, like the combobox item text string, then you can encode a key into that string text that you extract and then use in your all purpose command to lookup the desired arguments from a dictionary you have socked away as a "System.Collections.Specialized.StringCollection" applications setting for your add-in. 

 

So for example say the combobox item text strings are "T01-WhatMeWorry" and "T02-WhatNow" and your all purpose command can get that text. It would extract the "T01" or "T02". Then it would get the add-ins "Properties.Settings.Default.MyTextToolArguments" where MyTextToolArguments is a "System.Collections.Specialized.StringCollection" holding all the arguments as a StringCollection. It would then convert that StringCollection to a Dictionary <string><string> that matches keys to arguments. You might have keys like "T01_ARG01", "T01_ARG02", "T01_ARG03" , "T02_ARG01", "T02_ARG02", "T02_ARG03, T02_ARG04" etc. At that point the all purpose command gets the arguments it needs. Then Bob's your uncle.

 

You can get code examples online for routines that do the necessary conversion between StringCollection and Dictionary.

 

You can also turn this around to maintain that System.Collections.Specialized.StringCollection settings with other add-in code. You will eventually need that because the dictionary encoded into the settings will start out hardcoded and most likely need to be changed at a future date. 

0 Likes
Message 3 of 15

Troy_Gates
Advocate
Advocate

Both ComboBox and TextBox ribbon items have events. You'll want to use those events to see what their value is when they run your command.

 

  1. ComboBox events:
    1. CurrentChanged
    2. DropDownClosed
    3. DropDownOpened
  2. TextBox event:
    1.  EnterPressed 

 

Here is a resource with code examples for items you can build on a Ribbon: https://knowledge.autodesk.com/search-result/caas/CloudHelp/cloudhelp/2016/ENU/Revit-API/files/GUID-...

0 Likes
Message 4 of 15

Anonymous
Not applicable

That explains the expression, "bounced off". At the article bottom is the question, "Was this article helpful? Yes or No". We all eventually reach this article. No, it is not helpful in regard to comboboxes. It is missing a full implementation for a combobox. It would be very simple for whoever is supervising those articles to have a check list for what is mentioned and a check list of what is actually fully explained.  

Message 5 of 15

Anonymous
Not applicable

Also, there is nothing in the text explaining how these events are triggered in the command.  Maybe I'm setting this up wrong, but there isn't anything explaining how to properly do this.

 

I have a DLL that has a bunch of "commands" in it.  I have another "application" DLL with an "application" Addin file.  My "application" DLL has all the UI RIbbon coding.  When someone clicks the buttons that run in the application DLL, it triggers the "Command" DLL by using the class name and DLL path.

 

There doesn't seem to be a way to pass the arguments to using the Revit Ribbon code.  

 

for example:

 

        PushButton pushButton = panel.AddItem(new PushButtonData(
            MiscUIText,
            ButtonTextUI,
            ButtonDLLPath,
            DLLNamespace)) as PushButton;

Now I understand that example uses a PushButton, but if I replace it with combobox or textbox, and use a Revit event, I'm still not sure how it will be passed to the DLL.  

 

Am I supposed to code my "Command" coding in the "application" DLL?  That way I can use the contents of the Textbox or contents of the Combobox like this:  

 

void ProcessText(object sender, Autodesk.Revit.UI.Events.TextBoxEnterPressedEventArgs args)
{
        // cast sender as TextBox to retrieve text value
        TextBox textBox = sender as TextBox;
        string strText = textBox.Value as string;
}

 

This is all strangely confusing.

0 Likes
Message 6 of 15

Troy_Gates
Advocate
Advocate

Here is a very simple example showing how to create a barebones TextBox and grab the value when the Enter Key is pressed. Once you have the textBox.Value, you can send that to your command.

 


public void AddTextBox(UIControlledApplication app) { RibbonPanel panel = app.CreateRibbonPanel("Example"); TextBoxData textData = new TextBoxData("Text Box"); TextBox tBox = panel.AddItem(textData) as TextBox; tBox.PromptText = "Enter A Command"; tBox.EnterPressed += new EventHandler<Autodesk.Revit.UI.Events.TextBoxEnterPressedEventArgs>(ProcessText); } void ProcessText(object sender, Autodesk.Revit.UI.Events.TextBoxEnterPressedEventArgs args) { // cast sender as TextBox to retrieve text value TextBox textBox = sender as TextBox; string strText = textBox.Value as string; }

0 Likes
Message 7 of 15

Anonymous
Not applicable
Thanks, but I already know how to do all that. Also I can code it for a combobox too, returning the "Current" ItemText.

However, How do I run a Command DLL in the ProcessText you posted above? And how can I pass the strText to the Command DLL?

The only way I can think to do this is to write my codes as "Application" DLLs, but I'd much rather have a separate "Command" DLL which is triggered when a person clicks a button or combobox. But how can I pass the strText to the "Command" DLL? In the PushButtonData, you can set the DLL path and class name, but no arguments.
0 Likes
Message 8 of 15

Troy_Gates
Advocate
Advocate

Maybe store the value of the string in the registry or in a file that your command can access when it runs. I can think of multiple ways to store that value so that it can be accessed by your other command.

 

0 Likes
Message 9 of 15

Anonymous
Not applicable
I considered that, but I just wanted to check with the forum in case there was an in-the-box solution for passing strings, at the very least.

Thanks for your help brainstorming on this topic.
0 Likes
Message 10 of 15

Anonymous
Not applicable

Actually, I'm still running into a bigger problem.  When I get the event of a combobox, I'm unable to run anything from it.  How do i trigger the desired "Assembly Name" and "Class Name" that is expressed in the Button object, but not the items in the Combobox object?  

 

Maybe this is what Aksaks is talking about in his comments.  

 

For example:  This is how I can set a button with the Assembly Name and Class Name for the command:

 

 

        PushButton pushButton = panel.AddItem(new PushButtonData(
            MiscUIText,
            ButtonTextUI,
            ButtonDLLPath,
            DLLNamespace)) as PushButton;

where "ButtonDLLPath" is something like "c:\blah\blah\commandRevit.dll" and "DLLNamespace" is something like "RevitCommandV0" in the class.

 

 

However, when I use the combobox, I write something like this:

 

 

 ComboBoxData CB1Data = new ComboBoxData("11111");
ComboBoxData CB2Data = new ComboBoxData("22222");
IList<RibbonItem> cnt1Stacked = panel.AddStackedItems(CB1Data, CB2Data);

Autodesk.Revit.UI.ComboBox combo1 = cnt1Stacked[0] as Autodesk.Revit.UI.ComboBox;

Autodesk.Revit.UI.ComboBox combo2 = cnt1Stacked[1] as Autodesk.Revit.UI.ComboBox;

 ComboBoxMemberData SDD = new ComboBoxMemberData("asdfsdafs", "werqwerwqe");

ComboBoxMember cb1Mem1 = combo1.AddItem(SDD);

 

which creates a bunch of combobox options.  However, there is no way to trigger a command, like in the button which has "Assembly Name" and "Class Name" properties on the ButtonData object.

 

However, I would assume that Revit engineers has created a non-event triggered way to run a Revit command.  Just a simple command like "RunCommand" or "GenericData" which allows a user to define their own events with the TextBox or Combobox button and run this generic command.  Any ideas?

 

 

 

b

0 Likes
Message 11 of 15

Anonymous
Not applicable

I think I see it now. I fooled with this a bit.

 

" However, there is no way to trigger a command, like in the button which has "Assembly Name" and "Class Name" properties on the ButtonData object."

 

Because they did not intend for someone to use it that way. The Revit ribbon combobox appears to be meant for selecting an option that would be available to a command called by a button. The combobox three events: CurrentChanged, DropDownClosed and DropDownOpened would fire handlers that maintain whatever option information scheme you have cooked up. The command called by some other button control, what you are used to using, needs to be able to look back to the information scheme go get the information it needs as arguments.  When you make the combos public and make the ribbon public as described by Jeremy Tammik, then your command can look back to see what the combos are set to in order to establish the needed text arguments if that is what you are trying to do. 

 

String thisPanelGenScripName = "GenScrip";
            RibbonPanel thisPanelGenScrip = a.CreateRibbonPanel(thisNewTabName, thisPanelGenScripName);

            ComboBoxData CB1Data = new ComboBoxData("11111");
            ComboBoxData CB2Data = new ComboBoxData("22222");
            IList<RibbonItem> cnt1Stacked = thisPanelGenScrip.AddStackedItems(CB1Data, CB2Data);

            Autodesk.Revit.UI.ComboBox combo1 = cnt1Stacked[0] as Autodesk.Revit.UI.ComboBox;

            Autodesk.Revit.UI.ComboBox combo2 = cnt1Stacked[1] as Autodesk.Revit.UI.ComboBox;

            ComboBoxMemberData SDD11 = new ComboBoxMemberData("CB1_01", "Item for CB1_01 item(SDD11)");
            ComboBoxMemberData SDD12 = new ComboBoxMemberData("CB1_02", "Item for CB1_02 item(SDD1)");

            ComboBoxMember cb1Mem11 = combo1.AddItem(SDD11);
            ComboBoxMember cb1Mem12 = combo1.AddItem(SDD12);

            ComboBoxMemberData SDD21 = new ComboBoxMemberData("CB2_01", "Item for CB2_01 item(SDD21)");
            ComboBoxMemberData SDD22 = new ComboBoxMemberData("CB2_02", "Item for CB2_02 item(SDD22)");

            ComboBoxMember cb1Mem21 = combo2.AddItem(SDD21);
            ComboBoxMember cb1Mem22 = combo2.AddItem(SDD22);

            combo1.CurrentChanged += 
                new EventHandler<Autodesk.Revit.UI.Events.ComboBoxCurrentChangedEventArgs>(ProcessComboChange);

            combo2.CurrentChanged +=
                new EventHandler<Autodesk.Revit.UI.Events.ComboBoxCurrentChangedEventArgs>(ProcessComboChange);

and then outside if the class App...Ribbon : IExternalApplication

 

void ProcessComboChange(object sender, Autodesk.Revit.UI.Events.ComboBoxCurrentChangedEventArgs args) {
            ComboBox cbox = sender as ComboBox;
            ComboBoxMember cbxMembr = cbox.Current as ComboBoxMember;
            System.Windows.MessageBox.Show(cbxMembr.ItemText);
        }

I am wondering if this handler needs to be removed and where.

 

 

Message 12 of 15

Anonymous
Not applicable

I suspected that.  

 

I really don't want to engage a second button to run it.  Bummer.

 

I'd rather there be a generic command that will run any Revit plugin DLL, regardless of the dumb button.  So you could run a command any time.  but whatev.  I can get this done by writing the selected element from the combobox to a text file, then force the person to click the darn button.  Then the code reads the text file to send the arguments.  On close, it'll clear the file.  yowza.  

 

thanks for your confirmation on this.  

0 Likes
Message 13 of 15

Anonymous
Not applicable

"When you make the combos public and make the ribbon public as described by Jeremy Tammik, then your command can look back to see what the combos are set to in order to establish the needed text arguments if that is what you are trying to do. "

 

 

Can you post a link to that?  I've looked around, and didnt find anything about reading Revit.UI.Comboboxes from the main REvit UI.

 

 

 

 

0 Likes
Message 14 of 15

Anonymous
Not applicable

Nevermind.  I found the "GetRibbonPanels" under the UI app object.  

0 Likes
Message 15 of 15

Anonymous
Not applicable

It all started with this:

 

http://thebuildingcoder.typepad.com/blog/2012/11/roll-your-own-toggle-button.html

 

Which resulted in this:

 

http://thebuildingcoder.typepad.com/blog/2016/09/stacked-ribbon-button-panel-options.html#3

 

I considered using a Revit ribbon combobox for a task after seeing your posts and fooling with them a bit. There did not seem to be a way to control the combobox width. It also ends up taking a lot of Ribbin-estate. There are also few other UI options available. I decided not to use it but to do something totally different for the task that needed a combo. Instead a Ribbon button fires up a floating, borderless "chromeless" WPF window that contains the combobox set to the user's previous setting. The window can be moved to any location the user likes and it will be at that location the next time it is used. You can't do anything like that with a Ribbon. The combobox contains BuiltInCategories. After dismissing the WPF with a ESC or mouse click the tool puts the user into select mode where only the elements being the selected BuiltInCategory being selected. That is the main purpose. It is a filtered selecting tool. It exits with those items selected. The task is arranged so that the needed combo occurs briefly only at the time it is of any use to the task while afterwards continuing into the real task at hand.

 

I think your text plunking task can be organized in a similar fashion. The user knows the certain task with options needs to be done. There is a button for it. The user does not need to see the options until the process is started. The initial options WPF full of UI controls shows the default option that a single click or ESC key will continue with or the user can select a different option. You have the full gamut of UI options to play with and because this is strictly a modal need there is no interference with Revit.  The WPF closing saves the desired option state and the rest of the custom Revit command reaches back to get the options for the arguments used in the command. For the filtered selecting tool the builtincategory is saved in the add-in's "default.settings". You could do the same. The filtered selecting tool also has a pick-to-select-example mode that saves the builtincategory for the other mode to use. This is essentially a mode that skips the combobox selector. By the way, a similar independent WPF can be used to provide feedback to the user while your custom Revit command is in action. So for your task it could inform the user, to paraphrase, "Here's what you are doing. Here are the options that will be used. Now go do this ...", that shows just before the getObject command and that is closed out when the command finishes.

 

 

 

0 Likes