Change RibbonItem (Button) Properties at Runtime

Anonymous

Change RibbonItem (Button) Properties at Runtime

Anonymous
Not applicable

I'm trying to essentially toggle a ribbon button's properties at runtime.  I have certain process' lined up to grab the button/RibbonItem instance, but when I attempt to change the button properties, the API returns out of my function having not changed anything.  It's doesn't throw an error or anything - it just doesn't do anything...

 

I essentially iterate through the Ribbon, it's panels and their Source.Items until I find the button I need to adjust.  I tried changing it during the iteration and that didn't work; I tried grabbing the button, creating a copy, assigning the new properties to the copy and then reassigning the button as the copy - that didn't work.... As usual, I'm sure it's just some tiny thing I'm missing.  I've tried a lot, and nothing seems to be wanting to cooperate with me, so I'm seeing how I can change the button at runtime.

 

For the record, the Properties I'm trying to modify are 'Name', 'Tooltip', and 'Image'.

 

Any ideas or direction is greatly appreciated.

 

Don't forget to mark your answers...  It helps the next individual find theirs faster!!

Cheers, 

 

Geoff Overfield

Senior Software Engineer

FabPro, LLC

FP_Logo(2).png

0 Likes
Reply
Accepted solutions (1)
6,025 Views
24 Replies
Replies (24)

adam.krug
Advocate
Advocate

Is your process fired from inside a command or e.g. Idling event handler or any other? Normally you can't affect things with API unless you are in such context. For instance, you build your new buttons, ribbons etc inside ExternalApplication.OnStartup command.

0 Likes

peteregan
Contributor
Contributor
Accepted solution

I can change my ribbon with this code:

List<RibbonPanel> rPanels = new List<RibbonPanel>();
rPanels = app.GetRibbonPanels();
foreach (RibbonPanel rp in rPanels)
{
	if (rp.Name == "-RMD-")
	{
		rp.Title = "New Name";
		foreach (RibbonItem ris in rp.GetItems())
		{
			ris.ItemText = "xyz";
			ris.ToolTip = "This is a test This is a test";
		}
	}
}

 

 

Changing the image is too complicated for my quick test, but you would need to do:
PushButton pb = ris as PushButton;
pb.LargeImage = new (BitmapImage(new Uri(filePath)));

 

Notice that in neither case did I change the "Name"

 

rename_ribbon_items.png

Anonymous
Not applicable

This is pretty much what I landed on.  You can change the button text and tooltip - but you cannot change the icon at runtime, which is what I originally was going for.

 

Don't forget to mark your answers...  It helps the next individual find theirs faster!!

Cheers, 

 

Geoff Overfield

Senior Software Engineer

FabPro, LLC

 FP_Logo(2).png

0 Likes

adam.krug
Advocate
Advocate

How about replacing a given button with a new one? Delete old, create new. Would this work?

0 Likes

FAIR59
Advisor
Advisor

if you cast the RibbonItem to a RibbonButton you can set the LargeImage property.

			Autodesk.Windows.RibbonButton my_button ;
			my_button.LargeImage = new System.Windows.Media.Imaging.BitmapImage(new Uri(filepath, UriKind.Absolute));
0 Likes

Anonymous
Not applicable

@adam.krug- Unfortunately, I do not think that will work.  From my experience, I believe that ribbon elements must be initialized during OnStartup, so you cannot create new buttons at runtime.  This would also lead me to believe that you couldn't delete them either.  As a side note, I also think this would just be bad practice, as it could open the door for a host of errors like losing paths for event handlers...  I could see too many ways something like this could go wrong.

 

@FAIR59- I attempted doing that already, and the image cannot be changed at runtime.  Only it's text properties like Name, Tooltip, etc can be successfully altered.  Though the code may "allow" you to change the value in the LargeImage property, the icon, itself, does not change and an internal error triggers...  The long story-short is that you cannot change the image of ribbon elements at runtime - the API does not allow it.  They all have to be set during OnStartup (from my experience).

 

Thank you for your feedback and contribution!

 

Don't forget to mark your answers...  It helps the next individual find theirs faster!!

Cheers, 

 

Geoff Overfield

Software Engineer

FabPro, LLC

FP_Logo(2).png

0 Likes

FAIR59
Advisor
Advisor

I wrote a little macro today (Revit 2018) and the button Image changed.

		// using adwin  = Autodesk.Windows;
		public void Test()
		{
			Document doc = this.ActiveUIDocument.Document;
			adwin.RibbonControl ribbon = adwin.ComponentManager.Ribbon;
			adwin.RibbonTab my_tab = null;
			adwin.RibbonPanel my_panel = null;
			adwin.RibbonButton my_button = null;
			foreach (var tab in ribbon.Tabs)
			{
				if (tab.Id == "Add-Ins")
				{
					my_tab = tab;
					break;
				}
			}
			if (my_tab==null) 	return;
			foreach(var panel in my_tab.Panels)
			{
				if(panel.Source.Id == "CustomCtrl_%Add-Ins%KCAP")
				{
					my_panel = panel;
					break;
				}
			}
			if( my_panel==null)	return;
			foreach(var item in my_panel.Source.Items)
			{
				if (item.Id.Contains("Fa_mirror"))
				{
					my_button = item as adwin.RibbonButton;
					break;
				}
			}
			if (my_button == null) return;
			string filepath = Path.Combine(@"K:\","ArkUser","basis.ico");
			my_button.LargeImage = new System.Windows.Media.Imaging.BitmapImage(new Uri(filepath, UriKind.Absolute));
			
		}

TA.Fehr
Advocate
Advocate

Thanks for this. I was looking on how to change my icon to notify the user of an update and this is the only method I've found that works.

The one thing I had to change was my icon had to be in ".ico" format, originally I had it as a ".png" and this didn't work.

0 Likes

Anonymous
Not applicable

Glad to be of some help.  I use .png's because of how we initialize our ribbon.  Perhaps using the .ico is what would allow it to change the image at run-time?  Please let me know!

0 Likes

TA.Fehr
Advocate
Advocate

I don't think that changing to an ICO would affect your ribbon. I previously used a PNG, and was able to swap it for an ICO. I did, however, need to scale the ICO to be the correct size (32 and 16).

My initialize is the same as what is found in the add-in examples:

g_inventorApplication = addInSiteObject.Application
            ' Connect to the user-interface events to handle a ribbon reset.
            M_uiEvents = g_inventorApplication.UserInterfaceManager.UserInterfaceEvents
            M_UIEvents2 = g_inventorApplication.CommandManager.UserInputEvents
            Dim LargeIcon As stdole.IPictureDisp = PictureDispConverter.ToIPictureDisp(My.Resources.Icon32)
            Dim SmallIcon As stdole.IPictureDisp = PictureDispConverter.ToIPictureDisp(My.Resources.Icon16)

            Dim controlDefs As Inventor.ControlDefinitions = g_inventorApplication.CommandManager.ControlDefinitions
            M_Button = controlDefs.AddButtonDefinition("Settings", "UIButton", CommandTypesEnum.kShapeEditCmdType, AddInClientID,,, SmallIcon, LargeIcon, ButtonDisplayEnum.kDisplayTextInLearningMode)
            M_AppEvents = g_inventorApplication.ApplicationEvents

and my code to change the icon is:

  Public Sub ChangeIcon(IconLoc As String)
        Dim RibbonControl As RibbonControl = ComponentManager.Ribbon
        Dim RibbonTab As Autodesk.Windows.RibbonTab = RibbonControl.FindTab("id_GetStarted")
        Dim ASPanel As Autodesk.Windows.RibbonPanel
        Dim Icon As Autodesk.Windows.RibbonButton

        For Each panel In RibbonTab.Panels
            If panel.Source.Id = "Button" Then
                ASPanel = panel
                For Each item In ASPanel.Source.Items
                    If item.Id.Contains("Button") Then
                        Icon = CType(item, Autodesk.Windows.RibbonButton)
                        Icon.LargeImage = New System.Windows.Media.Imaging.BitmapImage(New Uri(IconLoc, UriKind.Absolute))

                    End If
                Next
            End If
        Next
    End Sub

I had to include the icon files in the distribution so that I could reference the file names by location. Originally they were pulled from the resources, but this wouldn't work in a distribution environment.

 

Hope this helps

Songohu_85
Enthusiast
Enthusiast

I think that Jeremy has covered this issue many years ago:

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

Button image can be changed whenever you wish. In the above link you will find how to create a reference to the image.

Jaime_Alonso
Enthusiast
Enthusiast

I can not get it working. Is this still available in Revit 2021?

Thanks

0 Likes

Songohu_85
Enthusiast
Enthusiast

Yes, it works in 2021 too.

Jaime_Alonso
Enthusiast
Enthusiast

Songohu_85
Enthusiast
Enthusiast

https://github.com/songohu30/DockPanelButton

 

In the link above you will find an extract from how I work with dockable panels. At the beginning I simply toogled button image and text on every click (you should be able to fish out neccessary code). This easy option is used in button_easy. In medium version the image and text depends on current dockpanel visibility state so events and more complexed stuff is used but it works as it should with dockabple panels.

Forgive me if the comments doesn't clearly explain everything. I tried but probably I don't understand it myself to well 🙂 I'm a patient guy though so you can ask questions.

 

Cheers

Marek

 

p.s. I packed it all in App.cs so you get everything in one place. It's not a good practice to follow 😉

Jaime_Alonso
Enthusiast
Enthusiast

Thank you very much!! That was a full exercise to look at. Before getting into this, I got it working by setting the right Ids with the method provided by @FAIR59 to extract them at https://forums.autodesk.com/t5/revit-api-forum/reload-refresh-my-added-toolbar-with-external-command...

Any idea how renaming a button could work with a button within a Splitbuttondata?

Jaime_Alonso
Enthusiast
Enthusiast

I finally got it working by replacing the two adwin.RibbonButton by adwin.RibbonSplitButton and adding at the end;

my_button.Current.Text = "NEW NAME";

Thanks! The issue now is resetting the image. LargeImage property does not reset the image of my splitbutton... Sorry for my inexpertise 😃

Songohu_85
Enthusiast
Enthusiast

I'm happy to hear that you found a solution. I'd like to make a small suggestion for the future:

All the ribbon items are created on startup. You can also create references to all this objects on startup instead of searching for them in ribbon items. I haven't tested that but I'm like 90% sure it will work 🙂

    public class App : IExternalApplication
    {
	public List<RibbonItem> MyRibbonItems {get; set;}

        internal static App _app = null;
        public static App Instance
        {
            get { return _app; }
        }

        public Result OnShutdown(UIControlledApplication application)
        {
            return Result.Succeeded;
        }

        public Result OnStartup(UIControlledApplication application)
        {
            _app = this;

	    string path = Assembly.GetExecutingAssembly().Location;

            RibbonPanel ribPanel = application.CreateRibbonPanel("My Panel");

            PushButtonData pushButtonPanelControl1 = new PushButtonData("DockControlEasy", "Show Easy", path, "DockPanelButton.ShowHideDockEasy");
            pushButtonPanelControl1.LargeImage = GetEmbeddedImage("Resources.Inactive.png");
            RibbonItem button1 = ribPanel.AddItem(pushButtonPanelControl1);

	    MyRibbonItems = new List<RibbonItem>();
	    MyRibbonItems.Add(button1);

            return Result.Succeeded;
        }
    }
    
    //this is how you get access to a specific ribbon item within your namespace
    RibbonItem button = App.Instance.MyRibbonItems.Where(e => e.ItemText == "button text").FirstOrDefault();

 

 

Jaime_Alonso
Enthusiast
Enthusiast

Thank you. I am getting one error, maybe I am not setting something properly.

 

Captura.PNG

0 Likes