Dynamo
Primer for v2.0
简体中文
简体中文
  • 关于
  • 简介
    • 什么是 Dynamo 以及它是如何工作的?
    • Primer 用户手册、Dynamo 社区和平台
  • Dynamo 设置
  • 用户界面
    • 工作空间
    • 库
  • 节点和导线
  • 基本节点和概念
    • 节点索引
    • 计算设计的几何图形
      • 几何图形概述
      • 向量、平面和坐标系
      • 点
      • 曲线
      • 曲面
      • 实体
      • 网格
    • 程序的构建块
      • 数据
      • 数学
      • 逻辑
      • 字符串
      • 颜色
    • 使用列表进行设计
      • 什么是列表
      • 使用列表
      • 列表的列表
      • n 维列表
    • Dynamo 中的词典
      • 什么是词典
      • 词典节点
      • 代码块中的词典
      • Revit 使用案例
  • 自定义节点和软件包
    • 自定义节点
      • 自定义节点简介
      • 创建自定义节点
      • 发布到库
    • 软件包
      • 软件包简介
      • 软件包案例研究 - Mesh Toolkit
      • 开发软件包
      • 发布软件包
      • Zero-Touch 输入
  • 适用于 Revit 的 Dynamo
    • Revit 连接
    • 选择
    • 编辑
    • 创建
    • 自定义
    • 记录
  • Dynamo for Civil 3D
    • Civil 3D 连接
    • 快速入门
    • 节点库
    • 样例工作流
      • 道路
        • 灯杆放置
      • 浇口面
        • 服务设施放置
      • 公共设施
        • 重命名结构
      • 轨道
        • 间隙包络
      • 勘测
        • 点编组管理
    • 高级主题
      • 对象绑定
      • Python 和 Civil 3D
    • Dynamo Player
    • 有用的软件包
    • 资源
  • Forma Beta 版中的 Dynamo
    • 在 Forma 中设置 Dynamo Player
    • 在 Dynamo Player 中添加和共享图形
    • 在 Dynamo Player 中运行图形
    • Dynamo 计算服务与 Desktop Dynamo 的差异
  • 在 Dynamo 中编码
    • 代码块和 DesignScript
      • 什么是代码块
      • DesignScript 语法
      • 简写
      • 函数
    • 使用 DesignScript 的几何图形
      • DesignScript 几何图形基础知识
      • 几何基本体
      • 向量数学
      • 曲线:内插和控制点
      • 平移、旋转和其他变换
      • 曲面:内插、控制点、放样、旋转
      • 几何参数化
      • 相交和修剪
      • 几何布尔
      • Python 点生成器
    • Python
      • Python 节点
      • Python 和 Revit
      • 设置自己的 Python 模板
    • 语言更改
  • 最佳做法
    • 图形策略
    • 脚本编写策略
    • 脚本参考
    • 管理您的程序
    • 在 Dynamo 中高效处理大型数据集
  • 样例工作流
    • 快速入门工作流
      • 参数化花瓶
      • 吸引器点
    • 概念索引
  • 开发人员入门
    • 从源代码构建 Dynamo
      • 从源代码构建 DynamoRevit
      • 在 Dynamo 中管理和更新依赖项
    • 为 Dynamo 开发
      • 快速入门
      • Zero-Touch 案例研究 - 网格节点
      • 在 Zero-Touch 节点中执行 Python 脚本 (C#)
      • 进一步了解 Zero-Touch
      • 高级 Dynamo 节点自定义
      • 在 Dynamo 软件包中使用 COM(互操作)类型
      • NodeModel 案例研究 - 自定义 UI
      • 更新 Dynamo 2.x 的软件包和 Dynamo 库
      • 更新 Dynamo 3.x 的软件包和 Dynamo 库
      • 扩展程序
      • 为 Dynamo 2.0+ 定义自定义软件包组织
      • Dynamo 命令行界面
      • Dynamo 集成
      • 为 Dynamo For Revit 开发
      • 发布软件包
      • 从 Visual Studio 构建软件包
      • 软件包形式的扩展
    • 拉取请求
    • 测试期望
    • 示例
  • 附录
    • 常见问题解答
    • 可视化编程和 Dynamo
    • 资源
    • 发行说明
    • 有用的软件包
    • 示例文件
    • 主体集成图
    • 下载 PDF
    • Dynamo 键盘快捷键
Powered by GitBook
On this page
Edit on GitHub
Export as PDF
  1. 开发人员入门
  2. 为 Dynamo 开发

NodeModel 案例研究 - 自定义 UI

Previous在 Dynamo 软件包中使用 COM(互操作)类型Next更新 Dynamo 2.x 的软件包和 Dynamo 库

Last updated 2 months ago

相较于 Zero-Touch 节点,基于 NodeModel 的节点提供了更大的灵活性和更强大的功能。在本例中,我们将通过添加一个随机化矩形大小的集成滑块,来将 Zero-Touch 网格节点提升到下一个级别。

滑块会相对于单元大小缩放单元,因此用户不必为滑块提供正确的范围。

Model-View-Viewmodel 模式

在较高级别上,在 Dynamo 中建立模型-视图关系有两个部分:

  • NodeModel 类用于建立节点的核心逻辑(“模型”)

  • INodeViewCustomization 类用于自定义如何查看 NodeModel(“视图”)

NodeModel 对象已有关联的视图-模型 (NodeViewModel),因此我们可以仅关注自定义 UI 的模型和视图。

如何实现 NodeModel

NodeModel 节点与 Zero-Touch 节点有几个明显差异,我们将在本例中介绍这些差异。在我们进入 UI 自定义之前,让我们先构建 NodeModel 逻辑。

1.创建项目结构:

NodeModel 节点只能调用函数,因此我们需要将 NodeModel 和函数分离到不同的库中。对 Dynamo 软件包执行此操作的标准方法是为每个软件包创建单独的项目。先创建一个新的解决方案来包含项目。

  1. 选择 File > New > Project

  2. 选择 Other Project Types 以显示“解决方案”选项

  3. 选择 Blank Solution

  4. 将解决方案命名为 CustomNodeModel

  5. 选择 Ok

在解决方案中创建两个 C# 类库项目:一个用于函数,一个用于实现 NodeModel 接口。

  1. 在解决方案上单击鼠标右键,然后选择 Add > New Project

  2. 选择类库

  3. 将它命名为 CustomNodeModel

  4. 单击 Ok

  5. 重复该过程以添加另一个名为 CustomNodeModelFunctions 的项目

接下来,我们需要重命名自动创建的类库,然后将其添加到 CustomNodeModel 项目中。类 GridNodeModel 实现抽象的 NodeModel 类、GridNodeView 用于自定义视图,GridFunction 包含我们需要调用的任何函数。

  1. 添加另一个类,方法是在 CustomNodeModel 项目上单击鼠标右键、选择 Add > New Item...,然后选择 Class。

  2. 在 CustomNodeModel 项目中,我们需要 GridNodeModel.cs 和 GridNodeView.cs 类

  3. 在 CustomNodeModelFunction 项目中,我们需要 GridFunctions.cs 类

在我们将任何代码添加到类之前,请为此项目添加必需的软件包。CustomNodeModel 将需要 ZeroTouchLibrary 和 WpfUILibrary,CustomNodeModelFunction 将仅需要 ZeroTouchLibrary。WpfUILibrary 将用于我们稍后进行操作的 UI 自定义,ZeroTouchLibrary 将用于创建几何图形。可以为项目单独添加软件包。由于这些软件包具有依存关系,因此将自动安装 Core 和 DynamoServices。

  1. 在项目上单击鼠标右键,然后选择 Manage NuGet Packages

  2. 仅安装该项目所需的软件包

Visual Studio 会将我们参照的 NuGet 软件包复制到构建目录中。这可以设置为 false,这样一来软件包中就不会存在任何不必要的文件。

  1. 选择 Dynamo NuGet 软件包

  2. 将 Copy Local 设置为 false

2.继承 NodeModel 类

如前所述,使 NodeModel 节点与 ZeroTouch 节点不同的主要方面是其对 NodeModel 类的实现。NodeModel 节点需要此类中的多个函数,我们可以通过在类名后添加 :NodeModel 来获取这些函数。

将以下代码复制到 GridNodeModel.cs 中。

using System;
using System.Collections.Generic;
using Dynamo.Graph.Nodes;
using CustomNodeModel.CustomNodeModelFunction;
using ProtoCore.AST.AssociativeAST;
using Autodesk.DesignScript.Geometry;

namespace CustomNodeModel.CustomNodeModel
{
    [NodeName("RectangularGrid")]
    [NodeDescription("An example NodeModel node that creates a rectangular grid. The slider randomly scales the cells.")]
    [NodeCategory("CustomNodeModel")]
    [InPortNames("xCount", "yCount")]
    [InPortTypes("double", "double")]
    [InPortDescriptions("Number of cells in the X direction", "Number of cells in the Y direction")]
    [OutPortNames("Rectangles")]
    [OutPortTypes("Autodesk.DesignScript.Geometry.Rectangle[]")]
    [OutPortDescriptions("A list of rectangles")]
    [IsDesignScriptCompatible]
    public class GridNodeModel : NodeModel
    {
        private double _sliderValue;
        public double SliderValue
        {
            get { return _sliderValue; }
            set
            {
                _sliderValue = value;
                RaisePropertyChanged("SliderValue");
                OnNodeModified(false);
            }
        }
        public GridNodeModel()
        {
            RegisterAllPorts();
        }
        public override IEnumerable<AssociativeNode> BuildOutputAst(List<AssociativeNode> inputAstNodes)
        {
            if (!HasConnectedInput(0) || !HasConnectedInput(1))
            {
                return new[] { AstFactory.BuildAssignment(GetAstIdentifierForOutputIndex(0), AstFactory.BuildNullNode()) };
            }
            var sliderValue = AstFactory.BuildDoubleNode(SliderValue);
            var functionCall =
              AstFactory.BuildFunctionCall(
                new Func<int, int, double, List<Rectangle>>(GridFunction.RectangularGrid),
                new List<AssociativeNode> { inputAstNodes[0], inputAstNodes[1], sliderValue });

            return new[] { AstFactory.BuildAssignment(GetAstIdentifierForOutputIndex(0), functionCall) };
        }
    }
}

这不同于 Zero-Touch 节点。让我们了解一下每个部分的作用。

  • 指定节点属性,如名称、类别、InPort/OutPort 名称、InPort/OutPort 类型、描述。

  • public class GridNodeModel : NodeModel 是一个从 Dynamo.Graph.Nodes 中继承 NodeModel 类的类。

  • public GridNodeModel() { RegisterAllPorts(); } 是一个注册节点输入和输出的构造函数。

  • BuildOutputAst() 返回 AST(抽象语法树),这是从 NodeModel 节点返回数据所需的结构。

  • AstFactory.BuildFunctionCall() 调用 GridFunctions.cs 中的 RectangularGrid 函数。

  • new Func<int, int, double, List<Rectangle>>(GridFunction.RectangularGrid) 指定函数及其参数。

  • new List<AssociativeNode> { inputAstNodes[0], inputAstNodes[1], sliderValue }); 将节点输入映射到函数参数。

  • 如果输入端口未连接,则 AstFactory.BuildNullNode() 会构建空节点。这是为了避免在节点上显示警告。

  • RaisePropertyChanged("SliderValue") 会在滑块值发生更改时通知 UI

  • var sliderValue = AstFactory.BuildDoubleNode(SliderValue) 在 AST 中构建表示滑块值的节点

  • 将输入更改为 functionCall 变量 new List<AssociativeNode> { inputAstNodes[0], sliderValue }); 中的 sliderValue 变量

3.调用函数

CustomNodeModelFunction 项目将构建到 CustomNodeModel 中的单独程序集,以便可以调用它。

将以下代码复制到 GridFunction.cs 中。

using Autodesk.DesignScript.Geometry;
using Autodesk.DesignScript.Runtime;
using System;
using System.Collections.Generic;

namespace CustomNodeModel.CustomNodeModelFunction
{
    [IsVisibleInDynamoLibrary(false)]
    public class GridFunction
    {
        [IsVisibleInDynamoLibrary(false)]
        public static List<Rectangle> RectangularGrid(int xCount = 10, int yCount = 10, double rand = 1)
        {
            double x = 0;
            double y = 0;

            Point pt = null;
            Vector vec = null;
            Plane bP = null;

            Random rnd = new Random(2);

            var pList = new List<Rectangle>();
            for (int i = 0; i < xCount; i++)
            {
                y++;
                x = 0;
                for (int j = 0; j < yCount; j++)
                {
                    double rNum = rnd.NextDouble();
                    double scale = rNum * (1 - rand) + rand;
                    x++;
                    pt = Point.ByCoordinates(x, y);
                    vec = Vector.ZAxis();
                    bP = Plane.ByOriginNormal(pt, vec);
                    Rectangle rect = Rectangle.ByWidthLength(bP, scale, scale);
                    pList.Add(rect);
                }
            }
            pt.Dispose();
            vec.Dispose();
            bP.Dispose();
            return pList;
        }
    }
}

此函数类与 Zero-Touch 网格案例研究非常相似,但有一点不同:

  • 由于已从 CustomNodeModel 调用函数,因此 [IsVisibleInDynamoLibrary(false)] 会阻止 Dynamo“看到”以下方法和类。

正如我们为 NuGet 软件包添加参照一样,CustomNodeModel 需要参照 CustomNodeModelFunction 才能调用函数。

在我们参照函数之前,CustomNodeModel 的 using 语句将处于不活动状态

  1. 在 CustomNodeModel 上单击鼠标右键,然后选择 Add > Reference

  2. 选择 Projects > Solution

  3. 选中 CustomNodeModelFunction

  4. 单击 Ok

4.自定义视图

要创建滑块,我们需要通过实现 INodeViewCustomization 接口来自定义 UI。

将以下代码复制到 GridNodeView.cs 中

using Dynamo.Controls;
using Dynamo.Wpf;

namespace CustomNodeModel.CustomNodeModel
{
    public class CustomNodeModelView : INodeViewCustomization<GridNodeModel>
    {
        public void CustomizeView(GridNodeModel model, NodeView nodeView)
        {
            var slider = new Slider();
            nodeView.inputGrid.Children.Add(slider);
            slider.DataContext = model;
        }

        public void Dispose()
        {
        }
    }
}
  • public class CustomNodeModelView : INodeViewCustomization<GridNodeModel> 定义自定义 UI 所需的功能。

在完成设置项目结构后,使用 Visual Studio 的设计环境构建用户控件并在 .xaml 文件中定义其参数。通过工具箱,将滑块添加到 <Grid>...</Grid>。

  1. 在 CustomNodeModel 上单击鼠标右键,然后选择 Add > New Item

  2. 选择 WPF

  3. 将用户控件命名为 Slider

  4. 单击 Add

将以下代码复制到 Slider.xaml 中

<UserControl x:Class="CustomNodeModel.CustomNodeModel.Slider"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:CustomNodeModel.CustomNodeModel"
             mc:Ignorable="d" 
             d:DesignHeight="75" d:DesignWidth="100">
    <Grid Margin="10">
        <Slider Grid.Row="0" Width="80" Minimum="0" Maximum="1" IsSnapToTickEnabled="True" TickFrequency="0.01" Value="{Binding SliderValue}"/>
    </Grid>
</UserControl>
  • 在 .xaml 文件中定义滑块控件的参数。Minimum 和 Maximum 属性定义此滑块的数值范围。

  • 在 <Grid>...</Grid> 中,我们可以通过 Visual Studio 工具箱放置不同的用户控件

当创建 Slider.xaml 文件时,Visual Studio 会自动创建一个名为 Slider.xaml.cs 的 C# 文件,用于初始化滑块。更改此文件中的名称空间。

using System.Windows.Controls;

namespace CustomNodeModel.CustomNodeModel
{
    /// <summary>
    /// Interaction logic for Slider.xaml
    /// </summary>
    public partial class Slider : UserControl
    {
        public Slider()
        {
            InitializeComponent();
        }
    }
}
  • 该名称空间应为 CustomNodeModel.CustomNodeModel

GridNodeModel.cs 定义滑块计算逻辑。

5.配置为软件包

在我们构建项目之前,最后一步是添加一个 pkg.json 文件,以便 Dynamo 可以读取软件包。

  1. 在 CustomNodeModel 上单击鼠标右键,然后选择 Add > New Item

  2. 选择 Web

  3. 选择 JSON File

  4. 将该文件命名为 pkg.json

  5. 单击 Add

  • 将以下代码复制到 pkg.json 中

{
  "license": "MIT",
  "file_hash": null,
  "name": "CustomNodeModel",
  "version": "1.0.0",
  "description": "Sample node",
  "group": "CustomNodes",
  "keywords": [ "grid", "random" ],
  "dependencies": [],
  "contents": "Sample node",
  "engine_version": "1.3.0",
  "engine": "dynamo",
  "engine_metadata": "",
  "site_url": "",
  "repository_url": "",
  "contains_binaries": true,
  "node_libraries": [
    "CustomNodeModel, Version=1.0.0, Culture=neutral, PublicKeyToken=null",
    "CustomNodeModelFunction, Version=1.0.0, Culture=neutral, PublicKeyToken=null"
  ]
}
  • "name": 确定软件包的名称及其在 Dynamo 库中的分组

  • "keywords": 提供用于搜索 Dynamo 库的搜索词

  • "node_libraries": [] 指示与软件包关联的库

    最后一步是构建解决方案并发布为 Dynamo 软件包。请参见“软件包展开”一章,以了解如何在联机发布之前创建本地软件包以及如何直接从 Visual Studio 构建软件包。

Dynamo 基于 (MVVM) 软件体系结构模式,以使 UI 与后端保持分离。当创建 ZeroTouch 节点时,Dynamo 会在节点的数据与其 UI 之间绑定数据。要创建自定义 UI,我们必须添加数据绑定逻辑。

model-view-viewmodel
矩形网格图形
添加新类库
解决方案资源管理器
安装软件包
禁用本地软件包复制
添加参照
添加新滑块
添加 JSON 文件