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.