Table of Contents

Serialization

FlowGraph supports JSON serialization for saving and loading graphs.

Basic Usage

using FlowGraph.Core.Serialization;

// Serialize to JSON string
string json = GraphSerializer.Serialize(graph);

// Deserialize from JSON string
Graph graph = GraphSerializer.Deserialize(json);

File Operations

Extension methods for file I/O:

// Synchronous operations
graph.SaveToFile("my-graph.json");
var graph = GraphExtensions.LoadFromFile("my-graph.json");

// Async operations (recommended for large graphs)
await graph.SaveToFileAsync("my-graph.json");
var graph = await GraphExtensions.LoadFromFileAsync("my-graph.json");

Batch Loading

For better performance when loading large graphs, use batch loading to suppress change notifications:

// Using batch load mode
graph.BeginBatchLoad();
try
{
    // Add many nodes and edges
    foreach (var nodeData in largeDataSet)
    {
        graph.AddNode(CreateNode(nodeData));
    }

    foreach (var edgeData in edgeDataSet)
    {
        graph.AddEdge(CreateEdge(edgeData));
    }
}
finally
{
    graph.EndBatchLoad(); // Raises single notification
}

// Or use bulk operations
graph.AddNodes(nodeCollection); // Single notification for all nodes
graph.AddEdges(edgeCollection); // Single notification for all edges

// Subscribe to completion event
graph.BatchLoadCompleted += (s, e) =>
{
    Console.WriteLine("Graph loaded, UI will refresh");
};

Cloning

Create a deep copy of a graph:

var copy = graph.Clone();

Definition + State Pattern

FlowGraph uses an immutable Definition + mutable State pattern:

using FlowGraph.Core.Models;

// Node Definition (immutable) - structural properties
var definition = new NodeDefinition
{
    Id = Guid.NewGuid().ToString(),
    Type = "process",
    Label = "My Node",
    Inputs = [new PortDefinition { Id = "in", Type = "data" }],
    Outputs = [new PortDefinition { Id = "out", Type = "data" }],
    IsSelectable = true,
    IsDraggable = true,
    Data = customData
};

// Node State (mutable) - runtime properties
var state = new NodeState
{
    X = 100,
    Y = 100,
    Width = 150,
    Height = 80,
    IsSelected = false
};

var node = new Node(definition, state);

// Modify definition immutably
node.Definition = node.Definition with { Label = "Updated" };

// Modify state directly
node.State.X = 200;
node.State.IsSelected = true;

// Backward-compatible pass-through properties still work
node.Label = "Another Update"; // Updates Definition internally
node.Position = new Point(300, 300); // Updates State

JSON Format

The serialized format includes all graph data:

{
  "nodes": [
    {
      "id": "node-1",
      "type": "default",
      "label": "My Node",
      "position": { "x": 100, "y": 100 },
      "width": 150,
      "height": 80,
      "inputs": [{ "id": "in", "type": "data", "label": "Input" }],
      "outputs": [{ "id": "out", "type": "data", "label": "Output" }],
      "isSelectable": true,
      "isDraggable": true,
      "isDeletable": true,
      "isConnectable": true,
      "isResizable": true,
      "data": { "customProperty": "value" }
    }
  ],
  "edges": [
    {
      "id": "edge-1",
      "source": "node-1",
      "target": "node-2",
      "sourcePort": "out",
      "targetPort": "in",
      "type": "bezier",
      "markerEnd": "arrow",
      "label": "Connection",
      "autoRoute": false
    }
  ]
}

Custom Data

Nodes support arbitrary data through the Data property:

var node = new Node(
    new NodeDefinition
    {
        Id = "node1",
        Type = "custom",
        Data = new Dictionary<string, object>
        {
            { "value", 42 },
            { "name", "Example" }
        }
    },
    new NodeState { X = 100, Y = 100 }
);

// Backward-compatible approach
var legacyNode = new Node
{
    Type = "custom",
    Position = new Point(100, 100),
    Data = new { value = 42, name = "Example" }
};

Custom data is preserved during serialization.

Port Definitions

Ports now support additional properties:

var port = new PortDefinition
{
    Id = "data_in",
    Type = "data",
    Label = "Data Input",
    Position = PortPosition.Left,
    MaxConnections = 1, // Limit connections
    IsRequired = true // Mark as required
};

Performance Tips

  • Use BeginBatchLoad() / EndBatchLoad() for large graphs
  • Use AddNodes() / AddEdges() instead of individual adds
  • Use async methods for file operations
  • Consider virtualization for 100+ nodes (see Performance Guide)