Back to Devexpress

How to: Create a DiagramShape Descendant and Serialize Its Properties

windowsforms-118077-controls-and-libraries-diagrams-examples-how-to-create-a-diagramshape-descendant-and-serialize-its-properties.md

latest13.4 KB
Original Source

How to: Create a DiagramShape Descendant and Serialize Its Properties

  • Nov 13, 2018
  • 6 minutes to read

This example demonstrates how to serialize custom data using DiagramControl‘s serialization mechanism. In the example, the DiagramShape.Content property of diagram shapes is loaded from data objects every time the diagram is shown. To associate shapes with data objects, the DatabaseObjectID property is added at the DiagramShape descendant level. To serialize this property along with standard DiagramShape properties, follow the steps below.

Note

In certain scenarios, it is easier to use the DiagramItem.Tag property to store custom data without creating DiagramShape descendants. In this case, no further steps are needed as the Tag property is serialized by default.

  1. Mark your custom property with the XtraSerializableProperty attribute:
csharp
[XtraSerializableProperty]
public int DatabaseObjectID { get; set; }
  1. Call the DiagramItemTypeRegistrator.Register method to register your custom shape type for serialization. Custom shape types should be registered at the application start. If the custom shape is used in the Diagram Designer or Item Template Designer, it is necessary to also register it in the shape type’s static constructor.
csharp
DiagramControl.ItemTypeRegistrator.Register(typeof(DiagramShapeEx));

To allow end-users to edit your custom property in the Properties Panel, handle the DiagramControl.CustomGetEditableItemProperties event.

csharp
private void diagramControl1_CustomGetEditableItemProperties(object sender, DiagramCustomGetEditableItemPropertiesEventArgs e) {
    if (e.Item is DiagramShapeEx) {
        e.Properties.Add(TypeDescriptor.GetProperties(typeof(DiagramShapeEx))["DatabaseObjectID"]);
    }
}

View Example

csharp
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;

namespace XtraDiagram.CustomShapeProperties {
    static class Program {
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main() {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new Form1());
        }
    }
}
csharp
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using DevExpress.XtraDiagram;
using System.IO;
using DevExpress.Diagram.Core;

namespace XtraDiagram.CustomShapeProperties {
    public partial class Form1 : DevExpress.XtraEditors.XtraForm {
        const string diagramName = "diagram.xml";
        List<DataObject> DataObjects = new List<DataObject>();
        public Form1() {
            InitializeComponent();
            RegisterStencil();
            DataObjects.Add(new DataObject { ID = 0, Content = "Start" });
            DataObjects.Add(new DataObject { ID = 1, ParentID = 0, Content = "Node 1" });
            DataObjects.Add(new DataObject { ID = 2, ParentID = 1, Content = "Node 1_1" });
            DataObjects.Add(new DataObject { ID = 3, ParentID = 0, Content = "Node 2" });
            DataObjects.Add(new DataObject { ID = 4, ParentID = 3, Content = "Node 2_1" });
        }
        protected override void OnLoad(EventArgs e) {
            base.OnLoad(e);
            if (!File.Exists(diagramName))
                CreateDiagram();
            else
                LoadDiagram();
        }
        protected override void OnClosing(CancelEventArgs e) {
            base.OnClosing(e);
            diagramControl1.SaveDocument(diagramName);
        }
        void RegisterStencil() {
            var stencil = new DevExpress.Diagram.Core.DiagramStencil("CustomStencil", "Custom Shapes");
            var itemTool = new FactoryItemTool("CustomShape", () => "Custom Shape", diagram => { DiagramShapeEx customShape = new DiagramShapeEx() { Width = 100, Height = 50 }; return customShape; }, new System.Windows.Size(100, 50), false);
            stencil.RegisterTool(itemTool);
            DevExpress.Diagram.Core.DiagramToolboxRegistrator.RegisterStencil(stencil);
            DiagramControl.ItemTypeRegistrator.Register(typeof(DiagramShapeEx));
        }
        private void LoadDiagram() {
            try {
                diagramControl1.LoadDocument(diagramName);
                foreach (var item in diagramControl1.Items) {
                    var shape = item as DiagramShapeEx;
                    DataObject dataObject;
                    if (shape != null)
                        shape.Content = (dataObject = DataObjects.FirstOrDefault(x => x.ID == shape.DatabaseObjectID)) == null ? null : dataObject.Content;
                }
            }
            catch (Exception e) {
                CreateDiagram();
            }
        }
        private void CreateDiagram() {
            foreach (var dataObject in DataObjects) {
                var shape = new DiagramShapeEx {
                    Shape = BasicShapes.Rectangle,
                    Size = new Size(150, 100),
                    DatabaseObjectID = dataObject.ID,
                    Content = dataObject.Content
                };
                diagramControl1.Items.Add(shape);
                if (dataObject.ParentID != dataObject.ID)
                    diagramControl1.Items.Add(new DiagramConnector {
                        BeginItem = diagramControl1.Items.First(x => x is DiagramShapeEx && ((DiagramShapeEx)x).DatabaseObjectID == dataObject.ParentID),
                        EndItem = shape
                    });
            }
            diagramControl1.ApplyTreeLayout(Direction.Right);
        }
        private void OnShowingEditor(object sender, DiagramShowingEditorEventArgs e) {
            e.Cancel = true;
        }

        private void diagramControl1_CustomGetEditableItemProperties(object sender, DiagramCustomGetEditableItemPropertiesEventArgs e) {
            if (e.Item is DiagramShapeEx) {
                e.Properties.Add(TypeDescriptor.GetProperties(typeof(DiagramShapeEx))["DatabaseObjectID"]);
            }
        }
    }
    public class DataObject {
        public int ID { get; set; }
        public int ParentID { get; set; }
        public string Content { get; set; }
    }
}
csharp
using DevExpress.Diagram.Core;
using DevExpress.Utils.Serializing;
using DevExpress.XtraDiagram;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;

namespace XtraDiagram.CustomShapeProperties {
    public class DiagramShapeEx : DiagramShape {
        [XtraSerializableProperty]
        public int DatabaseObjectID { get; set; }
        static DiagramShapeEx() {
            DiagramControl.ItemTypeRegistrator.Register(typeof(DiagramShapeEx));
        }
    }
}
vb
Imports System
Imports System.Collections.Generic
Imports System.ComponentModel
Imports System.Data
Imports System.Drawing
Imports System.Linq
Imports System.Text
Imports System.Windows.Forms
Imports DevExpress.XtraDiagram
Imports System.IO
Imports DevExpress.Diagram.Core

Namespace XtraDiagram.CustomShapeProperties
    Partial Public Class Form1
        Inherits DevExpress.XtraEditors.XtraForm

        Private Const diagramName As String = "diagram.xml"
        Private DataObjects As New List(Of DataObject)()
        Public Sub New()
            InitializeComponent()
            RegisterStencil()
            DataObjects.Add(New DataObject With {.ID = 0, .Content = "Start"})
            DataObjects.Add(New DataObject With {.ID = 1, .ParentID = 0, .Content = "Node 1"})
            DataObjects.Add(New DataObject With {.ID = 2, .ParentID = 1, .Content = "Node 1_1"})
            DataObjects.Add(New DataObject With {.ID = 3, .ParentID = 0, .Content = "Node 2"})
            DataObjects.Add(New DataObject With {.ID = 4, .ParentID = 3, .Content = "Node 2_1"})
        End Sub
        Protected Overrides Sub OnLoad(ByVal e As EventArgs)
            MyBase.OnLoad(e)
            If Not File.Exists(diagramName) Then
                CreateDiagram()
            Else
                LoadDiagram()
            End If
        End Sub
        Protected Overrides Sub OnClosing(ByVal e As CancelEventArgs)
            MyBase.OnClosing(e)
            diagramControl1.SaveDocument(diagramName)
        End Sub
        Private Sub RegisterStencil()
            Dim stencil = New DevExpress.Diagram.Core.DiagramStencil("CustomStencil", "Custom Shapes")
            stencil.RegisterTool(New FactoryItemTool("CustomShape", Function() "Custom Shape", Function(diagram) New DiagramShapeEx(), New System.Windows.Size(230, 110), False))
            DevExpress.Diagram.Core.DiagramToolboxRegistrator.RegisterStencil(stencil)
            DiagramControl.ItemTypeRegistrator.Register(GetType(DiagramShapeEx))
        End Sub
        Private Sub LoadDiagram()
            Try
                diagramControl1.LoadDocument(diagramName)
                For Each item In diagramControl1.Items
                    Dim shape = TryCast(item, DiagramShapeEx)
                    Dim dataObject As DataObject
                    If shape IsNot Nothing Then
                        dataObject = DataObjects.FirstOrDefault(Function(x) x.ID = shape.DatabaseObjectID)
                        shape.Content = If(dataObject Is Nothing, Nothing, dataObject.Content)
                    End If
                Next item
            Catch e As Exception
                CreateDiagram()
            End Try
        End Sub
        Private Sub CreateDiagram()
            For Each dataObject In DataObjects
                Dim shape = New DiagramShapeEx With {.Shape = BasicShapes.Rectangle, .Size = New Size(150, 100), .DatabaseObjectID = dataObject.ID, .Content = dataObject.Content}
                diagramControl1.Items.Add(shape)
                If dataObject.ParentID <> dataObject.ID Then
                    diagramControl1.Items.Add(New DiagramConnector With {.BeginItem = diagramControl1.Items.First(Function(x) TypeOf x Is DiagramShapeEx AndAlso CType(x, DiagramShapeEx).DatabaseObjectID = dataObject.ParentID), .EndItem = shape})
                End If
            Next dataObject
            diagramControl1.ApplyTreeLayout(Direction.Right)
        End Sub
        Private Sub OnShowingEditor(ByVal sender As Object, ByVal e As DiagramShowingEditorEventArgs) Handles diagramControl1.ShowingEditor
            e.Cancel = True
        End Sub

        Private Sub diagramControl1_CustomGetEditableItemProperties(sender As Object, e As DiagramCustomGetEditableItemPropertiesEventArgs) Handles diagramControl1.CustomGetEditableItemProperties
            If TypeOf e.Item Is DiagramShapeEx Then
                e.Properties.Add(TypeDescriptor.GetProperties(GetType(DiagramShapeEx))("DatabaseObjectID"))
            End If
        End Sub
    End Class
    Public Class DataObject
        Public Property ID() As Integer
        Public Property ParentID() As Integer
        Public Property Content() As String
    End Class
End Namespace
vb
Imports System
Imports System.Collections.Generic
Imports System.Linq
Imports System.Windows.Forms

Namespace XtraDiagram.CustomShapeProperties
    Friend NotInheritable Class Program

        Private Sub New()
        End Sub

        ''' <summary>
        ''' The main entry point for the application.
        ''' </summary>
        <STAThread> _
        Shared Sub Main()
            Application.EnableVisualStyles()
            Application.SetCompatibleTextRenderingDefault(False)
            Application.Run(New Form1())
        End Sub
    End Class
End Namespace
vb
Imports DevExpress.Diagram.Core
Imports DevExpress.Utils.Serializing
Imports DevExpress.XtraDiagram
Imports System
Imports System.Collections.Generic
Imports System.ComponentModel
Imports System.Linq
Imports System.Text

Namespace XtraDiagram.CustomShapeProperties
    Public Class DiagramShapeEx
        Inherits DiagramShape

        <XtraSerializableProperty> _
        Public Property DatabaseObjectID() As Integer
        Shared Sub New()
            DiagramControl.ItemTypeRegistrator.Register(GetType(DiagramShapeEx))
        End Sub
    End Class
End Namespace