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
Solved! Go to Solution.
Solved by peteregan. Go to Solution.
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.
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"
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
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));
@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
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)); }
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.
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!
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
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.
Similar issue at https://forums.autodesk.com/t5/revit-api-forum/reload-refresh-my-added-toolbar-with-external-command... . Could you help me ?@Songohu_85 , @FAIR59
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 😉
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?
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 😃
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();
Thank you. I am getting one error, maybe I am not setting something properly.
Can't find what you're looking for? Ask the community or share your knowledge.