NodeStudio.Controls 0.6.4

dotnet add package NodeStudio.Controls --version 0.6.4
                    
NuGet\Install-Package NodeStudio.Controls -Version 0.6.4
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="NodeStudio.Controls" Version="0.6.4" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="NodeStudio.Controls" Version="0.6.4" />
                    
Directory.Packages.props
<PackageReference Include="NodeStudio.Controls" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add NodeStudio.Controls --version 0.6.4
                    
#r "nuget: NodeStudio.Controls, 0.6.4"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package NodeStudio.Controls@0.6.4
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=NodeStudio.Controls&version=0.6.4
                    
Install as a Cake Addin
#tool nuget:?package=NodeStudio.Controls&version=0.6.4
                    
Install as a Cake Tool

NodeStudio.Controls

NodeStudio 节点图编辑器控件库(WPF,.NET 8)——画布、工具箱、属性面板与深色主题

基于 Nodify 的完整节点编辑器界面控件,配合核心库 NodeStudio 使用:提供节点画布(拖拽/连线/框选/多选删除/复制粘贴)、工具箱(Expander 工具组 + 节点图标拖放)、右侧属性面板(节点操作控件)、块内部子图编辑器、深色样式库与统一弹窗/菜单。

功能

  • 节点画布:拖拽创建、拉线连接、选中节点相关连线高亮(#ffa500)、多选/框选、复制粘贴(含块内部节点与连线);多选复制粘贴:Ctrl+C 复制、Ctrl+V / 右键粘贴(单个粘贴到鼠标位置,多选按原位置整体平移并恢复相互连线)、Delete 删除选中(一次确认);快捷键上下文感知——焦点在输入框(表达式/数值编辑)中时 Ctrl+C/X/V、Delete 归文本编辑(复制/粘贴文本),点画布空白处切回焦点才是节点复制粘贴
  • 通用端口:每个节点自带「运行」bool 输入(false 跳过执行)与「运行状态」int 输出(0=未运行/1=成功/2=失败,引擎执行后写入)——悬停端口可看到"运行状态:成功"这类可读提示,接条件节点即可按上游运行结果分支
  • 运行控制:全局运行/暂停/连续运行;**右键任意节点「运行」**可单节点执行——不重置输入(已连接端口取上游上次输出值,未连接端口取手动值/默认值),不重跑上游;节点块右键运行即执行其内部子图;运行中画布只读保护;左下角显示图运行结果(外层/块内部按层级切换,耗时保留 3 位小数)
  • 块内部编辑器:双击节点块进入子图,面包屑导航返回;循环参数编辑;块输入/块输出虚拟节点右键增删/重命名端口(类型可选,含自定义类型)
  • 属性面板:选中节点显示其操作控件(NodeBaseControl 子类,XAML 自定义);内置条件/计算/延时/队列节点均带深色操作界面,条件/计算/队列节点的面板直接显示各输入/输出端口的最近一次运行值(无需悬停端口看 ToolTip),运行后自动刷新
  • 面板宽度可配:编辑器控件提供 PanelRatio 属性(0.15–0.85)设置右侧操作面板的默认占宽比例(默认 0.286);拖动中间分隔条仍可临时微调
  • 跨块/跨图数据流:数据入队/数据出队节点 + 全局数据队列(生产者-消费者:入队缓冲、出队取走、跨轮保留);出队节点的队列名下拉候选自动包含所有层级的数据入队节点
  • 属性多态序列化:属性声明为基类/接口、运行时为派生实例(含 List<T> 泛型列表混装多种派生类)自动打 $type 标识——派生类完整属性随图保存,导入时还原为原派生类(嵌套递归、词典值、端口手动值均支持;不打标时与旧版一致,旧图文件兼容)
  • 反序列化完成钩子:重写 NodeViewModel.OnDeserialized() 即可在图导入的全部还原(属性/端口/位置/端口手动值)完成后做自定义初始化
  • 深色风格:统一深色主题 + Styles.xaml 可复用样式库——覆盖按钮/输入框/复选框/单选/开关/滑块/进度条/列表/标签页/滚动条/表格/分组框/展开器/提示/菜单等常用控件,附 24 个内置配色资源(详见下文「内置深色样式」)
  • 序列化接入:文件菜单导出/导入 JSON 图(经核心库 GraphSerializer)

快速开始

dotnet add package NodeStudio.Controls

项目需 net8.0-windows(或更高 windows TFM)并启用 WPF:

<PropertyGroup>
  <TargetFramework>net8.0-windows</TargetFramework>
  <UseWPF>true</UseWPF>
</PropertyGroup>

<Application.Resources>
  <ResourceDictionary>
    <ResourceDictionary.MergedDictionaries>
      <ResourceDictionary Source="pack://application:,,,/NodeStudio.Controls;component/Views/Styles.xaml"/>
    </ResourceDictionary.MergedDictionaries>
  </ResourceDictionary>
</Application.Resources>
// 编辑器 ViewModel + 节点块
var editor = new EditorViewModel();
var block = new NodeBlockViewModel("计算块");
block.AddInput<int>("数值A").AddOutput<int>("结果");
editor.AddNode(block);

工具箱

左侧工具箱(ToolboxControl,绑定 NodeToolbox)以 Expander 工具组展示节点分类,每组标题条显示组名与节点数,可折叠:

  • 节点条目 = 图标 + 名称:图标取自 [Node(Icon = "\uE8EF")](默认 Segoe MDL2 Assets 码点,浅蓝色);图片图标用 Icon = "...", IconType = NodeIconType.Image——推荐嵌入资源(图片生成操作设为 Resource,填 /程序集名;component/路径,随程序集分发);也支持文件路径/pack:///https URI。文件不存在、无法解码或码点无效时,工具箱显示会抛出包含节点名的明确异常
  • 全局默认图标:可修改 ToolboxItem.DefaultIcon = "\uXXXX"(在扫描工具箱前设置),对所有未配图标的节点生效
  • 拖拽创建:按住节点条目拖到画布即可生成节点(ToolboxItem 拖放协议)
  • 深色风格:标题条 DarkHeaderBackground、悬停 DarkListHover,与整套样式一致

内置深色样式

合并 Styles.xaml 后即可使用(App.xaml 合并方式见上)。所有样式为显式 Key 样式,通过 StaticResource 引用;滚动条为隐式样式(全局自动生效,无需引用)。

控件样式(Views/Styles.xaml)

控件 样式 Key
按钮 IconButtonStyle / DialogButtonStyle(次)/ DialogPrimaryButtonStyle(主)/ DialogCloseButtonStyle(关闭)
文本输入 DialogTextBoxStyle / DarkPasswordBoxStyle
选择 DarkComboBoxStyle + DarkComboBoxItemStyle / DarkCheckBoxStyle / DarkRadioButtonStyle / DarkSwitchStyle(开关)
取值 DarkSliderStyle / DarkProgressBarStyle
列表 DarkListBoxStyle + DarkListBoxItemStyle
分页 DarkTabControlStyle + DarkTabItemStyle
滚动条 隐式 <Style TargetType="ScrollBar">(无按钮、蓝色滑块、悬停/按下变色);别名 DarkScrollBarStyle
表格 DarkDataGridStyle + DarkDataGridColumnHeaderStyle + DarkDataGridRowStyle + DarkDataGridCellStyle + DarkDataGridRowHeaderStyle + DarkDataGridEditingTextBoxStyle
容器 DarkGroupBoxStyle / DarkExpanderStyle / DarkSeparatorStyle
菜单/提示 DarkContextMenuStyle / DarkMenuItemStyle / DarkToolTipStyle
节点 CustomNodeStyle

内置配色(SolidColorBrush 资源,可直接引用)

<Border Background="{StaticResource DarkAccent}"/>
<TextBlock Foreground="{StaticResource DarkTextPrimary}"/>

底色:DarkWindowBackground / DarkPanelBackground / DarkHeaderBackground / DarkInputBackground 边框:DarkBorder / DarkBorderStrong / DarkBorderHover / DarkGridLine 强调:DarkAccent / DarkAccentHover / DarkAccentPressed / DarkAccentLight / DarkTextAccent 文字:DarkTextPrimary / DarkTextSecondary / DarkTextMuted / DarkTextOnAccent 危险:DarkDanger / DarkDangerPressed 状态:DarkRowHover / DarkListHover / DarkAlternatingRow / DarkScrollThumb / DarkScrollThumbHover

表格使用要点

  • 单元格文本居中:DarkDataGridCellStyle 已设 Horizontal/VerticalContentAlignment=Center;文本对齐还需在列的 ElementStyle 中设 TextAlignment=Center
  • 列级只读:<DataGridTextColumn IsReadOnly="True">(数据类属性需带 setter 才能编辑)
  • 编辑框深色:列上加 EditingElementStyle="{StaticResource DarkDataGridEditingTextBoxStyle}"

自定义节点界面

节点被选中时在右侧属性面板显示的操作控件,继承 NodeBaseControl 并用 XAML 搭建:


<ctrl:NodeBaseControl x:Class="MyApp.MyNodeControl"
                      xmlns:ctrl="clr-namespace:NodeStudio.Controls.Views;assembly=NodeStudio.Controls">
    <TextBox Text="{Binding Subject.Value, UpdateSourceTrigger=PropertyChanged}"
             Style="{StaticResource DialogTextBoxStyle}"/>
</ctrl:NodeBaseControl>
public class MyNodeControl : NodeBaseControl
{
    public MyNodeControl(MyNodeViewModel vm) : base(vm) => InitializeComponent();
}

// ViewModel 中(业务属性无需转发——节点属性用 SetProperty 即可自动刷新 UI;ViewModel 只做命令/交互):
public override Control GetControl() => new MyNodeControl(this);

ViewModel 注册(通常零注册):在 ViewModel 类上标注 [NodeViewModel(typeof(MyNode))](需提供公共构造函数 MyNodeViewModel(MyNode node) 包装传入实例),拖拽/复制粘贴/导入图时框架自动发现该映射并恢复操作控件,无需任何注册代码。

程序集延迟加载(插件宿主)时一键注册;依赖注入、非标准构造等特殊场景用 lambda 显式注册(优先级最高):

// 插件程序集加载后调用(不传参则扫描当前已加载的全部程序集)
NodeViewModelFactory.RegisterFromAssemblies(pluginAssembly);

// 特殊场景:lambda 显式注册,优先级高于 [NodeViewModel] 自动发现
NodeViewModelFactory.RegisterVmFactory<MyNode>(node => new MyNodeViewModel((MyNode)node));

属性多态序列化

节点属性声明为抽象基类/接口、运行时保存派生实例——包括最常见的"List<T> 泛型列表混装多种派生类"——序列化时自动写入 $type 类型标识,导入时还原为原派生类,派生类特有属性完整保留(普通属性行为不变,旧图文件兼容读取):

public abstract class Shape { public string Label { get; set; } = ""; }
public class CircleShape : Shape { public double Radius { get; set; } }
public class RectShape : Shape { public double Width { get; set; } public double Height { get; set; } }

public class MyNode : NodeBase
{
    public Shape? Main { get; set; }                  // 单值多态:声明抽象类
    public List<Shape> Shapes { get; set; } = new();  // 列表混装多种派生类
    public Dictionary<string, Shape> Map { get; set; } = new();  // 词典值多态
}

序列化后列表元素逐个携带类型标识:

"Shapes": [
  { "$type": "MyApp.CircleShape", "Radius": 2.5, "Label": "主圆" },
  { "$type": "MyApp.RectShape", "Width": 3, "Height": 4, "Label": "横幅" }
]

规则与支持范围:

  • 打标条件:运行时类型 ≠ 声明类型(或声明为 object/抽象类/接口);对象型值把 $type 并入 JSON 对象首键,基元型值包成 { "$type": …, "$value": … }
  • 支持嵌套递归(派生对象内部再有多态属性/多态列表)、词典值、输入端口手动值;还原时校验派生类型可赋值给声明类型,不兼容则该属性跳过(保持默认值,不中断导入)
  • 限制:集合容器类型不保真(IList<T> 等接口声明还原为 List<T>,元素类型完整保真);含 $type 的嵌套对象需可无参构造;属性图循环引用不支持

反序列化完成钩子(OnDeserialized)

图导入时每个节点的还原时序:节点构造函数 + ViewModel 构造(Init(),仅构造态,看不到保存的数据)→ 属性/端口定义/位置/端口手动值还原 → OnDeserialized()。

需要"还原后初始化"(重算派生字段、同步外部资源等),重写 NodeViewModel.OnDeserialized() 即可:

public class MyNodeViewModel : NodeViewModel
{
    public MyNodeViewModel(MyNode node) { Subject = node; Init(); }
    public override Control GetControl() => new MyNodeControl(this);

    // 全部框架还原就绪后调用(块内部子图的节点随递归各自触发);异常会被框架吞掉,不影响导入
    public override void OnDeserialized()
    {
        var node = (MyNode)Subject;   // 此处已能看到还原后的属性与端口手动值
        // ... 自定义初始化
    }
}

注意:重写 Init() 做不到这件事——它在 ViewModel 构造时、属性还原之前调用;复制粘贴走 INode.Clone() 实例克隆,不经过此钩子(粘贴场景的初始化在 Clone() 里做)。

依赖

  • NodeStudio (>= 0.6.2)
  • Nodify 7.3.0
  • CommunityToolkit.Mvvm 8.4.2
  • Microsoft.Xaml.Behaviors.Wpf 1.1.142

许可证

MIT

Product Compatible and additional computed target framework versions.
.NET net8.0-windows7.0 is compatible.  net9.0-windows was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.6.4 83 9/18/2026
0.6.3 85 9/17/2026
0.6.2 86 9/16/2026
0.6.1 93 9/13/2026
0.6.0 96 9/11/2026
0.5.0 91 9/10/2026
0.4.11 103 9/8/2026
0.4.10 101 9/5/2026
0.4.9 100 9/3/2026
0.4.8 97 9/2/2026
0.4.6 106 8/30/2026
0.4.5 108 8/24/2026
0.4.4 101 8/21/2026
0.4.0 111 8/17/2026
0.3.0 116 8/16/2026
0.2.0 112 8/13/2026
0.1.0 106 8/11/2026

1) 计算节点/条件节点表达式新增对象路径引用 {…}:{input} 引用输入原始值、{input[0]} 取列表/数组元素、{input.Area} 取属性、{input[0].Area} 链式(.属性 与 [索引] 任意交替),可与四则/数学函数/比较/逻辑自由组合;属性缺失、索引越界、null 链断在运行期报明确中文错误(条件节点中失败路线不激活、节点标红);旧语法 [名称] 原样兼容,旧图文件零迁移。2) 修复编辑器快捷键劫持文本复制粘贴的问题:焦点在输入框(表达式/数值编辑)中时 Ctrl+C/X/V、Delete 归文本编辑(复制/粘贴文本),不再误复制/粘贴节点;点画布空白处切回焦点仍为节点快捷键。3) README 补充对象路径语法与快捷键上下文说明。