Ribbon not loading on AutoCAD 2024

Ribbon not loading on AutoCAD 2024

R.Gerritsen4967
Advocate Advocate
2,268 Views
7 Replies
Message 1 of 8

Ribbon not loading on AutoCAD 2024

R.Gerritsen4967
Advocate
Advocate

I've been using my ribboncode for many versions of AutoCAD.

Last week I installed AutoCAD 2024 on my computer. Unfortunately, now my ribbon is not loading correctly.

 

I now use the following code to initialise the ribbon:

Public Class myRibbon

    Implements Autodesk.AutoCAD.Runtime.IExtensionApplication

    Public Sub Initialize() Implements Autodesk.AutoCAD.Runtime.IExtensionApplication.Initialize

        Try
            AddHandler Autodesk.AutoCAD.ApplicationServices.Application.Idle, AddressOf App_Idle

        Catch ex As System.Exception
            Dim doc As Document = Application.DocumentManager.MdiActiveDocument
            Dim ed As Editor = doc.Editor
            ed.WriteMessage(vbLf & "{0}", ex.ToString())
        End Try

    End Sub

    Private Sub App_Idle(sender As Object, e As EventArgs)

        RemoveHandler Autodesk.AutoCAD.ApplicationServices.Application.Idle, AddressOf App_Idle

        LoadRibbonPanels.LoadRibbon()

    End Sub

    Public Sub Terminate() Implements Autodesk.AutoCAD.Runtime.IExtensionApplication.Terminate
    End Sub

End Class

Public Class LoadRibbonPanels
    <CommandMethod("Loadribbon")> Public Shared Sub LoadRibbon()

        'Create Ribbon tabs
        Dim ribbonControl1 As Autodesk.Windows.RibbonControl = Autodesk.Windows.ComponentManager.Ribbon

        If ribbonControl1 IsNot Nothing Then
            Dim Tab As RibbonTab = ribbonControl1.FindTab("myRibbon")
            If Tab IsNot Nothing Then
                ribbonControl1.Tabs.Remove(Tab)
            End If

            Tab = New RibbonTab With {
                .Title = "myRibbon",
                .Id = "1"
            }

            'Add tab to the ribbon
            ribbonControl1.Tabs.Add(Tab)
            ' create Ribbon panels

        End If

    End Sub
End Class

 

As you can see I'm using the 'Application.Idle' event to load the ribbon on AutoCAD startup.

With all autocads up to 2023 this worked fine, but not in 2024.

It only works the first time I load the dll. After that the ribbon appears, but instantly disappears when a drawing is opened.

 

At first I was using the RibbonPaletteSetCreated event to load the ribbon, but, for now, this behaves the same as the Application.Idle event.

 

When I give the command 'LoadRibbon' the ribbons are displayed correctly. But I don't want to give this command everytime I start AutoCAD.

 

Does anyone know what I'm doing wrong?

0 Likes
Accepted solutions (1)
2,269 Views
7 Replies
Replies (7)
Message 2 of 8

norman.yuan
Mentor
Mentor
Accepted solution

Your code ONLY load the custom ribbon tab when Acad becomes idle after startup (btw, you really should only remove the idle event handler inside the LoadRibbon() method, that is, only remove the event handler after the custom ribbon items are loaded 

 

To keep the dynamically loaded custom ribbon items, you also need to handle RibbonPaletteSet.WorkspaceLoaded event to reload the custom ribbon items, when the current Workspace changes, which is what I suspect happens when you Acad 2024 starts.

 

Norman Yuan

Drive CAD With Code

EESignature

0 Likes
Message 3 of 8

R.Gerritsen4967
Advocate
Advocate

@norman.yuan 

Thank you! Adding the RibbonPaletteSet.WorkspaceLoaded event did the trick...

0 Likes
Message 4 of 8

AlexFielder
Advisor
Advisor

Hi @R.Gerritsen4967 @norman.yuan 

 

Do you happen to have an example of using the RibbonServices.RibbonPaletteSet.WorkspaceLoaded event that you can share?

 

I have an addin I am writing that loads the ribbon when I debug, but when I build a release, the ribbon tab loads but isn't populated.

I have adapted this old RibbonHandler from over at The Swamp, but it just doesn't work, which, given it was written before these events changed (per this post)  is not really surprising:

public class RibbonHelper
    {
        Action<RibbonControl> action = null;
        bool idleHandled = false;
        bool created = false;

        RibbonHelper(Action<RibbonControl> action)
        {
            this.action = action ?? throw new ArgumentNullException("initializer");
            SetIdle(true);
        }

        public static void OnRibbonFound(Action<RibbonControl> action)
        {
            new RibbonHelper(action);
        }

        private void SetIdle(bool value)
        {
            if (value != idleHandled)
            {
                if (value)
                    Application.Idle += Idle;
                else
                    Application.Idle -= Idle;

                idleHandled = value;
            }
        }

        private void Idle(object sender, EventArgs e)
        {
            SetIdle(false); // Prevent re-entry

            if (!EnsureRibbonControl(action) && !created)
            {
                created = true;
                RibbonServices.RibbonPaletteSetCreated += RibbonPaletteSetCreated;
            }
        }

        private void WorkspaceLoaded(object sender, EventArgs e)
        {
            if (EnsureRibbonControl(action))
            {
                // Once the ribbon is successfully created, no need to listen for WorkspaceLoaded
                RibbonServices.RibbonPaletteSet.WorkspaceLoaded -= WorkspaceLoaded;
            }
        }

        private bool EnsureRibbonControl(Action<RibbonControl> action)
        {
            var ribbonControl = RibbonServices.RibbonPaletteSet?.RibbonControl;
            if (ribbonControl != null)
            {
                action(ribbonControl);
                return true;
            }
            return false;
        }

        void RibbonPaletteSetCreated(object sender, EventArgs e)
        {
            RibbonServices.RibbonPaletteSetCreated -= RibbonPaletteSetCreated;
            RibbonServices.RibbonPaletteSet.WorkspaceLoaded -= WorkspaceLoaded;
            SetIdle(true);
        }
    }

 

Here is my initialization class:

public class Initialization : IExtensionApplication
    {
        private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

        private DocumentCollection _dwgManager = null;
        private static bool _handlerLoaded = false;
        //private static string _customCmd = null;
        private static ObjectId _selectedEntId = ObjectId.Null;
        private static CustomCommandMappers _customCommands = null;
        //private static bool _runCustomCommand = false;
        private static OptionsDlg _options = null;
        private static UXSettings uXSettings;
        private static List<MyButton> buttons = new List<MyButton>();
        public void Initialize()
        {
            Document dwg = Application.DocumentManager.MdiActiveDocument;
            Editor ed = dwg.Editor;
            _dwgManager = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager;
            uXSettings = new UXSettings();

            try
            {
                CadApp.Idle += OnIdle;

                Application.DisplayingOptionDialog += new TabbedDialogEventHandler(Application_DisplayingOptionDialog);

                _dwgManager.DocumentActivated += new DocumentCollectionEventHandler(DwgManager_Activated);
                _dwgManager.DocumentBecameCurrent += new DocumentCollectionEventHandler(DwgManager_Activated);

                ed.WriteMessage("\nInitializing {0}...", this.GetType().Name);

                RibbonHelper.OnRibbonFound(SetupRibbon);
            }
            catch (System.Exception ex) when (Commands.NotDebugging)
            {
                ed.WriteMessage("failed:\n{0}", ex.ToString());
                log.Error(ex.ToString());
            }


        }

        private void WorkspaceLoaded(object sender, EventArgs e)
        {
            RibbonHelper.OnRibbonFound(this.SetupRibbon);
        }

        private void SetupRibbonByCUI(string tabName, string panelName)
        {
            var cuiFile = CadApp.GetSystemVariable("MENUNAME");
            var cs = new Autodesk.AutoCAD.Customization.CustomizationSection(cuiFile.ToString() + @".cuix");
            var currWorkspace = (string)CadApp.GetSystemVariable("WSCURRENT");

            Autodesk.AutoCAD.Customization.RibbonRoot root = cs.MenuGroup.RibbonRoot;
            Autodesk.AutoCAD.Customization.RibbonPanelSourceCollection panels = root.RibbonPanelSources;

            Autodesk.AutoCAD.Customization.RibbonPanelSource panelsrc=new Autodesk.AutoCAD.Customization.RibbonPanelSource(root)
            {
                Name = panelName,
                Text = panelName
            };
            panelSrc.ElementID = panelSrc.Id = panelSrc.Name + "_PanelSourceID";

            panels.Add(panelSrc);

            Autodesk.AutoCAD.Customization.RibbonTabSource ribbonTabSource = new Autodesk.AutoCAD.Customization.RibbonTabSource(root)
            {
                Name = tabName,
                Text = tabName
            };
            ribbonTabSource.ElementID = ribbonTabSource.Id = ribbonTabSource.Name + "_TabSourceID";

            root.RibbonTabSources.Add(ribbonTabSource);

            Autodesk.AutoCAD.Customization.RibbonPanelSourceReference panelSrcRef = new Autodesk.AutoCAD.Customization.RibbonPanelSourceReference(ribbonTabSource)
            {
                PanelId = panelSrc.ElementID
            };
            ribbonTabSource.Items.Add(panelSrcRef);

            Autodesk.AutoCAD.Customization.WSRibbonTabSourceReference wsRibbonTabSourceRef = Autodesk.AutoCAD.Customization.WSRibbonTabSourceReference.Create(ribbonTabSource);

            int curWsIndex = cs.Workspaces.IndexOfWorkspaceName(currWorkspace);
            Autodesk.AutoCAD.Customization.WSRibbonRoot wsRibbonRoot = cs.Workspaces[curWsIndex].WorkspaceRibbonRoot;

            //Set the owner of the ribbon tab source reference and add it to the workspace ribbon tab collection
            wsRibbonTabSourceRef.SetParent(wsRibbonRoot);
            wsRibbonRoot.WorkspaceTabs.Add(wsRibbonTabSourceRef);

            BuildButtonsFromCommandMethods();

            Autodesk.AutoCAD.Customization.MacroGroup macroGroup = cs.MenuGroup.MacroGroups[0];


            Autodesk.AutoCAD.Customization.RibbonRow ribbonRow = panelSrc.AddNewRibbonRow();
            foreach (var btn in buttons)
            {
                Autodesk.AutoCAD.Customization.MenuMacro btnMacro = macroGroup.CreateMenuMacro($"{btn.Text}_Macro", $"^C^C{btn.Command}", btn.Tag.ToString(), btn.Help, 
                                                            Autodesk.AutoCAD.Customization.MacroType.Any, btn.SmallIcon.ToString(), btn.LargeIcon.ToString(), btn.Label);

                Autodesk.AutoCAD.Customization.RibbonCommandButton ribbonCommandButton = new Autodesk.AutoCAD.Customization.RibbonCommandButton(ribbonRow)
                {
                    MacroID = btnMacro.ElementID,
                    ButtonStyle = Autodesk.AutoCAD.Customization.RibbonButtonStyle.LargeWithText,
                    KeyTip = btn.Text,
                    Text = btn.Text,
                    TooltipTitle = btn.Tooltip
                };

                ribbonRow.Items.Add(ribbonCommandButton);
                Autodesk.AutoCAD.Customization.RibbonSeparator ribbonSeparator = new Autodesk.AutoCAD.Customization.RibbonSeparator(ribbonRow);
                ribbonSeparator.SeparatorStyle = Autodesk.AutoCAD.Customization.RibbonSeparatorStyle.Line;
                ribbonRow.Items.Add(ribbonSeparator);
                //ribbonRow.AddNewButton(btn.Text, 
                //                        btn.Label, 
                //                        btn.Command, 
                //                        btn.Tooltip, 
                //                        btn.SmallIcon.ToString(), 
                //                        btn.LargeIcon.ToString(), 
                //                        Autodesk.AutoCAD.Customization.RibbonButtonStyle.LargeWithText);
            }
            
            cs.Save();
        }

        private void SetupRibbon(RibbonControl control)
        {
            var doc = CadApp.DocumentManager.MdiActiveDocument;
            var ed = doc.Editor;
            if (uXSettings.RibbonEnabled)
            {
                BuildButtonsFromCommandMethods();
                RibbonControl ribbon = ComponentManager.Ribbon;
                if (ribbon != null)
                {
                    RibbonTab tab = ribbon.FindTab("Stainless UK_Id");
                    if (tab != null)
                    {
                        ribbon.Tabs.Remove(tab);
                    }
                    BuildRibbonTabAndPanel("Stainless UK", "Masonry Support");
                }
                else
                {
                    ed.WriteLine("Ribbon not found, maybe AutoCAD is not idle yet..?");
                }
            }
        }

        private RibbonControl BuildRibbonTabAndPanel(string tabName, string panelName)
        {
            Autodesk.Windows.RibbonControl ribbon = ComponentManager.Ribbon;
            if (ribbon != null)
            {
                RibbonTab rtab = new RibbonTab
                {
                    Title = tabName,
                    Id = $"{tabName}_Id",
                    Name = tabName
                };
                rtab.Panels.Add(AddOnePanel(panelName));
                ribbon.Tabs.Add(rtab);
                
            }
            return ribbon;
        }

        private void BuildButtonsFromCommandMethods()
        {
            var doc = CadApp.DocumentManager.MdiActiveDocument;

            if (doc == null) return;

            var ed = doc.Editor;

            var asm = Assembly.GetExecutingAssembly();

            var type = asm.GetType("CADLibraryMSA.Commands");

            if (type == null)
            {
                ed.WriteMessage("\nCould not find the Commands class.");
                return;
            }

            foreach (var m in type.GetMethods())
            {
                foreach (CustomAttributeData attr in m.CustomAttributes)
                {
                    if (attr.AttributeType.Name == "ButtonMethod")
                    {
                        GetSettingFromUXSettings(attr, "Text", out string btnText);

                        GetSettingFromUXSettings(attr, "ToolTip", out string cmdToolTip);

                        MyButton btn = new MyButton(attr.GetAttributeValue<string>("Command"),
                                                    btnText,
                                                    attr.GetAttributeValue<string>("Help"),
                                                    attr.GetAttributeValue<string>("Tag"),
                                                    attr.GetAttributeValue<Bitmap>("SmallIcon"),
                                                    attr.GetAttributeValue<Bitmap>("LargeIcon"),
                                                    $"{attr.GetAttributeValue<string>("Label")}_Id",
                                                    cmdToolTip, attr.GetAttributeValue<int>("ButtonOrder"));
                        //btn.Text = btn.Command;

                        btn.Click += (s, e) =>
                        {
                            var b2 = (Button)s;
                            var m2 = type.GetMethod(b2.Text);
                            if (m2 != null)
                            {
                                var res = m2.Invoke(this, null);
                            }
                        };
                        buttons.Add(btn);
                    }
                }
            }
        }

        private static void GetSettingFromUXSettings(CustomAttributeData attr, string v, out string btnText)
        {
            btnText = attr.GetAttributeValue<string>(v);
            string pattern = @"uXSettings\.(\w+)";
            if (btnText.Contains("uXSettings"))
            {
                if (Regex.Matches(btnText, pattern).Count > 0)
                {
                    var matches = Regex.Matches(btnText, pattern);
                    PropertyInfo prop = uXSettings.GetType().GetProperty(matches[0].Groups[1].Value);
                    string replacement = prop.GetValue(uXSettings).ToString();
                    btnText = Regex.Replace(btnText, @"uXSettings\.(\w+)", replacement);
                }
            }
        }

        static RibbonPanel AddOnePanel(string panelName)
        {
            RibbonButton rb;
            Version version = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version;
            RibbonPanelSource rps = new RibbonPanelSource
            {
                Title = panelName + $" - v{version}",
                Id = $"{panelName}_Id",
                Name = panelName
            };
            RibbonPanel rp = new RibbonPanel
            {
                Source = rps
            };

            var sortedButtons = buttons.OrderBy(x => x.ButtonOrder).ToList();
            var doc = CadApp.DocumentManager.MdiActiveDocument;
            var ed = doc.Editor;
            foreach (var btn in sortedButtons)
            {
                //MenuMacro menuMacro = macroGroup.CreateMenuMacro($"{btn.Text}_Macro", $"^C^C{btn.Command}", btn.Tag.ToString(), btn.Help, MacroType.Any, btn.SmallIcon.ToString(), btn.LargeIcon.ToString(), btn.Label);
                //ribButton.MacroID = menuMacro.ElementID;

                rb = new RibbonButton
                {
                    CommandParameter = btn.Command,
                    CommandHandler = new RibbonCommandHandler(),
                    Text = btn.Text,
                    HelpTopic = btn.Help,
                    Tag = btn.Tag,
                    Name = btn.Label,
                    ToolTip = btn.Tooltip,
                    ShowText = true,
                    ShowImage = true,
                    IsToolTipEnabled = true,
                    IsEnabled = true,
                    IsVisible = true,
                    Size = RibbonItemSize.Large,
                    ResizeStyle = RibbonItemResizeStyles.HideText,
                    Orientation = System.Windows.Controls.Orientation.Vertical
                };
                var smallImage = LoadImage(btn.SmallIcon);
                var largeImage = LoadImage(btn.LargeIcon);

                if (smallImage != null)
                {
                    rb.Image = smallImage;
                }
                
                if (largeImage != null)
                {
                    rb.LargeImage = largeImage;
                }
                ed.WriteLine($"Added: {rb.Text} button");

                rps.Items.Add(rb);
                RibbonSeparator ribbonSeparator = new RibbonSeparator();
                ribbonSeparator.SeparatorStyle = RibbonSeparatorStyle.Line;
                rps.Items.Add(ribbonSeparator);
            }
            //Create a Command Item that the Dialog Launcher can use,
            // for this test it is just a place holder.
            //RibbonButton rci = new RibbonButton();
            //rci.Name = "TestCommand";

            ////assign the Command Item to the DialgLauncher which auto-enables
            //// the little button at the lower right of a Panel
            //rps.DialogLauncher = rci;

            //rb = new RibbonButton();
            //rb.Name = "Test Button";
            //rb.ShowText = true;
            //rb.Text = "Test Button";
            ////Add the Button to the Tab
            //rps.Items.Add(rb);
            return rp;
        }

        private static BitmapImage LoadImage(Bitmap imageToLoad)
        {
            Bitmap pic = imageToLoad;

            MemoryStream ms = new MemoryStream();

            pic.Save(ms, ImageFormat.Png);

            BitmapImage bi = new BitmapImage();

            bi.BeginInit();

            bi.StreamSource = ms;

            bi.EndInit();

            return bi;
        }


        private void Application_DisplayingOptionDialog(object sender, TabbedDialogEventArgs e)
        {
            if (_options == null)
            {
                _options = new OptionsDlg(uXSettings);
            }

            if (uXSettings == null)
            {
                uXSettings = new UXSettings();
                _options.DataContext = uXSettings;
            }

            _options.Resources = new ResourceDictionary() { Source = new Uri("pack://application:,,,/CADLibraryMSA;component/Themes/LightTheme.xaml") }; // Set the resource dictionary to the LightTheme.xaml file

            TabbedDialogExtension tde = new TabbedDialogExtension
            (
                _options,
                new TabbedDialogAction(OnOK),
                new TabbedDialogAction(OnCancel),
                new TabbedDialogAction(OnHelp),
                new TabbedDialogAction(OnApply)
            );
            e.AddTab("CAD Library Masonry Support Options", tde);
        }

        private static void OnOK()
        {
            ButtonPressedMessage("OK");
            SaveSettings();
        }

        private static void OnCancel()
        {
            uXSettings = null;
            ButtonPressedMessage("Cancel");
        }

        private static void OnHelp()
        {
            ButtonPressedMessage("Help");
        }

        private static void OnApply()
        {
            ButtonPressedMessage("Apply");
            SaveSettings();
        }

        private static void ButtonPressedMessage(string name)
        {
            Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
            ed.WriteMessage("The {0} button was pressed.\n", name);
        }

        private static void SaveSettings()
        {
            if (_options != null)
            {
                if (uXSettings != null)
                {
                    uXSettings.Save();
                }
            }
        }

        private void DwgManager_Activated(object sender, DocumentCollectionEventArgs e)
        {
            //if the document is not null, then we need to build the UI
            if (e.Document != null)
            {
                if (uXSettings.EnableDoubleClickSystemEditing)
                {
                    AppDoubleClickHandler appDoubleClickHandler = new AppDoubleClickHandler();
                    Application.SetSystemVariable("DBLCLKEDIT", 0);
                    AppDoubleClickHandler.AddDoubleClickHandler();
                }
                else
                {
                    Application.SetSystemVariable("DBLCLKEDIT", 1);
                    AppDoubleClickHandler.RemoveDoubleClickHandler();
                }
            }
        }

        private void OnIdle(object sender, EventArgs e)
        {
            var doc = CadApp.DocumentManager.MdiActiveDocument;
            if (doc != null)
            {
                CadApp.Idle -= OnIdle;
                //RibbonHelper.OnRibbonFound(SetupRibbon);
                doc.Editor.WriteMessage("\nCADLibraryMSA loaded.\n");
            }
        }

        public void Terminate()
        {
            _dwgManager.DocumentActivated -= new DocumentCollectionEventHandler(DwgManager_Activated);
            Application.DisplayingOptionDialog -= new TabbedDialogEventHandler(Application_DisplayingOptionDialog);
        }
    }

 

Any help greatly appreciated as I am losing my wits over this. 😞

 

Thanks,

 

Alex.

0 Likes
Message 5 of 8

R.Gerritsen4967
Advocate
Advocate

@AlexFielder ,

 

This is my code to initialize a ribbon:

Public Class GSRibbon
    Implements Autodesk.AutoCAD.Runtime.IExtensionApplication

    Public Sub Initialize() Implements Autodesk.AutoCAD.Runtime.IExtensionApplication.Initialize

        Try
            AddHandler Autodesk.AutoCAD.ApplicationServices.Application.Idle, AddressOf App_Idle

        Catch ex As System.Exception
            Dim doc As Document = Application.DocumentManager.MdiActiveDocument
            Dim ed As Editor = doc.Editor
            ed.WriteMessage(vbLf & "Loading ribbon failed:")
            ed.WriteMessage(vbLf & "{0}", ex.ToString())
        End Try
    End Sub

    Private Sub App_Idle(sender As Object, e As EventArgs)

        RemoveHandler Autodesk.AutoCAD.ApplicationServices.Application.Idle, AddressOf App_Idle

        GSRibbonPanels.GSRibbon()
        AddHandler Autodesk.AutoCAD.Ribbon.RibbonServices.RibbonPaletteSet.WorkspaceLoaded, AddressOf Workspace_Loaded

    End Sub

    Private Sub Workspace_Loaded(sender As Object, e As EventArgs)
        GSRibbonPanels.GSRibbon()
    End Sub

    Public Sub Terminate() Implements Autodesk.AutoCAD.Runtime.IExtensionApplication.Terminate
    End Sub

End Class

 

GSRibbonPanels.GSRibbon() is where I create my ribbonpanels.

 

I'm sorry this is in Visual Basic😁. I just can't get used to C#.

Hope this helps!

0 Likes
Message 6 of 8

AlexFielder
Advisor
Advisor

I appreciate the reply, no matter that it is in VB. 🙂

 

After posting I moved one thing in my code and lo and behold the ribbon now displays reliably.

 

For future-me's sake, here is the  one part of initialization.cs that I changed to get mine to work:

 

private void OnIdle(object sender, EventArgs e)
        {
            var doc = CadApp.DocumentManager.MdiActiveDocument;
            if (doc != null)
            {
                CadApp.Idle -= OnIdle;
                RibbonHelper.OnRibbonFound(SetupRibbon); // < uncommented this line 
                doc.Editor.WriteMessage("\nCADLibraryMSA loaded.\n");
            }
        }

 

🙂

Message 7 of 8

joseguiaCES
Participant
Participant
" .. future me sake .." thats funny
replying to keep this topic and code handy, thank you both for sharing. 😃
0 Likes
Message 8 of 8

AlexFielder
Advisor
Advisor
It's funny because it is true lol - I have lost count the number of times I have hit upon a problem that I have already solved some other time but forgotten about the solution and ended up back in these forums reading my own words.
0 Likes