-
Notifications
You must be signed in to change notification settings - Fork 96
Extension Points
Extension points can be declared in an assembly using the following attributes:
- [Mono.Addins.TypeExtensionPoint]: applied to a type, declares an extension point bound to that type.
- [Mono.Addins.ExtensionPoint]: applied to an assembly, declares a generic extension point in that assembly.
Both attributes have the same properties (all are optional)
Property | Description |
---|---|
Path | Extension path that identifies the extension point |
Name | Display name of the extension point |
Description | Long description of the extension point |
NodeName | Element name to be used when defining an extension in an XML manifest. The default name is "Type". |
NodeType | Type of the extension node to be created for extensions. See the Custom Extension Node Types section for more details. |
ExtensionAttributeType | Type of the custom attribute to be used to specify metadata for the extension point |
Here is a basic example which declares an extension point bound to the ICommand interface:
[TypeExtensionPoint]
public interface ICommand
{
void Run ();
}
This extension point would allow defining command extensions like this:
[Extension]
public class HelloCommand: ICommand
{
public void Run ()
{
Console.WriteLine ("Hello World");
}
}
It is possible to declare several extension points for a single type. In this case, the Path property has to be used to identify each extension point. For example:
[TypeExtensionPoint (Path="/Commands/RegularCommands")]
[TypeExtensionPoint (Path="/Commands/SpecialCommands")]
public interface ICommand
{
void Run ();
}
Extensions for each extension point can then be declared like this:
[Extension ("/Commands/RegularCommands")]
public class HelloCommand: ICommand
{ ... }
[Extension ("/Commands/SpecialCommands")]
public class SomeSpecialCommand: ICommand
{ ... }
The ExtensionAttributeType property specifies a custom attribute to be used for declaring extensions for this extension point. This attribute can also be used to define custom metadata for the extensions. For example:
[TypeExtensionPoint (ExtensionAttributeType=typeof(CommandAttribute))]
public interface ICommand
{
void Run ();
}
public class CommandAttribute: CustomExtensionAttribute
{
public CommandAttribute ()
{
}
public CommandAttribute ([NodeAttribute ("Label")] string label)
{
Label = label;
}
[NodeAttribute]
string Label { get; set; }
}
This extension point would allow defining command extensions like this:
[Command ("Hello")]
public class HelloCommand: ICommand
{
public void Run ()
{
Console.WriteLine ("Hello World");
}
}
The custom attribute type has to follow some basic rules:
- It must be a subclass of Mono.Addins.CustomExtensionAttribute.
- The class must have a default constructor.
- There must be a read/write property or a field for each metadata value. This property or field must have the [NodeAttribute] attribute applied to it.
- If the class has a constructor that sets some properties or fields, each parameter must have a [NodeAttribute (name)] attribute applied to it. The 'name' specified in the attribute must be one of the metadata properties or fields.
A generic extension point is not bound to any particular type and can be used, for example, to declare data extensions:
[assembly:ExtensionPoint ("/TextEditor/Templates", NodeName="Template", ExtensionAttributeType=typeof(TemplateAttribute)]
public class TemplateAttribute: CustomExtensionNode
{
public string File { get; set; }
}
An extension for this extension point can be declared like this:
[assembly:Template (File="Letter.txt")]
[assembly:Template (File="Fax.txt")]
Or the same, using an XML manifest:
<ExtensionModel>
<Extension path="/TextEditor/Templates">
<Template File="Letter.txt"/>
<Template File="Fax.txt"/>
</Extension>
</ExtensionModel>
It is possible to define extension points which accept several types of extensions. This can be done by defining several [ExtensionPoint] attributes on the same extension path. For example:
[assembly:ExtensionPoint ("/TextEditor/ToolbarButtons", Name="Main toolbar", NodeName="Button", ExtensionAttributeType=typeof(ToolButtonAttribute)]
[assembly:ExtensionPoint ("/TextEditor/ToolbarButtons", NodeName="Separator", ExtensionAttributeType=typeof(ToolSeparatorAttribute)]
public class ToolButtonAttribute: CustomExtensionAttribute
{
[NodeAttribute]
string Icon { get; set; }
[NodeAttribute]
string Label { get; set; }
}
public class ToolSeparatorAttribute: CustomExtensionAttribute
{
}
The above example would allow a toolbar to be defined using custom attributes like this:
[assembly:ToolButton (Id="OpenCmd", Icon="open.png" Label="Open File")]
[assembly:ToolButton (Id="NewCmd", InsertAfter="OpenCmd" Icon="new.png" Label="New File")]
[assembly:ToolSeparator (Id="Separator1", InsertAfter="NewCmd")]
[assembly:ToolButton (Id="CloseCmd", InsertAfter="Separator1" Label="Close")]
Or the same, using an XML manifest:
<ExtensionModel>
<Extension path="/TextEditor/ToolbarButtons">
<Button Id="OpenCmd" Icon="open.png" Label="Open File" />
<Button Id="NewCmd" Icon="new.png" Label="New File" />
<Separator />
<Button Id="CloseCmd" Label="Close" />
</Extension>
</ExtensionModel>
Let's see how an extension point can be declared in an XML manifest using an example which would allow extending the toolbar of a Text Editor application:
<Addin namespace="TextEditor" id="Core" version="1.0" isroot="true">
...
<ExtensionPoint path="/TextEditor/ToolbarButtons" name="Main toolbar">
<Description>Main toolbar of the editor. Extensions can register here new buttons.</Description>
<ExtensionNode name="ToolButton" type="TextEditor.ToolButtonNode">
<Description>Registers a new button in the toolbar</Description>
</ExtensionNode>
<ExtensionNode name="ToolSeparator" type="TextEditor.ToolSeparatorNode">
<Description>Adds a new separator to the toolbar</Description>
</ExtensionNode>
</ExtensionPoint>
...
</Addin>
The following table describes the attributes and elements shown above:
XML | Description |
---|---|
/Addin/ExtensionPoint | The root element for extension points |
/Addin/ExtensionPoint/@path | Path of the extension point. |
/Addin/ExtensionPoint/@name | Display name of the extension point (to be shown in documentation). |
/Addin/ExtensionPoint/Description | Long description of the extension point. |
/Addin/ExtensionPoint/ExtensionNode | A type of node allowed in this extension point. |
/Addin/ExtensionPoint/ExtensionNode/@name | Name of the node type. When an element is added to an extension point, its name must match one of the declared node types. |
/Addin/ExtensionPoint/ExtensionNode/@type | CLR type that implements this extension node type. It must be a subclass of Mono.Addins.ExtensionNode. If not specified, by default it is Mono.Addins.TypeExtensionNode. |
/Addin/ExtensionPoint/ExtensionNode/Description | Description of what this kind of node represents. |
An extension point may accept several kinds of nodes at the same time, as long as all node types have a different name. The ''name'' attribute specifies the node name to use when extenders want to register an new node. The ''type'' attribute specifies the CLR class that will handle nodes of that type. That is, there will be one ''TextEditor.ToolButtonNode'' instance for each node registered with the name ''ToolButton'' (the next chapter explains how to create such node classes).
The node class also determines the attributes that can be used in a node. For example, in a toolbar button, it will allow specifying the name of the icon, or the command that must be run when clicking the button.
It is not mandatory to specify the name of an extension node. When not provided, a default name obtained from the node type implementation will be used (see Default node name and description).
- Extension Points and Extensions
- Querying Extension Points
- Type Extension Metadata
- Data-only Extension Points
- Data Files and Resources
- About Lazy Loading
- Thread Safety
- The Add-in Registry
- Addin Discovery
- Creating and Managing Add-in Packages
- Advanced Concepts