|
Eriq VanBibber
Guest
|
I'm trying to create a modular set of addins. Each feature will be hosted by a separate .net assembly.
I'd like to have a button from ProjectA get added to the same ribbon group as ProjectB.
Is this possible? i have tried simply setting the ribbon group ID to the same value, but then nothing shows. |
|
Posted 02 Oct, 2019 19:36:18
|
|
Top
|
|
Andrei Smolin
Add-in Express team
Posts: 18829
Joined: 2006-05-11
|
|
Posted 03 Oct, 2019 02:12:12
|
|
Top
|
|
Eriq VanBibber
Guest
|
andrei,
thanks for that pointer.
however, it doesn't seem to apply to my case.
i will have a "master" addin for which several "sub-addins" can be installed/added after the main addin has been installed. the "plugin for the plugin" type of thing.
So, i have this separate assembly that is simply an ADXAddinAdditionalModule. Then, i add this to the "Modules" property of the main addin. (though, i don't yet know how to do this at runtime).
So, how would i have a button in my "additional module" merge into an existing ribbon group from the main addin?
Does my question make sense?
Regards,
Eriq |
|
Posted 04 Oct, 2019 18:46:37
|
|
Top
|
|
Andrei Smolin
Add-in Express team
Posts: 18829
Joined: 2006-05-11
|
Hello Eriq,
You are right: I was pointing to a wrong direction. I've tested this and found that having an ADXRibbonTab on the add-in module or on an additional module generates a separate XML tab element whatever the settings are. This is by design, unfortunately. A way to solve this would be to intercept the BeforeRibbonCreate event of the add-in module and do the following:
- Identify the target Ribbon container (tab or group) that will have a combined set of controls.
- Identify the source Ribbon container providing Ribbon controls on the additional module.
- Move the Ribbon components from the source container to the target container.
- Delete the source container.
The last step is required because right after raising the BeforeRibbonCreate event, Add-in Express copies Ribbon tabs from the additional module to the main one.
Andrei Smolin
Add-in Express Team Leader |
|
Posted 07 Oct, 2019 05:53:05
|
|
Top
|
|
Eriq VanBibber
Guest
|
Ok. I had already thought about that before creating this thread. however, i didn't know about that last part - 'delete the source container'.
yet...how to do this? I see in the designer file that the ribbon tab control is added to the 'components' variable.
Remove it from there?
i have tried disposing of the tab, setting it to null, and removing it from the components collection, but all cases give me an exception with something about GetAttributes.
-Eriq |
|
Posted 07 Oct, 2019 12:05:59
|
|
Top
|
|
Andrei Smolin
Add-in Express team
Posts: 18829
Joined: 2006-05-11
|
Hello Eriq,
foreach (var item in this.components.Components)
{
System.Diagnostics.Debug.WriteLine("!!! " + item.ToString());
}
In a sample add-in, this prints the following:
[29872] !!! [AddinExpress.MSO.ADXRibbonTab]
[29872] !!! [AddinExpress.MSO.ADXRibbonGroup]
[29872] !!! [AddinExpress.MSO.ADXRibbonButton]
The following code fragment is from https://www.add-in-express.com/creating-addins-blog/2012/01/20/load-office-addin-on-condition/:
private void RemoveComponents()
{
for (int i = this.components.Components.Count - 1; i >= 0; i--)
this.components.Remove(this.components.Components[i]);
}
Eriq VanBibber writes:
all cases give me an exception with something about GetAttributes
Please provide details.
Andrei Smolin
Add-in Express Team Leader |
|
Posted 08 Oct, 2019 01:14:17
|
|
Top
|
|
Eriq VanBibber
Guest
|
Ok. Clearly i'm missing something. I followed similar logic as what you provided.
Here's my code:
Private Sub AddinModule_OnRibbonBeforeCreate(sender As Object, ribbonId As String) Handles Me.OnRibbonBeforeCreate
For Each modu In Me.Modules.OfType(Of ADXAddinAdditionalModuleItem)
If modu.Module IsNot Nothing AndAlso modu.ModuleProgID = "PTFO_MessageHeaderViewer.PTO_MessageHeaderViewer" Then
Dim ribbon As ADXRibbonTab
ribbon = modu.Module.GetContainer.Components.OfType(Of IComponent).FirstOrDefault(Function(__) TypeOf __ Is ADXRibbonTab)
While ribbon IsNot Nothing
modu.Module.GetContainer.Remove(ribbon)
While ribbon.Controls.Count
Dim grp = ribbon.Controls(0)
grp.AsRibbon.ADXModule = Me
ribbon.Controls.RemoveAt(0)
tabPTO.Controls.Add(grp)
End While
modu.Module.GetContainer.Remove(ribbon)
ribbon = modu.Module.GetContainer.Components.OfType(Of IComponent).FirstOrDefault(Function(__) TypeOf __ Is IADXRibbonComponent)
End While
Dim rc As IADXRibbonComponent
rc = modu.Module.GetContainer.Components.OfType(Of IADXRibbonComponent).FirstOrDefault
While rc IsNot Nothing
modu.Module.GetContainer.Remove(rc)
End While
For Each grp In GetContainer.Components.OfType(Of ADXRibbonTab)
grp.AsRibbon.ADXModule = Me
Next
End If
Next
End Sub
What i find is that after this method completes, i get a startup exception.
From what i can gather, the 'ProcessChildren' method is calling a 'GetAttributes' method that is failing with a null-ref exception.
using reflection, i find that the ADXRibbonGroup.GetAttributes method could fail here:
protected override SortedList GetAttributes()
{
SortedList sortedLists = new SortedList();
IADXRibbonComponent asRibbon = base.AsRibbon;
if (!this.shared)
{
sortedLists["getVisible"] = "getVisible_Callback";
if (this.IdMso == string.Empty)
{
if (asRibbon.ADXModule.Namespace == string.Empty) // <== This throws the error because ADXModule is null!
{
sortedLists["id"] = asRibbon.Id;
}
else
{
sortedLists["idQ"] = string.Concat("default:", asRibbon.Id);
}
...
// other code follows here.
Here's the full error text reported:
Detailed technical information follows:
---
Date and Time: 10/8/2019 10:53:36 AM
Machine Name: XXXXXXXXX
IP Address: XX.XX.XX.XX
Current User: XXXXXXXXXxx
Application Domain: C:ProjectsTFSOverlookOutlookToolsForPowerUsersinDebug
Assembly Codebase: file:///C:/Windows/assembly/GAC_MSIL/AddinExpress.MSO.2005/9.4.4644.0__4416dd98f0861965/AddinExpress.MSO.2005.dll
Assembly Full Name: AddinExpress.MSO.2005, Version=9.4.4644.0, Culture=neutral, PublicKeyToken=4416dd98f0861965
Assembly Version: 9.4.4644.0
Exception Source: AddinExpress.MSO.2005
Exception Type: System.NullReferenceException
Exception Message: Object reference not set to an instance of an object.
Exception Target Site: GetAttributes
---- Stack Trace ----
AddinExpress.MSO.ADXRibbonGroup.GetAttributes()
AddinExpress.MSO.2005.dll: N 0474 (0x1DA) IL
AddinExpress.MSO.ADXRibbonCustomControl.AddinExpress.MSO.IADXRibbonComponent.get_Attributes()
AddinExpress.MSO.2005.dll: N 0000 (0x0) IL
AddinExpress.MSO.ADXAddinModule.ProcessChildren(xmlData As XmlTextWriter, ribbonElement As IADXRibbonComponent, ribbonID As String, uniqueId As Int32, ribbonControl As IRibbonControl)
AddinExpress.MSO.2005.dll: N 0088 (0x58) IL
AddinExpress.MSO.ADXAddinModule.ProcessChildren(xmlData As XmlTextWriter, ribbonElement As IADXRibbonComponent, ribbonID As String, uniqueId As Int32, ribbonControl As IRibbonControl)
AddinExpress.MSO.2005.dll: N 0359 (0x167) IL
AddinExpress.MSO.ADXAddinModule.AddinExpress.MSO.IRibbonExtensibility.GetCustomUI(RibbonID As String)
AddinExpress.MSO.2005.dll: N 1704 (0x6A8) IL
|
|
Posted 08 Oct, 2019 12:53:25
|
|
Top
|
|
Andrei Smolin
Add-in Express team
Posts: 18829
Joined: 2006-05-11
|
Hello Eriq,
Private Sub AddinModule_OnRibbonBeforeCreate(sender As Object, ribbonId As String) Handles MyBase.OnRibbonBeforeCreate
For Each aModuleItem As AddinExpress.MSO.ADXAddinAdditionalModuleItem In Me.Modules
If aModuleItem.Module IsNot Nothing AndAlso aModuleItem.ModuleProgID = "ClassLibrary1.AddinAdditionalModule1" Then
Dim componentsToMove As List(Of IComponent) = New List(Of IComponent)()
Dim sourceContainer As IContainer = aModuleItem.Module.GetContainer
Dim targetContainer As IContainer = Me.GetContainer
Dim sourceTab As ADXRibbonTab = Nothing
Dim targetTab = Me.AdxRibbonTab1
For Each aComponent As IComponent In sourceContainer.Components
If TypeOf aComponent Is ADXRibbonTab Then
sourceTab = CType(aComponent, ADXRibbonTab)
Exit For
End If
Next
For Each aComponent As IComponent In sourceContainer.Components
If TypeOf aComponent Is IADXRibbonComponent Then
Dim cmp As IADXRibbonComponent = CType(aComponent, IADXRibbonComponent)
If cmp IsNot sourceTab Then
componentsToMove.Add(aComponent)
End If
End If
Next
For Each item As IComponent In componentsToMove
If TypeOf item Is IADXRibbonComponent Then
Dim cmp As IADXRibbonComponent = CType(item, IADXRibbonComponent)
If cmp.Root Is sourceTab Then
cmp.ADXModule = Me
End If
If TypeOf cmp Is ADXRibbonGroup Then
sourceTab.Controls.Remove(CType(cmp, ADXRibbonGroup))
targetTab.Controls.Add(CType(cmp, ADXRibbonGroup))
End If
End If
sourceContainer.Remove(item)
targetContainer.Add(item)
Next
sourceContainer.Remove(sourceTab)
End If
Next
End Sub
Andrei Smolin
Add-in Express Team Leader |
|
Posted 09 Oct, 2019 08:46:41
|
|
Top
|
|
Eriq VanBibber
Guest
|
Thanks!!!
It seems the component.Root thing was something i missed and didn't know about.
Regards,
Eriq |
|
Posted 09 Oct, 2019 10:47:54
|
|
Top
|
|
Andrei Smolin
Add-in Express team
Posts: 18829
Joined: 2006-05-11
|
Welcome!
Andrei Smolin
Add-in Express Team Leader |
|
Posted 10 Oct, 2019 02:37:00
|
|
Top
|
|