Skip to content
This repository has been archived by the owner on Sep 4, 2024. It is now read-only.

Extension Points

slluis edited this page Nov 20, 2014 · 3 revisions
Home > Reference Manual > Description of Add ins and Add in Roots > 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");
	}
}

Multiple extension points for a single type

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
{ ... }

Extension metadata

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.

Generic extension points

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>

Extension points with multiple extension nodes

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>

Declaration using an XML manifest

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).

Clone this wiki locally