mirror of
https://gitee.com/langsisi_admin/serein-flow
synced 2026-03-03 00:00:49 +08:00
6.4 KiB
6.4 KiB
📘 自述文档:基于 .NET 8 的流程可视化框架
🧩 项目介绍
本项目是一个基于 .NET 8 的流程可视化框架,
- 全部运行依赖、运行环境、编辑器均为 开源,
- 支持 二次开发,适合用于嵌入式、工控、数据流程自动化等场景。
📺 Bilibili 视频更新:不定期更新项目相关内容,可前往我的 Bilibili 主页 查看。
🗓️ 计划任务(更新于 2025 年 7 月 28 日)
- ✅ 正在完善“流程图转 C# 代码”功能
- 🔥 构思 热更新机制
- 🔧 多客户端 远程控制逻辑设计中
🖌️ 如何绘制流程?
🛠️ 准备工作
- 编译
Serein.Workbench项目,确保工作台可运行。 - 新建一个类库项目,并添加对
Serein.Library的引用(也可通过 Negut 获取)。
✨ 开始绘图
- 在类库项目中添加一个类,使用
[DynamicFlow]特性标记类。 - 使用
[NodeAction]特性标记方法。 - 编译项目并将生成的 DLL 拖入工作台左侧“类库”面板中。
- 工作台自动解析并加载所有节点方法。
🎨 绘制节点流程
- 在工作台中新建一个画布。
- 从左侧类库面板中拖拽方法到画布上生成节点。
- 在节点连接器之间拖拽生成连线,表示数据/控制流。
- 可重复添加、连接多个节点构建完整流程。
▶️ 运行流程
- 从起始节点运行:
- 设置某节点为“起始节点” → 点击“运行” → 选择“从当前画布运行”
- 从指定节点运行:
- 框选单个节点 → 按
F5运行
- 框选单个节点 → 按
- 运行所有画布:
- 在“运行”菜单中选择“运行所有画布”
💾 保存/加载项目
- 保存项目:
视图→保存项目→ 选择保存路径 - 加载项目:
视图→加载本地项目→ 选择项目文件
🪵 查看输出日志
- 在
视图→输出窗口中查看异常、日志与调试信息
🧱 如何让方法成为流程节点?
- 使用
[NodeAction]特性标记方法 - 指定合适的节点类型(如 Action、Flipflop、Script 等)
📚 关键接口说明
IFlowContext(流程上下文)
节点之间数据传递的核心接口,由运行环境自动注入。
🔑 核心特点
- 全局单例环境接口,支持注册/获取实例(IoC 模式)
- 每个流程实例中上下文隔离,防止脏数据产生
🔍 常用属性
| 属性 | 类型 | 描述 |
|---|---|---|
RunState |
枚举 | 表示流程运行状态(初始化、运行中、运行完成) |
NextOrientation |
枚举 | 指定下一个分支(成功、失败、异常) |
Exit() |
方法 | 提前终止当前流程 |
🧾 DynamicNodeType 枚举说明
1️⃣ 控件不生成节点(生命周期方法)
| 枚举值 | 描述 |
|---|---|
Init |
程序启动时最先执行,适合进行类初始化等操作 |
Loading |
所有 DLL 的 Init 执行完毕后调用,适合业务初始化 |
Exit |
程序关闭时调用,适合释放线程/关闭服务 |
参数均为
IFlowContext,返回值支持异步,但框架不处理其结果。
2️⃣ 基础节点类型
📎 FlowCall(流程接口节点)
- 实现跨画布复用逻辑
- 支持参数共享模式(全局同步)或参数独立模式(本地隔离)
💡 Script(脚本节点)
- 使用 AST 抽象语法树动态编译运行
- 内置
global()、now()等函数,参考Serein.Library.ScriptBaseFunc类中成员方法。 - 在代码中调用
SereinScript.AddStaticFunction("your function name", MethodInfo);注册更多的内置方法。
示例:
// 入参是一个对象,入参名称是 "info" ,包含Var、Data属性。
// 自定义类
class Info{
string PlcName;
string Content;
string LogType;
DateTime LogTime;
}
plc = global("JC-PLC"); // 获取全局数据节点中的数据
log = new Info() {
Content = plc + " " + info.Var + " - 状态 Value : " + info.Data,
PlcName = plc.Name,
LogType = "info",
LogTime = now(),
};
return log;
🌐 GlobalData(全局数据节点)
- 获取/共享运行时跨节点数据
- 表达式使用:
global("DataKey")
3️⃣ 从 DLL 生成控件的节点
⚙️ Action
- 最基础的节点类型,入参自动匹配,返回值支持异步
🔁 Flipflop(触发器)
- 可响应外部事件或超时触发,需要有返回值
🧠 ExpOp(表达式节点)
- 提取对象的子属性、字段、数组、字典值
- 示例:
@Get .Array[22]或@Get .Dict["key"]
🔍 ExpCondition(条件表达式节点)
- 条件判断节点,支持布尔/数值/文本逻辑判断
示例:
条件表达式:.Age > 18 && data.Age < 35
注意,右侧出现的“data”是表达式数据的默认名称,假如你需要在表达式里其他地方使用入参数据时,就可以使用“data”。
或 .Text.StartsWith("1100") // 判断文本是否以1100开头
🖼️ UI(嵌入控件)
- 显示自定义
UserControl到工作台 - 返回实现
IEmbeddedContent接口的对象
示例代码片段:
await context.Env.UIContextOperation.InvokeAsync(() => {
var userControl = new UserControl();
adapter = new WpfUserControlAdapter(userControl, userControl);
});
return adapter;
public class WpfUserControlAdapter : IEmbeddedContent
{
private readonly UserControl userControl;
private readonly IFlowControl flowControl;
public WpfUserControlAdapter(UserControl userControl, IFlowControl flowControl)
{
this.userControl = userControl;
this.flowControl= flowControl;
}
public IFlowControl GetFlowControl()
{
return flowControl;
}
public object GetUserControl()
{
return userControl;
}
}
✅ 总结
- 该框架提供灵活的流程编辑、运行与二次扩展能力
- 支持脚本、全局数据、子流程等高级功能
- 适用于 AGV 调度、PLC 自动化、图形化逻辑控制等场景
本文档适用于开发者快速上手和参考具体接口用法。如需进一步了解,请关注项目演示视频或参与社区讨论。