◷ Reading Time: 10 minutes
In FlexRule, it is very easy to customize the behaviour of different editors in Rule Designer.
For this tutorial, we are going to introduce a custom activity node to the flow editor.
Steps
There are a couple of steps that need to be taken in order to create and register a new custom node in the designer.
- Creating item builder
- Creating toolbox
- Defining object model to be displayed in the property window
- Creating custom activity
- Registering custom activity
Required Assembly References
When you create a custom activity project you need to reference the following assemblies in your project:
- FlexRule.Designer.Common
- FlexRule.Designer.Controls
- FlexRule.Designer.Controls.Toolbox
- FlexRule.Designer.Core
- FlexRule.Designer.FlowEngine
For Shapes you also need to reference the following assembly:
- MindFusion.Diagramming
Creating item builder
An item builder is a class that is responsible for:
- Building an object model associated with your node in an editor
- Loading properties from a model to a defined object model
- Attaching the item to the editor when it is built
- Validating an item
- Saving an item
In order to create a builder, you simply need to override a class named ElementItemBuilderBase and then override the following methods:
/// This is the main class used to create the rule node command /// For example, this will be created by the builder strategy (NotifElementItemBuilder) public abstract class ElementItemBuilderBase { /// <summary> /// Create the properties for the item /// </summary> /// <param name="ctx">Context information related to the builder</param> public abstract void InitializePropertyCollection(BuildContext ctx); /// <summary> /// When a rule node is being loaded, this method will be used to assign the property's value /// </summary> /// <param name="node"></param> public abstract void AssignAttributes(XmlNode node); /// <summary> /// Indicates if there are any custom child needs to be created. Return false as default. /// </summary> /// <param name="node"></param> public abstract bool ShouldCreateChild(string childName); /// <summary> /// When a node is being created and attached to the document /// </summary> /// <param name="creator">node creator</param> /// <param name="parent">parent of the node to be created</param> /// <param name="reference">reference node to the one that is being created</param> /// <param name="position">position of the node to be created</param> /// <returns></returns> public abstract IElementItem Attach(ILogicalDocumentCreator creator, IElementItem parent, IElementItem reference, Position position); /// <summary> /// Override the behaviour for validating nodes /// </summary> /// <param name="context"></param> /// <param name="item"></param> public abstract void ValidateItem(ElementItemValidationContext context, IElementItem item); /// <summary> /// Writes the content of the rule node via the the xml writer /// </summary> /// <param name="document">The document logic has all the element builders of the rule </param> /// <param name="name">name of the file</param> /// <param name="extension">file extension, .help.xml is for the designer help and .xml is for the rule</param> /// <param name="writer"></param> public abstract void WriteContent(ILogicalDocument document, string name, string extension, XmlWriter writer); /// <summary> /// Properties of the object model for which the builder is responsible. /// </summary> public DynamicPropertyCollection Properties { get; protected set; } }
Creating toolbox
The next step is to define Group and Command (custom node) in the toolbox.

Defining a command on the toolbox is as easy as implementing an interface named IToolBoxInitializer.
/// <summary> /// Implement initializer for the toolbox that allows toolbox items be created /// </summary> public interface IToolBoxInitializer { /// <summary> /// Initialize commands on the toolbox /// </summary> /// <param name="toolBoxBuilder"></param> void Initialize(IToolBoxWindowBuilder toolBoxBuilder); /// <summary> /// Stores and reads the next available toolbox (if required) /// <remarks>Implement this as an auto property.</remarks> /// </summary> IToolBoxInitializer Next { get; set; } }
With the argument that the Initialize method provides, you can create groups and commands on the toolbox. To add a group, for example, you can use:
toolBoxBuilder.ToolBox.Groups.Add("Custom", new ToolboxGroup("Custom"));
And to add a command, for example:
ToolboxGroup windowsFormsGroup = toolBoxBuilder.ToolBox.Groups["Custom"]; windowsFormsGroup.Items.Add(new ToolboxItem(Commands.Notif, ImageKeyNotif, new string[] { "Activity", Commands.Notif }, true));
Defining object model
Each builder (e.g., NotifElementItemBuilder) would have an implemented method called:
public override void InitializePropertyCollection(BuildContext ctx)
This is where your application gets a chance to register the model object properties to be added into the Properties Window. BuildContext gives you information about:
- Where does this command belong?
- What is the command name?
- What is the parent item or builder?
When an item is added to a document or an item is selected from a document editor, the Properties Window shows that item with a list of all available properties. The Property window then allows the user to modify the values of the selected item. There are multiple different types of view that Property windows allow you to create:
- Simple
- Collection
- Nested

Simple Properties
Simple properties are just a name and value of a specific type (e.g., string, int, enum, etc.). To add a simple property/value you just need to AddProperty to Properties. If Properties is null then you need to instantiate it first. To add a name/value to it, you can simply use a code like this:
// Creates a string property named 'id' with null default value that the display title is '(id)' Properties.AddProperty("id", null, typeof(string)).DisplayName = "(id)"; // And similarly for description Properties.AddProperty("Description", string.Empty, typeof(string), "Any description related to this command").DisplayName = "(Description)"; Properties["Description"].AllowEnterValue = true;
Collection of Properties
Now when you want a collection of some other properties, you add the property similarly. However, instead of setting a simple type for a name/property, you use
typeof(List<DynamicPropertyCollection>)
as the type. This makes the Properties window automatically launch a collection editor. For example, let’s say we want a collection of strings that is called Messages
var messagesProperty = Properties.AddProperty("Messages", null, typeof(List<DynamicPropertyCollection>));
That sets up the collection editor. In the collection editor, there will be a similar structure to edit messages. In order to set up that structure, you need use ListManager.Schema from Messages property (in this example).
messagesProperty.ListManager.Schema.AddProperty("Message", null, typeof(string)).DisplayName = "Title";
What happens at this point is that when the collection editor is launched, it allows you to modify the list of objects that has one property called Message displayed as Title.
Nested Properties
For nested properties, you need to create an instance of DynamicPropertyCollection and add all of the properties to this collection, then pass that instance to a DynamicObject
// Creates a collection to hold all of the nested properties var collection = new DynamicPropertyCollection(); collection.AddProperty("uri", null, typeof(string)); // Create a dynamic object using the initialised properties var nestedProperty = new DynamicObject("", collection); // And add the nestedProperty to the 'Properties' in the builder Properties.AddProperty("ProcSource", nestedProperty, typeof(DynamicObject)).DisplayName = "ProcSource";
Creating custom activity
A custom activity in a flow editor implements the ICustomActivity interface, which is very similar to ElementItemBuilderBase, but with one difference – it allows you to create a Printable object and return it to be displayed as a ‘not’ in the flow.
public CustomNode CreateNode(IDiagramNodeCreationInfo info, IElementItem element);
Please note that for easier implementation, you can drive a custom activity class from CustomActivityBase
Shapes
There are different ways to create a CustomNode’s shape. In FlexRule Designer, we use Shape to build different shapes on a diagram. MindFusion.Diagramming.Shapes in assembly MindFusion.Diagramming will give you some useful predefined shapes. Check http://www.mindfusion.eu/onlinehelp/flowchartnet/Table_of_Predefined_Shapes.htmfor a list of predefined shapes.
public override CustomNode CreateNode(IDiagramNodeCreationInfo info, IElementItem element) { return new CustomNode(Shapes.RoundRect) { FillColorFrom = Color.FromArgb(255, 224, 192), FillColorTo = Color.FromArgb(255, 128, 0), Size = new Size(10, 10), }; }
MindFusion.Diagramming.Shapes provides some pre-built shapes that can be used. Otherwise, you can implement your own by following the link below:
http://www.mindfusion.eu/onlinehelp/flowchartnet/T_MindFusion_Diagramming_Shape.htm
Registering custom activity
You need to register your custom activity in the settings file: FlexRule.Designer.Settings.config
In the Activities section of the settings, add your custom node:
<Activities> <Validator assembly="FlexRule.Designer.ValidationEngine.dll" type="FlexRule.Designer.ValidationEngine.CustomActivity" /> <Notification assembly="FlexRule.Designer.Core.dll" type="FlexRule.Designer.Notifications.CustomActivity" /> <Notif assembly="FlexRule.Designer.Sample.FlowCustomActivity.dll" type="FlexRule.Designer.Sample.FlowCustomActivity.NotifCustomActivity" /> </Activities>
After registering the new activity, you can start dragging and dropping the new activity as well as connecting other nodes to it.

Download the sample code
Download the sample project (FlexRule.Designer.Sample.FlowCustomActivity2.zip) using the attachment at the end of the project.
Build the class library and put the assembly into the designer folder. When you create a new project, select this assembly as one of your builders in the properties window.
Migration from Old Designer
Assemblies and Types
- Assembly FlexRule.Designer.Controls.Diagram has been replaced by MindFusion.Diagramming
- Type ICustomActivity method signature has been changed from
Printable CreateNode(IFlowNodeCreationInfo info, IElementItem element);
to
CustomNode CreateNode(IDiagramNodeCreationInfo info, IElementItem element);
- Type Printable and LinkableCustomFigureContainer are replaced by CustomNode that contains a Shape
Re-defined Shapes and Custom Shapes
- FiguresFactory is replaced by MindFusion.Diagramming.Shapes that offer pre-built shapes
- Predefined shapes are listed at http://www.mindfusion.eu/onlinehelp/flowchartnet/Table_of_Predefined_Shapes.htm
To use a predefined shape by its identifier, you can simply use
Shape.FromId(string identifier)
in order to return the instance of a predefined shape by its identifier. For example, Shape.FromId(“Display”) returns a shape for a Display.

- Custom Shapes can be built using http://www.mindfusion.eu/onlinehelp/flowchartnet/T_MindFusion_Diagramming_Shape.htm