mirror of
https://github.com/wwiinnddyy/LanMountainDesktop.git
synced 2026-06-20 23:54:26 +08:00
14 KiB
14 KiB
创建第一个插件
通过这个教程,你将在 15 分钟内创建一个简单但功能完整的插件。
学习目标
- ✅ 使用模板创建插件项目
- ✅ 实现插件入口类
- ✅ 创建一个简单的桌面组件
- ✅ 注册组件到宿主
- ✅ 运行和测试插件
前置准备
确保你已经:
- ✅ 安装了 .NET 10 SDK
- ✅ 安装了插件模板(参考 环境准备)
- ✅ 有一个支持 C# 的 IDE
步骤 1: 创建项目
使用模板创建
# 创建新插件项目
dotnet new lmd-plugin -n HelloWorldPlugin
# 进入项目目录
cd HelloWorldPlugin
# 还原依赖
dotnet restore
项目结构预览
HelloWorldPlugin/
├── HelloWorldPlugin.csproj # 项目文件
├── Plugin.cs # 插件入口(我们要修改这个)
├── plugin.json # 插件清单(我们要修改这个)
├── Components/
│ └── SampleComponent.cs # 示例组件(我们要修改这个)
├── Views/
│ └── SampleComponentView.axaml # 组件视图(我们要修改这个)
├── ViewModels/
│ └── SampleComponentViewModel.cs
├── Assets/
│ └── icon.png # 插件图标
└── Settings/
└── PluginSettingsPage.axaml # 设置页
步骤 2: 配置插件清单
编辑 plugin.json,修改基本信息:
{
"Id": "com.example.helloworldplugin",
"Name": "Hello World Plugin",
"Version": "1.0.0",
"Author": "Your Name",
"Description": "My first LanMountainDesktop plugin - displays a greeting",
"MinHostVersion": "1.0.0",
"SdkVersion": "5.0.0",
"Dependencies": [],
"Permissions": [],
"Icon": "Assets/icon.png",
"Homepage": "https://github.com/yourusername/helloworldplugin"
}
字段说明
- Id: 插件唯一标识符,建议使用反向域名格式
- Name: 用户看到的插件名称
- Version: 插件版本号(语义化版本)
- MinHostVersion: 最低支持的宿主版本
- SdkVersion: 使用的 SDK 版本
步骤 3: 实现插件入口
编辑 Plugin.cs:
using LanMountainDesktop.PluginSdk;
using LanMountainDesktop.Shared.Contracts;
using HelloWorldPlugin.Components;
using HelloWorldPlugin.Views;
using HelloWorldPlugin.ViewModels;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
namespace HelloWorldPlugin;
/// <summary>
/// Hello World 插件入口
/// </summary>
public class Plugin : IPlugin
{
public string Id => "com.example.helloworldplugin";
public string Name => "Hello World Plugin";
public string Version => "1.0.0";
private IPluginContext? _context;
/// <summary>
/// 插件初始化
/// </summary>
public async Task InitializeAsync(IPluginContext context)
{
_context = context;
// 记录日志
context.Logger.LogInformation("Hello World Plugin is initializing...");
// 获取组件注册表
var componentRegistry = context.Services
.GetService<IComponentRegistry>();
if (componentRegistry != null)
{
// 注册 Hello World 组件
componentRegistry.RegisterComponent<HelloWorldComponent>(
componentFactory: () => new HelloWorldComponent(),
viewFactory: (component) => new HelloWorldComponentView
{
DataContext = new HelloWorldComponentViewModel(
(HelloWorldComponent)component
)
}
);
context.Logger.LogInformation(
"HelloWorldComponent registered successfully"
);
}
// 异步操作示例(如果需要)
await Task.CompletedTask;
}
/// <summary>
/// 插件关闭
/// </summary>
public async Task ShutdownAsync()
{
_context?.Logger.LogInformation(
"Hello World Plugin is shutting down..."
);
// 清理资源(如果有)
await Task.CompletedTask;
}
}
代码说明
- 实现 IPlugin 接口 - 定义插件的基本信息和生命周期
- InitializeAsync - 插件加载时调用,注册组件和服务
- ShutdownAsync - 插件卸载时调用,清理资源
- 日志记录 - 使用
context.Logger记录日志
步骤 4: 创建组件类
编辑 Components/SampleComponent.cs,重命名为 HelloWorldComponent.cs:
using LanMountainDesktop.PluginSdk.Components;
using LanMountainDesktop.Shared.Contracts.Components;
using System.ComponentModel;
namespace HelloWorldPlugin.Components;
/// <summary>
/// Hello World 桌面组件
/// </summary>
[Component(
Id = "com.example.helloworldplugin.helloworld",
Name = "Hello World",
Description = "Displays a friendly greeting message",
Category = "Demo",
Icon = "avares://HelloWorldPlugin/Assets/icon.png"
)]
public class HelloWorldComponent : ComponentBase
{
public override string Id => "com.example.helloworldplugin.helloworld";
public override string Name => "Hello World";
private string _greeting = "Hello, World!";
private int _clickCount = 0;
/// <summary>
/// 问候语
/// </summary>
public string Greeting
{
get => _greeting;
set => SetProperty(ref _greeting, value);
}
/// <summary>
/// 点击次数
/// </summary>
public int ClickCount
{
get => _clickCount;
set => SetProperty(ref _clickCount, value);
}
/// <summary>
/// 组件初始化
/// </summary>
public override Task InitializeAsync()
{
// 从设置加载问候语
Greeting = Settings.GetValue("Greeting", "Hello, World!");
ClickCount = Settings.GetValue("ClickCount", 0);
Logger.LogInformation("HelloWorldComponent initialized");
return Task.CompletedTask;
}
/// <summary>
/// 组件更新(定时调用)
/// </summary>
public override Task UpdateAsync()
{
// 这里可以更新组件数据
// 例如:从 API 获取数据、更新时间等
return Task.CompletedTask;
}
/// <summary>
/// 增加点击次数
/// </summary>
public void IncrementClickCount()
{
ClickCount++;
Settings.SetValue("ClickCount", ClickCount);
}
}
组件说明
- ComponentBase - 所有组件的基类,提供基础功能
- 属性通知 - 使用
SetProperty自动触发 UI 更新 - 设置持久化 - 使用
Settings保存和读取配置 - InitializeAsync - 组件创建时调用
- UpdateAsync - 定时调用(默认 1 秒),用于更新数据
步骤 5: 创建组件视图
编辑 Views/SampleComponentView.axaml,重命名为 HelloWorldComponentView.axaml:
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="using:HelloWorldPlugin.ViewModels"
x:Class="HelloWorldPlugin.Views.HelloWorldComponentView"
x:DataType="vm:HelloWorldComponentViewModel">
<!-- 组件容器 -->
<Border Background="{DynamicResource CardBackgroundBrush}"
CornerRadius="{DynamicResource DesignCornerRadiusComponent}"
Padding="20"
BorderBrush="{DynamicResource CardBorderBrush}"
BorderThickness="1">
<StackPanel Spacing="12">
<!-- 标题 -->
<TextBlock Text="{Binding Component.Name}"
FontSize="18"
FontWeight="Bold"
Foreground="{DynamicResource TextFillColorPrimaryBrush}" />
<!-- 问候语 -->
<TextBlock Text="{Binding Component.Greeting}"
FontSize="16"
Foreground="{DynamicResource TextFillColorSecondaryBrush}"
TextWrapping="Wrap" />
<!-- 点击次数 -->
<TextBlock Foreground="{DynamicResource TextFillColorTertiaryBrush}">
<Run Text="Clicks: " />
<Run Text="{Binding Component.ClickCount}" FontWeight="Bold" />
</TextBlock>
<!-- 按钮 -->
<Button Content="Click Me!"
Command="{Binding ClickCommand}"
HorizontalAlignment="Stretch"
Padding="12,8" />
</StackPanel>
</Border>
</UserControl>
编辑对应的代码后台 HelloWorldComponentView.axaml.cs:
using Avalonia.Controls;
namespace HelloWorldPlugin.Views;
public partial class HelloWorldComponentView : UserControl
{
public HelloWorldComponentView()
{
InitializeComponent();
}
}
视图说明
- 动态资源 - 使用
{DynamicResource}适配主题 - 圆角规范 - 使用
DesignCornerRadiusComponent保持一致性 - 数据绑定 - 使用
{Binding}绑定到 ViewModel - 响应式布局 - 使用
StackPanel自动布局
步骤 6: 创建视图模型
编辑 ViewModels/SampleComponentViewModel.cs,重命名为 HelloWorldComponentViewModel.cs:
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using HelloWorldPlugin.Components;
namespace HelloWorldPlugin.ViewModels;
/// <summary>
/// Hello World 组件视图模型
/// </summary>
public partial class HelloWorldComponentViewModel : ObservableObject
{
[ObservableProperty]
private HelloWorldComponent _component;
public HelloWorldComponentViewModel(HelloWorldComponent component)
{
_component = component;
}
/// <summary>
/// 点击按钮命令
/// </summary>
[RelayCommand]
private void Click()
{
Component.IncrementClickCount();
// 更新问候语
var greetings = new[]
{
"Hello, World!",
"你好,世界!",
"Bonjour le monde!",
"Hola, Mundo!",
"Привет, мир!",
"こんにちは、世界!"
};
var index = Component.ClickCount % greetings.Length;
Component.Greeting = greetings[index];
// 保存问候语
Component.Settings.SetValue("Greeting", Component.Greeting);
}
}
ViewModel 说明
- ObservableObject - MVVM Toolkit 基类,提供属性通知
- [ObservableProperty] - 自动生成属性和通知代码
- [RelayCommand] - 自动生成命令
- 业务逻辑 - 处理用户交互和数据更新
步骤 7: 构建插件
# 构建项目
dotnet build -c Release
# 查看输出
dir bin\Release\net10.0\
输出目录应包含:
HelloWorldPlugin.dll- 主程序集plugin.json- 插件清单Assets/- 资源文件- 依赖的 DLL 文件
步骤 8: 安装和测试
方法 1: 复制到插件目录
# 创建插件目录
$pluginDir = "$env:LOCALAPPDATA\LanMountainDesktop\plugins\HelloWorldPlugin"
New-Item -ItemType Directory -Path $pluginDir -Force
# 复制文件
Copy-Item -Path "bin\Release\net10.0\*" -Destination $pluginDir -Recurse -Force
# 启动宿主应用
# (从开始菜单或安装目录启动)
方法 2: 使用符号链接(开发模式)
# 需要管理员权限
$pluginDir = "$env:LOCALAPPDATA\LanMountainDesktop\plugins\HelloWorldPlugin"
$buildDir = "$(pwd)\bin\Release\net10.0"
New-Item -ItemType SymbolicLink -Path $pluginDir -Target $buildDir -Force
验证插件加载
- 启动阑山桌面
- 查看日志文件:
Get-Content "$env:LOCALAPPDATA\LanMountainDesktop\logs\latest.log" -Tail 50 - 应该看到类似输出:
[INFO] Hello World Plugin is initializing... [INFO] HelloWorldComponent registered successfully
添加组件到桌面
- 右键点击桌面空白处
- 选择"添加组件"
- 找到"Hello World"组件
- 点击添加
- 组件应该出现在桌面上
测试功能
- 点击"Click Me!"按钮
- 观察点击次数增加
- 观察问候语在不同语言间切换
- 重启应用,验证设置持久化
步骤 9: 调试插件
附加调试器
- 启动阑山桌面应用
- 在 Visual Studio 中:
- 选择"调试" → "附加到进程"
- 找到
LanMountainDesktop.exe - 点击"附加"
- 在插件代码中设置断点
- 触发相应功能(如点击按钮)
查看日志
# 实时查看日志
Get-Content "$env:LOCALAPPDATA\LanMountainDesktop\logs\latest.log" -Wait -Tail 50
常见问题
插件没有加载
检查清单:
plugin.json存在且格式正确- 插件 DLL 文件存在
- 查看日志中的错误信息
- 确认插件 ID 唯一
组件没有显示
检查清单:
- 组件已正确注册
- 组件 ID 唯一
- 视图文件正确编译为 AvaloniaResource
- DataContext 正确设置
按钮点击没有响应
检查清单:
- Command 绑定正确
- ViewModel 方法存在
- 查看日志中的异常信息
下一步
恭喜!你已经创建了第一个插件。接下来可以:
完整代码仓库
本教程的完整代码可以在以下位置找到:
小结
在这个教程中,你学会了:
- ✅ 使用模板创建插件项目
- ✅ 配置插件清单
- ✅ 实现插件入口类
- ✅ 创建桌面组件(模型、视图、视图模型)
- ✅ 注册组件到宿主
- ✅ 使用设置系统持久化数据
- ✅ 构建、安装和测试插件
- ✅ 调试插件代码
这是一个完整但简单的插件,展示了插件开发的基本流程。在实际项目中,你可以添加更多功能,如网络请求、定时任务、复杂 UI 等。