You will build: a state machine with guarded transitions. Time: about 15 minutes. Prerequisites: Beep.Skia and Beep.Skia.StateMachine.

1. States

using Beep.Skia;
using Beep.Skia.StateMachine;

var manager = new DrawingManager();

var idle = new InitialStateNode { X = 60, Y = 120, Width = 50, Height = 50 };
var active = new StateNode { X = 200, Y = 100, Width = 180, Height = 80, Title = "Active" };
var done = new FinalStateNode { X = 460, Y = 120, Width = 50, Height = 50 };

foreach (var node in new SkiaComponent[] { idle, active, done })
    manager.AddComponent(node);

2. Transitions with triggers and guards

Transition semantics live on the line: a trigger event, an optional guard and an action. The three properties also drive the label, so the diagram reads trigger [guard] / action.

manager.ConnectComponents(idle, active);
var start = manager.GetLines().Last();
start.TriggerEvent = "power.on";
start.Label1 = "power.on";

manager.ConnectComponents(active, done);
var finish = manager.GetLines().Last();
finish.TriggerEvent = "work.completed";
finish.GuardCondition = "errors == 0";
finish.TransitionAction = "flushMetrics()";
finish.Label1 = "work.completed [errors == 0] / flushMetrics()";

3. Behaviour on states

States carry entry and exit behaviour plus an activity performed while active:

active.EntryAction = "startHeartbeat()";
active.DoActivity = "processQueue()";
active.ExitAction = "stopHeartbeat()";

4. Validate

Validation flags unreachable states and dead ends; the workflow engine then executes the graph with the guards evaluated at run time.

var validator = new DiagramValidator();
validator.AddDefaultRules();
var issues = validator.Validate(manager.GetComponents().ToList(), manager.GetLines());
Console.WriteLine($"{issues.Count} issue(s)");

To execute it, publish the diagram as a workflow — see the Workflow Engine.

Next steps