Eigene Erweiterungen für das Ribbon unter SharePoint 2010 oder 2013, d.h. eigene Buttons, Groups und Tabs welche anhand von CustomAction-Elementen und zugehörigem Feature deployed werden können haben standardmäßig einen Nachteil:
Custom-Action-Elemente für das Ribbon sind standardmäßig kontextsensitiv und an eine bestimmte Liste, einen ContentType oder einen Dateityp gebunden!
“Kontextsensitiv” heißt in diesem Fall das die entsprechenden Ribbon-Elemente welche mit einer CustomAction verknüpft sind nur angezeigt werden falls der Benutzer in der Weboberfläche eine entsprechende Liste bzw. Bibliothek ausgewählt hat.
Standard Ribbon Elemente
Wie diese Verknüpfung Zustande kommt kann man leicht an einer beispielhaften XML/CAML Definition für eine CustomAction für das Ribbon erkennen:
<CustomAction Id="HvBlog.Ribbon.CustomTab" RegistrationType="List" RegistrationId="101" Location="CommandUI.Ribbon"> <CommandUIExtension> <CommandUIDefinitions> <CommandUIDefinition Location="Ribbon.Tabs._children"> <Tab Id="HvBlog.Ribbon.CustomTab" Sequence="300" Description="" Title="Custom Tab"> <Scaling Id="HvBlog.Ribbon.CustomTab.Scaling"> <MaxSize Id="HvBlog.Ribbon.CustomTab.CustomGroup.MaxSize" GroupId="HvBlog.Ribbon.CustomTab.CustomGroup" Size="TwoLarge" /> <Scale Id="HvBlog.Ribbon.CustomTab.CustomGroup.Scaling.CustomTabScaling" GroupId="HvBlog.Ribbon.CustomTab.CustomGroup" Size="TwoLarge" /> </Scaling> <Groups Id="HvBlog.Ribbon.CustomTab.Groups"> <Group Id="HvBlog.Ribbon.CustomTab.CustomGroup" Sequence="10" Title="Custom Group" Description="" Template="HvBlog.Ribbon.Templates.CustomTab"> <Controls Id="HvBlog.Ribbon.CustomTab.CustomGroup.Controls"> <Button Id="HvBlog.Ribbon.CustomTab.CustomGroup.CustomButton" Command="Armstrong.Ribbon.Command.CustomCommand" Sequence="10" LabelText="Custom Button" TemplateAlias="c1" Image32by32="/_layouts/$Resources:core,Language;/images/formatmap32x32.png" Image32by32Top="-96" Image32by32Left="-288" /> </Controls> </Group> </Groups> </Tab> </CommandUIDefinition> <CommandUIDefinition Location="Ribbon.Templates._children"> <GroupTemplate Id="HvBlog.Ribbon.Templates.CustomTab"> <Layout Title="TwoLarge" LayoutTitle="TwoLarge"> <Section Alignment="Top" Type="OneRow"> <Row> <ControlRef DisplayMode="Large" TemplateAlias="c1" /> <ControlRef DisplayMode="Large" TemplateAlias="c2" /> </Row> </Section> </Layout> </GroupTemplate> </CommandUIDefinition> </CommandUIDefinitions> <CommandUIHandlers> <CommandUIHandler Command="Armstrong.Ribbon.Command.CustomCommand" CommandAction="javascript:alert('CustomCommand executed!');" EnabledScript="javascript:return true;" /> </CommandUIHandlers> </CommandUIExtension> </CustomAction>
Wichtig sind hierbei folgende Attribute des CustomAction-Elements:
- RegistrationType
- Gibt die Kontext-Art für die Ribbon-Elemente an
- Mögliche Werte: List, ContentType, ProgId, FileType
- RegistrationId
- Gibt die zum RegistrationType passende ID für die zu verknüpfenden Elemente an
- Mögliche Werte sind List-ID, ContentType-ID etc.
Sind diese Attribute in der Definition angegeben zeigt SharePoint die Ribbon-Elemente wie erwähnt nur im entsprechenden Kontext an, was ja auch dem Konzept des Ribbons entspricht so wie Microsoft es vorgesehen hat um dem Benutzer immer nur relevante Informationen zum aktuellen Inhalt zu liefern.
Es kann aber durchaus Situationen geben in denen ein eigenes Ribbon-Tab durchaus auch ohne den Kontext einer Liste oder eines Eintrags/Dokuments Sinn macht, z.B. Listen-übergreifende Funktionen, Funktionen für Site-Workflows und Funktionen welche nicht direkt von einem bestimmten Website-Inhalt abhängen.
ACHTUNG:
Es ist notwendig ein eigenes Ribbon-Tab zu erstellen da die Standard Ribbon-Tabs von SharePoint alle kontextsensitiv sind und ein Tab als übergeordnetes Element für andere Elemente immer benötigt wird!
Ribbon Delegate-Control
Man könnte meinen dass das Weglassen der oben genannten Attribute in der CustomAction-Definition den gewünschten Effekt hat und das Tab immer im Ribbon anzeigt, aber das ist leider nicht der Fall.
Da Tabs standardmäßig nicht sichtbar sind und erst durch einen entsprechenden Kontext vom System aktiviert werden, müssen wir diese Funktionalität in einer simplen Form für unser Ribbon-Tab selbst implementieren. Dies geschieht am besten mit einem sog. “Delegate-Control”.
Delegate-Controls sind deploybare Controls (also Komponenten mit Server-Side Code) die per CustomAction Definition für einzelne Websites registriert werden können.
Da diese Controls in den meisten Fällen durch die SharePoint Master-Pages ausgeführt werden ist es mit ihnen z.B. möglich Code bei jedem Seitenaufruf einer Website auszuführen. Genau diese Möglichkeit benötigen wir um das Ribbon-Tab global aktiv, also immer sichtbar zu machen.
Die Registrierung eines Delegate Controls besteht aus einer recht kurzen XML/CAML Definition:
<Control Id="AdditionalPageHead" Sequence="90" ControlSrc="~/_controltemplates/HVblog/RibbonManagerControl.ascx" />
Das entsprechende ASP.NET UserControl (oder auch “CONTROLTEMPLATE” wie die Komponenten in SharePoint genannt werden) welches hier beispielhaft “RibbonManagerControl.ascx” genannt wird benötigt nur simplen Code um das Ribbon-Tab pauschal zu aktivieren:
public partial class RibbonManagerControl : UserControl { private const string RIBBON_TAB_ID = "HvBlog.Ribbon.CutomTab"; protected override void OnPreRender(EventArgs e) { base.OnPreRender(e); SPRibbon ribbon = SPRibbon.GetCurrent(Page); if (!ribbon.IsTabAvailable(RIBBON_TAB_ID)) { ribbon.MakeTabAvailable(RIBBON_TAB_ID); } } }
Ergebnis
Wenn nun die CustomAction-Definitionen für die Ribbon-Elemente und das Delegate-Control in einem Feature zusammen deployed und für eine Website oder Site-Collection aktiviert werden ist das entsprechende Ribbon-Tab auf allen Webpages der Website immer zu sehen.
Über den Scope des Features welches die CustomActions deployed kann dann noch bestimmt werden in welchen Bereichen das Ribbon-Tab aktiv ist:
- Web: einzelne Websites
- SiteCollection: alle Websites in einer Site-Collection