第十五章:插件系统与扩展开发
15.1 插件系统概述
15.1.1 Weikio Plugin Framework
LightCAD的插件系统基于Weikio Plugin Framework构建,这是一个.NET平台的轻量级插件加载框架,支持运行时动态加载和卸载程序集。
15.1.2 内置行业插件
LightCAD预置了五个行业插件:
| 插件 | 文件 | 大小 | 功能领域 |
|---|---|---|---|
| QdArch | QdArch.dll | 591KB | 建筑设计 |
| QdElectric | QdElectric.dll | 45KB | 电气设计 |
| QdHvac | QdHvac.dll | 95KB | 暖通设计 |
| QdStruct | QdStruct.dll | 173KB | 结构设计 |
| QdWater | QdWater.dll | 201KB | 给排水设计 |
15.2 插件加载机制
15.2.1 插件管理器
public class PluginManager
{
private static List<IPlugin> loadedPlugins = new();
private static string pluginDirectory;
/// <summary>
/// 加载指定目录下的所有插件
/// </summary>
public static void LoadPlugins(string directory)
{
pluginDirectory = directory;
if (!Directory.Exists(directory))
{
Directory.CreateDirectory(directory);
return;
}
var pluginFiles = Directory.GetFiles(directory, "*.dll");
foreach (var pluginFile in pluginFiles)
{
try
{
LoadPlugin(pluginFile);
}
catch (Exception ex)
{
Console.WriteLine(
$"加载插件失败 {Path.GetFileName(pluginFile)}: {ex.Message}");
}
}
}
/// <summary>
/// 加载单个插件
/// </summary>
private static void LoadPlugin(string pluginPath)
{
// 使用Weikio Plugin Framework加载
var assembly = Assembly.LoadFrom(pluginPath);
// 查找实现IPlugin接口的类型
var pluginTypes = assembly.GetTypes()
.Where(t => typeof(IPlugin).IsAssignableFrom(t)
&& !t.IsAbstract && !t.IsInterface);
foreach (var pluginType in pluginTypes)
{
var plugin = (IPlugin)Activator.CreateInstance(pluginType);
plugin.Initialize();
loadedPlugins.Add(plugin);
Console.WriteLine($"已加载插件:{plugin.Name} v{plugin.Version}");
}
}
/// <summary>
/// 获取所有已加载的插件
/// </summary>
public static IReadOnlyList<IPlugin> LoadedPlugins => loadedPlugins;
/// <summary>
/// 卸载所有插件
/// </summary>
public static void UnloadAll()
{
foreach (var plugin in loadedPlugins)
{
plugin.Shutdown();
}
loadedPlugins.Clear();
}
}
15.2.2 插件接口
/// <summary>
/// 插件基础接口
/// </summary>
public interface IPlugin
{
/// <summary>
/// 插件名称
/// </summary>
string Name { get; }
/// <summary>
/// 插件版本
/// </summary>
string Version { get; }
/// <summary>
/// 插件描述
/// </summary>
string Description { get; }
/// <summary>
/// 插件作者
/// </summary>
string Author { get; }
/// <summary>
/// 初始化插件
/// </summary>
void Initialize();
/// <summary>
/// 关闭插件
/// </summary>
void Shutdown();
}
/// <summary>
/// 带命令注册能力的插件
/// </summary>
public interface ICommandPlugin : IPlugin
{
/// <summary>
/// 注册插件命令
/// </summary>
void RegisterCommands(CommandRegistry registry);
}
/// <summary>
/// 带UI扩展能力的插件
/// </summary>
public interface IUIPlugin : IPlugin
{
/// <summary>
/// 注册菜单项
/// </summary>
void RegisterMenuItems(MenuRegistry registry);
/// <summary>
/// 注册工具栏按钮
/// </summary>
void RegisterToolbarItems(ToolbarRegistry registry);
/// <summary>
/// 注册面板
/// </summary>
void RegisterPanels(PanelRegistry registry);
}
/// <summary>
/// 带元素类型扩展能力的插件
/// </summary>
public interface IElementPlugin : IPlugin
{
/// <summary>
/// 注册自定义元素类型
/// </summary>
void RegisterElementTypes(ElementTypeRegistry registry);
}
15.3 开发自定义插件
15.3.1 创建插件项目
# 创建类库项目
dotnet new classlib -n MyLightCADPlugin -f net8.0-windows
# 添加LightCAD核心引用
cd MyLightCADPlugin
dotnet add reference ../LightCAD.Core/LightCAD.Core.csproj
dotnet add reference ../LightCAD.Runtime/LightCAD.Runtime.csproj
15.3.2 实现插件
// MyPlugin.cs
public class MyPlugin : IPlugin, ICommandPlugin, IElementPlugin
{
public string Name => "我的自定义插件";
public string Version => "1.0.0";
public string Description => "LightCAD自定义插件示例";
public string Author => "开发者";
public void Initialize()
{
Console.WriteLine("我的插件已初始化");
}
public void Shutdown()
{
Console.WriteLine("我的插件已关闭");
}
public void RegisterCommands(CommandRegistry registry)
{
registry.Register(new CommandInfo
{
Name = "MYCOMMAND",
DisplayName = "我的命令",
Description = "执行自定义操作",
Action = ExecuteMyCommand
});
registry.Register(new CommandInfo
{
Name = "DRAWSTAR",
DisplayName = "绘制星形",
Description = "绘制一个正五角星",
Action = DrawStar
});
}
public void RegisterElementTypes(ElementTypeRegistry registry)
{
registry.Register(new ElementType
{
Guid = new LcGuid("my-plugin-star-element"),
Name = "Star",
DisplayName = "五角星",
Category = "自定义图形",
Is3D = false,
Creator = () => new StarElement()
});
}
private void ExecuteMyCommand()
{
// 自定义命令逻辑
MessageBox.Show("执行自定义命令!");
}
private void DrawStar()
{
// 绘制五角星的逻辑
var center = InputManager.GetPoint("指定五角星中心:");
var radius = InputManager.GetDistance("指定外径:");
var star = CreateStarPolyline(center, radius, 5);
DocumentManager.Current.Entities.Add(star);
}
private LcPolyline CreateStarPolyline(Point2d center,
double outerRadius, int points)
{
var polyline = new LcPolyline { IsClosed = true };
var innerRadius = outerRadius * 0.382;
for (int i = 0; i < points * 2; i++)
{
var angle = Math.PI / 2 + Math.PI * i / points;
var r = (i % 2 == 0) ? outerRadius : innerRadius;
polyline.AddVertex(new Point2d(
center.X + r * Math.Cos(angle),
center.Y + r * Math.Sin(angle)
));
}
return polyline;
}
}
15.3.3 自定义元素类型
/// <summary>
/// 自定义五角星元素
/// </summary>
public class StarElement : LcEntity, IUpdateObject
{
public Point2d Center { get; set; }
public double OuterRadius { get; set; } = 50;
public double InnerRadius { get; set; } = 19.1;
public int Points { get; set; } = 5;
public double Rotation { get; set; } = 0;
public override string TypeName => "Star";
public override BoundingBox2d Bounds
{
get
{
return new BoundingBox2d
{
Min = new Point2d(
Center.X - OuterRadius, Center.Y - OuterRadius),
Max = new Point2d(
Center.X + OuterRadius, Center.Y + OuterRadius)
};
}
}
public override void TransformBy(Matrix4d matrix)
{
var p3d = new Point3d(Center.X, Center.Y, 0);
var transformed = matrix.Transform(p3d);
Center = new Point2d(transformed.X, transformed.Y);
}
public override LcEntity Clone()
{
return new StarElement
{
Center = Center,
OuterRadius = OuterRadius,
InnerRadius = InnerRadius,
Points = Points,
Rotation = Rotation,
Color = Color,
LayerName = LayerName
};
}
public override double DistanceTo(Point2d point)
{
return point.DistanceTo(Center) - OuterRadius;
}
/// <summary>
/// 获取五角星的顶点
/// </summary>
public List<Point2d> GetVertices()
{
var vertices = new List<Point2d>();
for (int i = 0; i < Points * 2; i++)
{
var angle = Rotation + Math.PI / 2 + Math.PI * i / Points;
var r = (i % 2 == 0) ? OuterRadius : InnerRadius;
vertices.Add(new Point2d(
Center.X + r * Math.Cos(angle),
Center.Y + r * Math.Sin(angle)
));
}
return vertices;
}
public bool NeedsUpdate { get; private set; }
public void OnUpdate(UpdateContext context)
{
NeedsUpdate = false;
}
}
15.4 插件部署
15.4.1 编译和部署
# 编译插件
dotnet build -c Release
# 将编译输出复制到LightCAD的Plugins目录
copy bin/Release/net8.0-windows/MyLightCADPlugin.dll \
../LightCAD.WinForm/bin/Debug/net8.0-windows/Plugins/
15.4.2 插件清单文件
为了更好地管理插件信息,可以创建清单文件:
{
"name": "MyLightCADPlugin",
"version": "1.0.0",
"author": "开发者",
"description": "LightCAD自定义插件示例",
"assembly": "MyLightCADPlugin.dll",
"dependencies": [],
"minimumLightCADVersion": "1.0.0"
}
15.5 ComponentActionLoader
15.5.1 操作加载器
ComponentActionLoader是LightCAD中专门用于加载建模操作的插件加载器:
public class ComponentActionLoader
{
private Dictionary<string, IComponentAction> actions = new();
/// <summary>
/// 从程序集加载操作
/// </summary>
public void LoadActionsFromAssembly(Assembly assembly)
{
var actionTypes = assembly.GetTypes()
.Where(t => typeof(IComponentAction).IsAssignableFrom(t)
&& !t.IsAbstract);
foreach (var type in actionTypes)
{
var action = (IComponentAction)Activator.CreateInstance(type);
actions[action.Name] = action;
}
}
/// <summary>
/// 获取操作
/// </summary>
public IComponentAction GetAction(string name)
{
return actions.TryGetValue(name, out var action) ? action : null;
}
/// <summary>
/// 获取所有操作
/// </summary>
public IEnumerable<IComponentAction> GetAllActions()
{
return actions.Values;
}
/// <summary>
/// 获取某个类别的操作
/// </summary>
public IEnumerable<IComponentAction> GetActionsByCategory(string category)
{
return actions.Values.Where(a => a.Category == category);
}
}
public interface IComponentAction
{
string Name { get; }
string DisplayName { get; }
string Category { get; }
LcSolid3d Execute(ActionContext context);
}
15.6 扩展点总结
15.6.1 LightCAD可扩展的维度
| 扩展维度 | 接口/机制 | 说明 |
|---|---|---|
| 元素类型 | IElementPlugin / ElementTypeRegistry | 定义新的图元类型 |
| 命令 | ICommandPlugin / CommandRegistry | 添加新的用户命令 |
| 建模操作 | IComponentAction / ComponentActionLoader | 添加3D建模操作 |
| UI菜单 | IUIPlugin / MenuRegistry | 扩展菜单系统 |
| UI工具栏 | IUIPlugin / ToolbarRegistry | 添加工具栏按钮 |
| UI面板 | IUIPlugin / PanelRegistry | 添加侧边面板 |
| 文件格式 | IFormatPlugin / FormatConverter | 支持新的文件格式 |
| 捕捉类型 | ISnapProvider / SnapManager | 自定义捕捉行为 |
15.7 本章小结
本章详细介绍了LightCAD的插件系统和扩展开发方法。LightCAD基于Weikio Plugin Framework提供了灵活的插件加载机制,支持运行时动态加载插件。通过IPlugin及其扩展接口(ICommandPlugin、IElementPlugin、IUIPlugin),开发者可以在多个维度上扩展LightCAD的功能。内置的五个行业插件展示了实际的插件应用场景。ComponentActionLoader专门用于加载3D建模操作,是建模扩展的核心入口。
上一章:第十四章:文件格式与数据交换
下一章:第十六章:命令与操作系统