Update on project
I started this thread partly to document my progress as I was starting to improve my C# skills (long way to go yet!) but also in an effort to help others overcome what looked like a steep learning curve for Alibre AddOn development by sharing what I discovered.
Here are a few notes on what I have found so far.. Just what I think important.
1 The Alibre documentation is not good! It does not provide any detail of many important interfaces that need to be implemented in order to develop a properly integrated AddOn.
2 Knowledge of the following files and interfaces is essential:
AddOn.adc.
(see my UtilitiesForAlibre.adc)
This is an XML text file. The Alibre documentation appears to be correct unless you want to develop using C# in which case, you MUST add the directive type="Managed" in the DLL section.
AlibreAddOn.cs (see my AlibreAddOn.cs)
This class is the main link between Alibre and your custom AddOn. It MUST have the class name "AlibreAddOn" and MUST be in the namespace "AlibreAddOnAssembly". To date, I have only implemented the AddOnLoad method where I initialise my custom implementation of IAlibreAddOn. The AlibreAddOn also requires a method (not documented by Alibre) "public static IAlibreAddOn GetAddOnInterface()". This method should return your custom implementation of IAlibreAddOn (in my code this is the UtilitiesForAlibre class.
IAlibreAddOn (see my UtilitiesForAlibre)
This interface is where you add menus to your AddOn that will show up in the Alibre menu and tool bar. You will need to implement this interface (see my implementation UtilitiesForAlibre).
Launching of your UserControl is done in the public IAlibreAddOnCommand InvokeCommand(int menuID, string sessionIdentifier) method.
If like me you want several menu items, just use a switch statement to call routines that launch your UserControl in response to an individual menu.
There are a few traps to be aware of when launching a new UserControl. These all hinge around the need to clean up when you are done with a control and not to launch a control twice in the same Alibre design window. There are of course multiple ways this can be achieved but I chose to have each menu open/close he relevant control. To keep track of opened controls, I use a Dictionary<string, IAddOnCommand> for each control. When a control is launched, entry is added to the dictionary with the string being the current session identifier and the IAddOnCommand being the name of your implementation of IAddOnCommand for that control. When a control is closed, the entry is removed from the Dictionary. There is also a need to take care of the situation of the Alibre design window being closed while the control is still open. I took care of this by adding an event to my implementation of IAddOnCommand which is called in the IAddOnCommand.OnTerminate() method. The listener for this event is in IAlibreAddOn and simply removes and entry from the Dictionary.
IAlibreAddOnCommand (see my EmptyAddOnCommand for a simple example)
An implementation of this interface allows you to get information from the Alibre Design window. So, if you want your control to 'know' when you select a plane or sketch or what button you have clicked this is where you do it. Your implementation of this interface is also responsible for instantiating your UserControl and adding it to a panel in the Alibre Design window. There are a few methods here where some care is needed.
Constructor
C#:
public EmptyAddOnCommand(IADSession session)
{
this.session = session; // a reference to the current design session
PanelPosition = (int) ADDockStyle.AD_RIGHT; // where do you want the docked panel
EmptyUserControl = new EmptyUserControl(session); // finally get to create your user control
}
DockedPanelHandle
C#:
/// <summary>
/// Get/Set the PanelHandle
/// set adds the User control to the Parent, docks and autosizes.
/// </summary>
public virtual long DockedPanelHandle
{
get => PanelHandle;
set
{
Debug.WriteLine(value);
if (value != (long) IntPtr.Zero)
{
var control = Control.FromHandle((IntPtr) value);
if (control != null)
{
EmptyUserControl.Parent = control;
EmptyUserControl.Dock = DockStyle.Fill;
EmptyUserControl.AutoSize = true;
EmptyUserControl.Show();
control.Show();
PanelHandle = value;
}
}
}
}
Terminate event - invoked in OnTerminate()
C#:
public event EventHandler<EmptyAddonCommandTerminateEventArgs> Terminate;
OnTerminate.. do some clean up
C#:
/// <summary>
/// Called when Alibre terminates the add-on command; add-on should make sure to release all references to its CommandSite
/// </summary>
/// <exception cref="NotImplementedException"></exception>
public void OnTerminate()
{
Debug.WriteLine("OnTerminate");
WriteToUserControl("OnTerminate");
if (EmptyUserControl != null) EmptyUserControl.Dispose();
if (CommandSite != null)
{
CommandSite.RemoveDockedPanel(DockedPanelHandle);
DockedPanelHandle = (long) IntPtr.Zero;
CommandSite = null;
}
EmptyAddonCommandTerminateEventArgs args = new EmptyAddonCommandTerminateEventArgs(this);
Terminate.Invoke(this, args);
}
OnComplete() This is where the DockedPanelHandle IntPtr is generated
C#:
/// <summary>
/// Called when Alibre has successfully initiated this command; gives it a chance to perform any initializations
/// </summary>
/// <exception cref="NotImplementedException"></exception>
public void OnComplete()
{
Debug.WriteLine("OnComplete Starting");
WriteToUserControl("OnComplete Starting");
try
{
DockedPanelHandle = CommandSite.AddDockedPanel(PanelPosition, "Empty Add On");
}
catch (Exception ex)
{
var num = (int) MessageBox.Show(ex.ToString(), Application.ProductName, MessageBoxButtons.OK,
MessageBoxIcon.Exclamation);
throw ex;
}
Debug.WriteLine("OnComplete Done");
WriteToUserControl("OnComplete Done");
}
UserRequestedClose() More clean up code...
C#:
/// <summary>
/// Actions to take when closing
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
public void UserRequestedClose()
{
EmptyUserControl.Dispose();
CommandSite.RemoveDockedPanel(DockedPanelHandle);
DockedPanelHandle = (long) IntPtr.Zero;
CommandSite = null;
}
Sample code
Copies of source code is available on GitHub here:
UtilitiesForAlibre
I use Jetbrains Rider but Visual Studio should wok OK if you want to work with my code.
As of writing, the code is at version 1.0.0.6
I would like to thank all Alibre forum members for their encouragement and particularly simonb65 for helpful hints and tips.
A compiled copy of my AddOn is attached. If you want to try out, you need to extract the files into directory Alibre Design/Program/Addons/UtilitiesForAlibre
That's all for now but I'm sure to make changes - and will accept all (constructive) criticism and suggestions for new features.
David