using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Autodesk.Windows;
using Autodesk.AutoCAD.Ribbon;
using Autodesk.AutoCAD.ApplicationServices;
namespace LegalDrafting
{
public class LegalDraftingRibbonBuilder
{
private const string TAB_TITLE = "FSJ CAD Tools";
private const string TAB_ID = "FSJ_Custom_Tab";
private const string PANEL_TITLE = "Legal Drafting Tools";
private RibbonControl _ribbonControl;
private RibbonTab _ribbonTab;
private RibbonPanel _ribbonPanel;
private RibbonPanelSource _panelSource;
public LegalDraftingRibbonBuilder()
{
//Create ribbon tab: FSJ_Custom_Tab
_ribbonControl = RibbonServices.RibbonPaletteSet.RibbonControl;
_ribbonTab = GetExistingFSJCadToolsRibbonTab();
if (_ribbonTab == null)
{
//Create new tab
_ribbonTab = new RibbonTab();
_ribbonTab.Title = TAB_TITLE;
_ribbonTab.Id = TAB_ID;
_ribbonControl.Tabs.Add(_ribbonTab);
}
}
public void CreateLegalDraftingRibbonPanel()
{
//get existing or create new ribbon panel
if (GetExistingLegalDraftingRibbonPanel()) return;
//Create new panel, if not exists
_panelSource = new RibbonPanelSource();
_panelSource.Title = PANEL_TITLE;
_ribbonPanel = new RibbonPanel();
_ribbonPanel.Source = _panelSource;
_ribbonTab.Panels.Add(_ribbonPanel);
//Add buttons
RibbonButton button = new RibbonButton();
button.Text = "Legend";
button.CommandParameter = "LegalLegend ";
button.ShowText = true;
button.CommandHandler = new LegalDraftingRibbonCommandHandler();
RibbonToolTip toolTip = new RibbonToolTip();
toolTip.Command = "LegalLegend"; ;
toolTip.Title = "Command: LegalLegend";
toolTip.Content = "Generate legal plan's legend list";
toolTip.ExpandedContent = "Generate legal plan's legend list " +
"by searching drawing content visible in the viewports of layouts";
button.ToolTip = toolTip;
_panelSource.Items.Add(button);
_panelSource.Items.Add(new RibbonRowBreak());
}
#region private methods
private RibbonTab GetExistingFSJCadToolsRibbonTab()
{
//Find existing ribbon tab
foreach (var t in _ribbonControl.Tabs)
{
if (t.Title.ToUpper() == TAB_TITLE.ToUpper() &&
t.Id.ToUpper() == TAB_ID.ToUpper())
{
return t;
}
}
return null;
}
private bool GetExistingLegalDraftingRibbonPanel()
{
//Find existing panel
foreach (var p in _ribbonTab.Panels)
{
if (p.Source.Title.ToUpper() == PANEL_TITLE.ToUpper())
{
_ribbonPanel = p;
_panelSource = p.Source;
return true;
}
}
return false;
}
#endregion
}
public class LegalDraftingRibbonCommandHandler : System.Windows.Input.ICommand
{
public bool CanExecute(object parameter)
{
return true;
}
public event EventHandler CanExecuteChanged;
public void Execute(object parameter)
{
RibbonButton btn = parameter as RibbonButton;
if (btn != null)
{
Document dwg = Autodesk.AutoCAD.ApplicationServices.Application.
DocumentManager.MdiActiveDocument;
dwg.SendStringToExecute((string)btn.CommandParameter, true, false, true);
}
}
}
}
#region IExtensionApplication
public void Initialize()
{
Document dwg = Application.DocumentManager.MdiActiveDocument;
Editor ed = dwg.Editor;
try
{
ed.WriteMessage("\nLoading legal drafting utility...");
//Get database connection
_connectionString = SetConnectionString();
//Load ribbon panel for legal drafting command access
Autodesk.AutoCAD.Ribbon.RibbonServices.RibbonPaletteSetCreated +=
new EventHandler(RibbonServices_RibbonPaletteSetCreated);
}
catch(System.Exception ex)
{
ed.WriteMessage("\nLoading legal drafting utility loaded failed:");
ed.WriteMessage("\n{0}", ex.ToString());
}
Autodesk.AutoCAD.Internal.Utils.PostCommandPrompt();
}
private void RibbonPaletteSet_Loaded(object sender, EventArgs e)
{
LoadLegalDraftingRibbonPanel();
}
private void RibbonServices_RibbonPaletteSetCreated(object sender, EventArgs e)
{
Autodesk.AutoCAD.Ribbon.RibbonServices.RibbonPaletteSet.Loaded +=
new EventHandler(RibbonPaletteSet_Loaded);
}
private static void LoadLegalDraftingRibbonPanel()
{
Editor ed = null;
Document dwg = Application.DocumentManager.MdiActiveDocument;
if (dwg != null) ed = dwg.Editor;
try
{
LegalDraftingRibbonBuilder rib = new LegalDraftingRibbonBuilder();
rib.CreateLegalDraftingRibbonPanel();
if (ed != null)
{
ed.WriteMessage("\nFSJ Custom CAD ribbon tab loaded.");
}
}
catch (System.Exception ex)
{
if (ed != null)
{
ed.WriteMessage("\nLoading FSJ Custom CAD ribbon tab failed\n{0}.", ex.ToString());
}
}
}
public void Terminate()
{
}
#endregion
Methinks 'the best way' of loading one's assembly should depend on the nature of the code... You don't want to NETLOAD an assembly that hooks RibbonServices.RibbonPaletteSetCreated Event to fully initialize, as by the time you're able to enter NETLOAD that event has already come and gone.
There seems to be a lot of confusion about ribbon initialization. It's pretty simple, and you don't have to concern yourself with how/when your app is loaded.
If when your app is loaded, the ribbon exists, then you add a handler to the Application.Idle event, and the first time the event fires, you remove the Idle event handler so it doesn't fire again, and you initialize your ribbon components.
If upon loading of your app the ribbon doesn't exist, then you hook the RibbonPalleteSetCreated event. If/when that event fires, you add a handler to the Application.Idle event, and when that event fires, remove that handler from the Idle event and initialize your ribbon components.
So, in all cases, you are doing initialization in a handler for the Idle event, and the only question is when to add the Idle event handler, which depends on whether the ribbon exists when your app is loaded.
I haven't seen a case where that fails, including when the ribbon exists but is not visible. If there is some issue with the initializing your ribbon components when the ribbon isn't visible, I'd like to know about it, as that would seem to be the only possible gotcha in this case.
n.yuan, thank you for your reply... I am in the process of testing that now, but seem to be having some Autoloader-specific trouble. More on that below.
Continuation from another thread here:Methinks 'the best way' of loading one's assembly should depend on the nature of the code... You don't want to NETLOAD an assembly that hooks RibbonServices.RibbonPaletteSetCreated Event to fully initialize, as by the time you're able to enter NETLOAD that event has already come and gone.
There seems to be a lot of confusion about ribbon initialization. It's pretty simple, and you don't have to concern yourself with how/when your app is loaded.
If when your app is loaded, the ribbon exists, then you add a handler to the Application.Idle event, and the first time the event fires, you remove the Idle event handler so it doesn't fire again, and you initialize your ribbon components.
If upon loading of your app the ribbon doesn't exist, then you hook the RibbonPalleteSetCreated event. If/when that event fires, you add a handler to the Application.Idle event, and when that event fires, remove that handler from the Idle event and initialize your ribbon components.
So, in all cases, you are doing initialization in a handler for the Idle event, and the only question is when to add the Idle event handler, which depends on whether the ribbon exists when your app is loaded.
I haven't seen a case where that fails, including when the ribbon exists but is not visible. If there is some issue with the initializing your ribbon components when the ribbon isn't visible, I'd like to know about it, as that would seem to be the only possible gotcha in this case.
Firstly, thank you Tony for confirming what I have experienced via Application.Idle event's success.
When only evaluating if a RibbonTab is successfully created, the code works fine, but is not able to accommodate the Autoloader requirement I am trying to meet by adding said RibbonTab prior to other partial CUIx being loaded into UI.
I have tried both, adding the RibbonTab to ComponentManager.Ribbon, and directly to Main CUIx & nested Workspaces as shown here (http://autodesk.lithium.com/t5/AutoCAD-2011/common-ribbontab-in-different-partial-cui/m-p/3409873#M22793)... In both cases, I end up with non-Combined RibbonTabs with common Tab ID's.
What I am finding is that simply adding a RibbonTab to ComponentManager.Ribbon is irrelevant (for the purposes of Partial CUIx), and adding to Main CUI is required. However, given startup sequence, my doing so is still not successful as is done after Autoloader has loaded partial CUIx.
Put simply, what I am attempting to achieve, is to have sufficient code such that a 'root' RibbonTab is added (seemingly to Main CUIx) prior to partial CUIx added via Autoloader... I'm even okay with changing the CUIx component within PackageContents.xml to not load on startup, and instead by CommandInvocation, where the 'add root RibbonTab' snippet would end with SendStringToExecute if necessary... My problem is getting it to actually work.
If I absolutely have to implement RibbonTab & RibbonPanels via code, it's possible, but I'd like to avoid if reasonably possible... It's important to me to supply CUIx for user's ability to customize Workspace to their liking. This 'model' is something I am trying to work out for both internal purposes (i.e., 'root' company RibbonTab, with basic items, supplemented by Sector / Discipline-specific Partials being added), as well as Autodesk Exchange Autoloader (i.e., multiple, small plug-ins, that load individual RibbonPanels to same 'root' RibbonTab).
Perhaps I shouldn't be surprised, but given the enthusiasm with which Autodesk is 'pushing' Autoloader, one might expect that this Main CUIx requirement would have a workaround by now... Perhaps that's my naivete.
So there it is, Tony... Just like with AutoCAD Security, the only 'gotcha' I've found, is Autoloader.
As always, any insight would be most helpful.
Cheers