NodeStudio 0.5.0
dotnet add package NodeStudio --version 0.5.0
NuGet\Install-Package NodeStudio -Version 0.5.0
<PackageReference Include="NodeStudio" Version="0.5.0" />
<PackageVersion Include="NodeStudio" Version="0.5.0" />
<PackageReference Include="NodeStudio" />
paket add NodeStudio --version 0.5.0
#r "nuget: NodeStudio, 0.5.0"
#:package NodeStudio@0.5.0
#addin nuget:?package=NodeStudio&version=0.5.0
#tool nuget:?package=NodeStudio&version=0.5.0
NodeStudio
节点图框架核心库(.NET Standard 2.0)——图引擎、节点模型、表达式与序列化
NodeStudio 是一个 WPF 节点图编辑器框架的核心库:提供节点/端口模型、并行 DAG 执行引擎、条件/数值表达式引擎、图序列化(导出/导入)、组合源生成器,以及自定义类型/属性持久化扩展机制。配套控件库 NodeStudio.Controls 提供完整的 WPF 编辑器界面。
功能
- 并行执行引擎:入度事件驱动调度,就绪节点并行运行、失败不影响下游、支持取消
- 节点模型:继承
NodeBase定义节点,AddInput<T>/AddOutput<T>声明端口,[Node]特性进工具箱;业务属性SetProperty变更通知(可直接绑定 UI),每个节点自带通用「运行」bool 输入端口(false 跳过执行、下游照常) - 节点块:子图封装 + for 循环 + 「运行」开关,双击进入内部编辑
- 条件/计算表达式:内置表达式引擎(引用输入、数学函数、算术/比较/逻辑),实时校验
- 序列化:图 JSON 导出/导入(节点/连线/参数/子图),格式带版本号,旧文件兼容、过新文件友好提示
- 自定义类型端口:
PortTypeRegistry.Register("name", typeof(T))注册任意类型,节点块动态端口可选 - 属性分层持久化:复杂属性自动序列化 →
PropertySerializerRegistry编解码 →ISerializableNode完全接管;[NotSerialized]标记排除 - 执行会话资源:
Scope.Track(disposable)在每轮图执行结束(含失败/取消)后统一释放 - 全局数据队列:
DataQueueStore+ 「数据入队/数据出队」节点——生产者-消费者模型(入队缓冲、出队取走、跨轮保留) - 内置延时节点:输入/输出 object 通配、任意类型数据流中做时序控制(响应取消)
快速开始
dotnet add package NodeStudio
using NodeStudio.Core;
var graph = new NodeGraph();
var node = new MyNode { Name = "我的节点" };
graph.AddNode(node);
var result = await graph.ExecuteAsync(); // GraphResult:耗时/成功/失败节点
定义节点
两种方式:继承 NodeBase(最常用,下方示例)或组合 NodeComposition + 源生成器(声明式端口字段,编译期自动补齐样板代码,详见下方「组合源生成器」)。
// [Node(分类, 工具箱显示名)];Icon 可选,配合 IconType 指定类型:
// Glyph(默认)= Segoe MDL2 Assets 码点;Image = 图片路径/URI(文件不存在或格式非法时工具箱显示会抛异常)
[Node("基础", "常量", Icon = "\uE8A5", Description = "输出固定常量值")]
public class ConstantNode : NodeBase
{
private readonly NodeOutput<int> _output;
private int _value = 1;
public int Value { get => _value; set => SetProperty(ref _value, value); } // 自动随图序列化;变更通知可直接绑定
public ConstantNode() => _output = AddOutput<int>("结果");
protected override Task ExecuteAsync()
{
_output.SetValue(Value);
return Task.CompletedTask;
}
public override INode Clone() // 复制粘贴需要
{
var c = new ConstantNode { Value = Value };
Comp.CopyTo(c.Comp);
return c;
}
}
- 输入端口:
AddInput<int>("数值A"),执行时input.GetValue()读取 - 异步/取消:
await Task.Delay(ms, CurrentCancellationToken) - 资源释放:
Scope?.Track(obj) - 属性持久化:默认自动;
[NotSerialized]排除;PropertySerializerRegistry/ISerializableNode处理特殊类型 - 属性变更通知:业务属性用
SetProperty(ref _value, value)写法即可直接绑定 UI({Binding Subject.Value}),ViewModel 无需转发 - 通用「运行」输入端口:每个节点自带(bool,默认 true)——连接到条件输出或手动设为 false 时节点跳过执行(标记"未运行",下游照常)
- 工具箱图标:
[Node(Icon = "\uE8EF")]指定专属图标(默认按 Segoe MDL2 Assets 码点解释);图片图标用Icon = "...", IconType = NodeIconType.Image——推荐嵌入资源方式:图片文件生成操作设为 Resource,填/程序集名;component/路径(如"/MyApp;component/Assets/logo.png"),随程序集分发无需单独携带;也支持绝对/相对文件路径与 pack:///https URI。文件不存在、无法解码或码点无效时工具箱显示会抛出明确异常;不指定则显示通用默认图标(全局默认可改:ToolboxItem.DefaultIcon = "\uXXXX",需在扫描工具箱前设置)
组合源生成器
本包同时是 Roslyn 源生成器(NodeCompositionGenerator):用「组合」方式定义节点时,编译期自动生成 INode 的样板委托成员,避免手写重复代码。
用法
不继承 NodeBase,直接实现 INode:类声明为 partial,用特性字段声明端口,ExecuteAsync 与 Clone 自己实现(业务逻辑生成器不碰):
using NodeStudio.Attributes;
using NodeStudio.Core;
[Node("基础", "加法")]
public partial class AddNode : INode
{
// 端口字段——生成器在 InitNode 中按端口名/类型赋值,声明时用 null! 抑制可空警告
[NodeInput("数值A")] private NodeInput<int> _a = null!;
[NodeInput("数值B")] private NodeInput<int> _b = null!;
[NodeOutput("和")] private NodeOutput<int> _sum = null!;
/// <summary>普通属性照常自动序列化</summary>
public int Offset { get; set; }
public Task ExecuteAsync(CancellationToken cancellationToken = default)
{
_sum.SetValue(_a.GetValue() + _b.GetValue() + Offset);
return Task.CompletedTask;
}
public INode Clone() // 复制粘贴需要
{
var c = new AddNode { Offset = Offset };
Comp.CopyTo(c.Comp);
return c;
}
}
生成器自动补齐:Comp 字段、构造器(调用 InitNode() 完成端口接线)、INode 的全部状态/端口委托成员(Id/Name/Category/X/Y/State/RunStatus/LastExecutionTimeMs/Inputs/Outputs/SetExecutionTime/Reset)。
生效条件(全部满足才生成)
- 类是
partial; - 类带
[Node]特性且实现INode(直接实现或经基类); - 有
[NodeInput]/[NodeOutput]标注的字段(自动生成Comp字段 + 构造器 +InitNode()接线);或类里已有NodeComposition类型的字段(此时生成器只补INode委托成员,端口初始化由自己负责)。两者皆无则跳过。
注意事项
[NodeInput]/[NodeOutput]只对字段生效:标在属性上不报错但也不会生成任何东西;- 自己写了构造函数时,生成器不会再生构造器——需在构造中手动调用
InitNode(); - 端口名省略时使用字段名,建议显式指定;
- 特性的
DefaultValue目前不参与生成(默认值需走Comp.AddInput<T>(name, defaultValue)手写路径)。
引用方式
- NuGet 引用(
dotnet add package NodeStudio):自动生效——包内 DLL 同时打进analyzers/dotnet/cs,Roslyn 自动加载; - 同解决方案项目引用:普通
ProjectReference不会激活生成器,需额外加一条分析器引用:
<ProjectReference Include="..\NodeStudio\NodeStudio.csproj" />
<ProjectReference Include="..\NodeStudio\NodeStudio.csproj"
OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
生成结果在「解决方案资源管理器 → 分析器 → NodeCompositionGenerator」下查看({类名}.g.cs)。
依赖
- System.Text.Json 8.0.5
许可证
MIT
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
| .NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
| .NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen40 was computed. tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- System.Text.Json (>= 8.0.5)
NuGet packages (1)
Showing the top 1 NuGet packages that depend on NodeStudio:
| Package | Downloads |
|---|---|
|
NodeStudio.Controls
NodeStudio 节点图编辑器控件库(WPF):基于 Nodify 的节点画布、工具箱、属性面板与操作界面,内置深色样式;依赖 NodeStudio 核心库。 |
GitHub repositories
This package is not used by any popular GitHub repositories.
重大更新:1) 所有节点自带通用「运行」bool 输入端口——连接条件输出或手动设为 false 即跳过执行(标记 NotRun、下游照常),条件分支后无需再用节点块包装(注意:所有 NodeBase 节点输入端口数 +1,且「运行」端口排在最前,建议按端口名取用);2) NodeBase 实现 INotifyPropertyChanged——业务属性用 SetProperty 写法即可直接绑定 {Binding Subject.属性},ViewModel 无需转发属性。