Files
serein-flow/flow_visualizer_cn.md

215 lines
6.4 KiB
Markdown
Raw Normal View History

2025-07-30 11:59:22 +08:00
# 📘 自述文档:基于 .NET 8 的流程可视化框架
## 🧩 项目介绍
本项目是一个基于 **.NET 8** 的流程可视化框架,
- 全部运行依赖、运行环境、编辑器均为 **开源**
- 支持 **二次开发**,适合用于嵌入式、工控、数据流程自动化等场景。
📺 **Bilibili 视频更新**:不定期更新项目相关内容,可前往我的 [Bilibili 主页](https://space.bilibili.com/33526379) 查看。
---
## 🗓️ 计划任务(更新于 2025 年 7 月 28 日)
- ✅ 正在完善“**流程图转 C# 代码**”功能
- 🔥 构思 **热更新机制**
- 🔧 多客户端 **远程控制逻辑**设计中
---
## 🖌️ 如何绘制流程?
### 🛠️ 准备工作
1. 编译 `Serein.Workbench` 项目,确保工作台可运行。
2. 新建一个类库项目,并添加对 `Serein.Library` 的引用(也可通过 Negut 获取)。
### ✨ 开始绘图
1. 在类库项目中添加一个类,使用 `[DynamicFlow]` 特性标记类。
2. 使用 `[NodeAction]` 特性标记方法。
3. 编译项目并将生成的 DLL 拖入工作台左侧“类库”面板中。
4. 工作台自动解析并加载所有节点方法。
### 🎨 绘制节点流程
1. 在工作台中新建一个画布。
2. 从左侧类库面板中拖拽方法到画布上生成节点。
3. 在节点连接器之间拖拽生成连线,表示数据/控制流。
4. 可重复添加、连接多个节点构建完整流程。
### ▶️ 运行流程
- **从起始节点运行**
- 设置某节点为“起始节点” → 点击“运行” → 选择“从当前画布运行”
- **从指定节点运行**
- 框选单个节点 → 按 `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);` 注册更多的内置方法。
示例:
```csharp
// 入参是一个对象,入参名称是 "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触发器
- 可响应外部事件或超时触发,需要有返回值
2025-07-30 11:59:22 +08:00
#### 🧠 ExpOp表达式节点
- 提取对象的子属性、字段、数组、字典值
- 示例:`@Get .Array[22]``@Get .Dict["key"]`
#### 🔍 ExpCondition条件表达式节点
- 条件判断节点,支持布尔/数值/文本逻辑判断
示例:
```text
条件表达式:.Age > 18 && data.Age < 35
注意右侧出现的“data”是表达式数据的默认名称假如你需要在表达式里其他地方使用入参数据时就可以使用“data”。
或 .Text.StartsWith("1100") // 判断文本是否以1100开头
```
#### 🖼️ UI嵌入控件
- 显示自定义 `UserControl` 到工作台
- 返回实现 `IEmbeddedContent` 接口的对象
示例代码片段:
```csharp
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 自动化、图形化逻辑控制等场景
---
> 本文档适用于开发者快速上手和参考具体接口用法。如需进一步了解,请关注项目演示视频或参与社区讨论。