笔者在前文中已经介绍了如何使用Grasshopper(以下简称GH)模板搭建一个电池组件项目,并进行一些简单的项目配置,相信各位读者已经在进行各种自定义功能电池的开发了。
不过,随着想要制作的电池的增多,每次都从项目模板创建新电池的话,会导致有许许多多的项目存在。倘若这些电池都是服务于同一个目的,将这些电池分散在不同的项目会导致不太方便管理。其次,对于这些电池如果使用到了一些共同的依赖项,还需针对每个项目重新配置一遍,十分费时费力。
“如何 在同一个项目中实现多个电池 ”是从读者处反馈最多的问题,另外附带的一个问题是,每次从项目模板中创建的但却一直被我们忽略的 “ …Info.cs ” 文件到底是用来干什么的?本文就为读者们解答这两个问题。
如何在同一个项目中实现多个电池
比起直接说步骤,笔者还是先来说说 自己写的电池是如何被GH识别的 吧,这样可以更方便大家理解。
相信大家在 如何创建GH电池 一文中已经了解到了,每一个GH电池项目最终都会编译成为一个 DLL类库 文件。而在调试之前,我们也在 Rhino 中通过设置命令将这个DLL类库的文件夹所在地址放入到了GH的某个设置中。再结合我们所有自定义电池都是继承自 GH_Component
类,那么GH识别电池的逻辑也就十分简单了:
- 在给定的文件夹中搜索类库,并动态加载
- 将所有是
GH_Component
的类使用反射(Reflect)获取 - 在电池被拖入画布时,实例化对象
于是,在同一个项目中实现多个电池的思路也十分简单 —— 在项目中添加继承自 GH_Component
的类即可(在同一个文件中添加类,亦或是添加类在一个新文件中均可)。
例如,在同一个 .cs 文件中定义 2 个继承自 GH_Component
的类即可实现在同一个文件中做出 2 个GH电池(类必须具备 public 属性,原因是显而易见的):
namespace MyGhComponents
{
public class MyFirstComponent : GH_Component
{
// 构造方法必须提供额外属性,否则GH无法成功创建电池
public MyFirstComponent()
: base("First Component",
"FC",
"Dummy for first component",
"Params",
"Best Digital Crab"){}
// Guid属性必须实现,https://guidgenerator.com/ 可以免费获取
// 就如同前文提到的,永远不要手动创建Guid
// Like mentioned before, NEVER create Guid manually.
public override Guid ComponentGuid => new Guid("********-****-****-****-********2213");
// ... 具体实现略
}
public class MySecondComponent : GH_Component
{
// 构造方法可以使用模板中默认的(调用base方法),如同MyFirstComponent一样
// 也可以通过自定义赋值来实现,但必须保证下列属性有赋值,否则电池无法创建
// Name, NickName, Description, Category, SubCategory
public MySecondComponent()
{
Name = "Second Component";
NickName = "SC";
Description = "Another way of providing basic descriptive information of component";
Category = "Params";
SubCategory = "Best Digital Crab";
}
public override Guid ComponentGuid => new Guid("********-****-****-****-********9981");
// ... 具体实现略
}
}
2021.2.22 笔者注:
在上述代码中的第二个类的构造函数中,笔者代码并没有继承基类的构造函数。这是极度不推荐的,因为如此做会导致电池内部的输入/输出参数管理类无法初始化,且在自定义类中无法初始化它们。所以这个代码只能生成一个没有输入/输出参数的电池。自己使用时务必继承基类的构造方法
运行项目,就会发现GH中出现了2个新电池。
于是我们也明白了,GH在加载的过程中,那个绿色的小框框是搁这反射呢?还特意告诉大家我正在反射获取 xxxxComponent …
所以更进一步的,为什么在前文配置调试环境中设置 GrasshopperDeveloperSettings 时,需要把 Memory load *.gha assemblies … 前面的复选框去掉勾选的原因就是,我们的在调试时的断点都是在dll文件中的,如果GH把我们写好的电池类dll都读到内存中去了,dll文件上的断点就没法被触发了,自然就没法调试了。
说了这么多,相信大家也明白GH是怎么认识电池的了,也明白了我们应该做什么可以让GH认识到我们写的电池 —— 无论以什么形式,往项目中添加继承自 GH_Component
的类即可。
另外,也向大家推荐另一种方便的方式在Visual Studio里往自己的GH电池项目中添加电池类(前提是安装了GH的官方模板):
- 在项目管理器中找到项目,点击右键,选择添加新类
- 在弹出的窗口中其实就已经可以找到GH电池的模板了,将文件名改成自己喜欢的名字,确认添加即可
【再次特别提醒】!! 千万不要手改Guid !! 使用生成器!!
模板中 xxxxInfo.cs 文件是做什么的
有了前文的经验,我们首先来看看这通过模板创建的 xxxxInfo.cs 文件包含了个继承自什么都类。
namespace MyGhComponents
{
public class MyFirstComponentInfo : GH_AssemblyInfo
{
public override string Name
{
get
{
// ...
}
}
public override Bitmap Icon
{
get
{
// ....
}
}
// .....
}
}
这 GH_AssemblyInfo
是什么东西?
在.NET环境中,Assembly可以认为是一个组件,一群独立的工具拼装在一起服务于一个最终项目,即一个 DLL 。GH_AssemblyInfo
这个类就是用来对这个DLL附带一些额外的信息,用于在某些别的地方展示。也就是说,这个类是用来对我们某一些电池组成的电池工具包做一个总说明和展示。
在哪里展示呢?
在Grasshopper中的菜单栏中找到 Help -> About,在弹出的类似于载入窗口的绿色长方形中,左上角有个特别小的 黑色方块,点击它,就会出现许许多多小图标,而这个 GH_AssemblyInfo
就是为这个小图标提供图标信息和鼠标悬停信息展示。
如果GH在使用反射(Reflect)获取DLL信息时,没找到这个DLL中包含有继承自 GH_AssemblyInfo
的类,那么它就会从其他的能够被识别的类里按某个顺序挑一个类作为这个信息的提供者,但仅仅提供名字,不会包含图标。此时,上图中许许多多的绿色六边形的图标就是这些“做了电池但没提供总信息”的电池Assemblies的替代图标。
所以,只要你不担心其他人在点开这个About信息左上角的小黑块时看到自己做的电池套餐居然是个很丑的绿色六边形图标,你甚至可以把这个 xxxxInfo.cs 文件直接从项目中去除掉,电池依然是可以正确运行的。