Skip to main content
All docs
V24.2

Extend a Default Diagram Item

  • 4 minutes to read

You can create a diagram item descendant with additional properties to extend a default diagram item.

View Example: Create a DiagramShape Descendant with Editable and Serializable Properties

Create and Register Descendants

  1. Create a custom class and inherit it from the required type (DiagramShape, DiagramContainer, DiagramList, DiagramConnector, DiagramContentItem, or DiagramImage):

    public class CustomDiagramShape : DiagramShape {
        //...
    }
    

    Make sure that your descendant class has a parameterless constructor.

  2. Call the DiagramItemTypeRegistrator.Register method to register your descendant type and allow its serialization. You should register descendants at application startup.

    DiagramControl.ItemTypeRegistrator.Register(typeof(CustomDiagramShape));
    

    If the custom item is used in the Diagram Designer or Item Template Designer, it is necessary to also register it in the item static constructor:

    public class CustomDiagramShape : DiagramShape {
        // Descendant properties
        static CustomDiagramShape() {
            DiagramControl.ItemTypeRegistrator.Register(typeof(CustomDiagramShape));
        }
    }
    

    Note

    The DiagramControl registration mechanism uses short type names to register diagram item descendants of custom types. Generic types are registered only by their short names without type parameters.

  3. Register a FactoryItemTool that creates your custom item:

    var stencil = new DiagramStencil("CustomStencil", "Custom Shapes");  
    var itemTool = new FactoryItemTool(  
        "CustomShape",  
        () => "Custom Shape", diagram => {  
            CustomDiagramShape customShape = new CustomDiagramShape() { Width = 100, Height = 50 };  
            return customShape;  
        },  
        new Size(100, 50),  
        false  
    );  
    stencil.RegisterTool(itemTool);  
    DiagramToolboxRegistrator.RegisterStencil(stencil);
    

Define Custom Properties and Enable Their Serialization

The DiagramControl serializes items and their properties when a user performs the following actions: copy, paste, cut, undo, and redo. The serialization mechanism is also used to save diagrams to a stream or XML document. Mark your custom properties with the XtraSerializableProperty attribute to enable their serialization:

[XtraSerializableProperty]
public int DatabaseObjectID { get; set; }

Handle the DiagramControl.CustomGetSerializableItemProperties event instead if you cannot change your diagram item implementation:

private void diagramControl1_CustomGetSerializableItemProperties(object sender, DiagramCustomGetSerializableItemPropertiesEventArgs e) {
    e.Properties.Add(TypeDescriptor.GetProperties(typeof(CustomDiagramShape))["DatabaseObjectID"]);
}

You can also handle the DiagramControl.CustomGetEditableItemProperties event to allow users to edit your custom properties in the Properties Panel. Refer to the following section in the event description: Add a Shape Descendant’s Property.

Add Property Descriptors for Custom Properties

The Properties Panel allows users to edit properties that are not defined directly at the diagram item level (for example, when your diagram is bound to a data source and you need to edit source item properties). To do this, handle the DiagramControl.CustomGetEditableItemProperties event and use the CreateProxyProperty method to create a custom property descriptor. For additional information, refer to the following section in the event description: Add Independent Properties.

Assign Type Converters

The Properties Panel uses the Property Grid control to edit properties. This control supports custom TypeConverters that can be assigned to properties of a diagram item descendant. You can use these converters when editable properties are object collections or custom types.

public class CollectionDescriptionConverter : CollectionConverter {
    public override PropertyDescriptorCollection GetProperties(ITypeDescriptorContext context, object value, Attribute[] attributes) {
        if (value is List<int> list)
            return new PropertyDescriptorCollection(list.Select(x => new CustomPropertyDescriptor(Guid.NewGuid().ToString())), new Attribute[] { ... });
        return base.GetProperties(context, value, attributes);
    }

    public override bool GetPropertiesSupported(ITypeDescriptorContext context) => true;
}

public class CustomPropertyDescriptor : PropertyDescriptor { ... }

public class CustomDiagramShape : DiagramShape {
    [TypeConverter(typeof(CollectionDescriptionConverter))]
    public ObservableCollection<string> _Values { get; set; }
}