Files
LanMountainDesktop/docs/01-AirApp开发/01-快速开始/02-创建第一个轻应用.md
2026-08-11 23:03:55 +08:00

531 lines
14 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 创建第一个轻应用
通过这个教程,你将在 15 分钟内创建一个简单但功能完整的轻应用。
## 学习目标
- ✅ 使用模板创建轻应用项目
- ✅ 实现轻应用入口类
- ✅ 创建一个简单的桌面组件
- ✅ 注册组件到宿主
- ✅ 运行和测试轻应用
## 前置准备
确保你已经:
- ✅ 安装了 .NET 10 SDK
- ✅ 安装了轻应用模板(参考 [环境准备](01-环境准备.md)
- ✅ 有一个支持 C# 的 IDE
## 步骤 1: 创建项目
### 使用模板创建
```powershell
# 创建新轻应用项目
dotnet new lmd-airapp -n HelloWorldAirApp
# 进入项目目录
cd HelloWorldAirApp
# 还原依赖
dotnet restore
```
### 项目结构预览
```
HelloWorldAirApp/
├── HelloWorldAirApp.csproj # 项目文件
├── AirApp.cs # 轻应用入口(我们要修改这个)
├── airapp.json # 轻应用清单(我们要修改这个)
├── Components/
│ └── SampleComponent.cs # 示例组件(我们要修改这个)
├── Views/
│ └── SampleComponentView.axaml # 组件视图(我们要修改这个)
├── ViewModels/
│ └── SampleComponentViewModel.cs
├── Assets/
│ └── icon.png # 轻应用图标
└── Settings/
└── AirAppSettingsPage.axaml # 设置页
```
## 步骤 2: 配置轻应用清单
编辑 `airapp.json`,修改基本信息:
```json
{
"Id": "com.example.helloworldplugin",
"Name": "Hello World AirApp",
"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: 实现轻应用入口
编辑 `AirApp.cs`
```csharp
using LanMountainDesktop.AirAppSdk;
using LanMountainDesktop.Shared.Contracts;
using HelloWorldAirApp.Components;
using HelloWorldAirApp.Views;
using HelloWorldAirApp.ViewModels;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
namespace HelloWorldAirApp;
/// <summary>
/// Hello World 轻应用入口
/// </summary>
public class AirApp : IAirApp
{
public string Id => "com.example.helloworldplugin";
public string Name => "Hello World AirApp";
public string Version => "1.0.0";
private IAirAppRuntimeContext? _context;
/// <summary>
/// 轻应用初始化
/// </summary>
public async Task InitializeAsync(IAirAppRuntimeContext context)
{
_context = context;
// 记录日志
context.Logger.LogInformation("Hello World AirApp 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 AirApp is shutting down..."
);
// 清理资源(如果有)
await Task.CompletedTask;
}
}
```
### 代码说明
1. **实现 IAirApp 接口** - 定义轻应用的基本信息和生命周期
2. **InitializeAsync** - 轻应用加载时调用,注册组件和服务
3. **ShutdownAsync** - 轻应用卸载时调用,清理资源
4. **日志记录** - 使用 `context.Logger` 记录日志
## 步骤 4: 创建组件类
编辑 `Components/SampleComponent.cs`,重命名为 `HelloWorldComponent.cs`
```csharp
using LanMountainDesktop.AirAppSdk.Components;
using LanMountainDesktop.Shared.Contracts.Components;
using System.ComponentModel;
namespace HelloWorldAirApp.Components;
/// <summary>
/// Hello World 桌面组件
/// </summary>
[Component(
Id = "com.example.helloworldplugin.helloworld",
Name = "Hello World",
Description = "Displays a friendly greeting message",
Category = "Demo",
Icon = "avares://HelloWorldAirApp/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`
```xml
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="using:HelloWorldAirApp.ViewModels"
x:Class="HelloWorldAirApp.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`
```csharp
using Avalonia.Controls;
namespace HelloWorldAirApp.Views;
public partial class HelloWorldComponentView : UserControl
{
public HelloWorldComponentView()
{
InitializeComponent();
}
}
```
### 视图说明
- **动态资源** - 使用 `{DynamicResource}` 适配主题
- **圆角规范** - 使用 `DesignCornerRadiusComponent` 保持一致性
- **数据绑定** - 使用 `{Binding}` 绑定到 ViewModel
- **响应式布局** - 使用 `StackPanel` 自动布局
## 步骤 6: 创建视图模型
编辑 `ViewModels/SampleComponentViewModel.cs`,重命名为 `HelloWorldComponentViewModel.cs`
```csharp
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using HelloWorldAirApp.Components;
namespace HelloWorldAirApp.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: 构建轻应用
```powershell
# 构建项目
dotnet build -c Release
# 查看输出
dir bin\Release\net10.0\
```
输出目录应包含:
- `HelloWorldAirApp.dll` - 主程序集
- `airapp.json` - 轻应用清单
- `Assets/` - 资源文件
- 依赖的 DLL 文件
## 步骤 8: 安装和测试
### 方法 1: 复制到轻应用目录
```powershell
# 创建轻应用目录
$pluginDir = "$env:LOCALAPPDATA\LanMountainDesktop\plugins\HelloWorldAirApp"
New-Item -ItemType Directory -Path $pluginDir -Force
# 复制文件
Copy-Item -Path "bin\Release\net10.0\*" -Destination $pluginDir -Recurse -Force
# 启动宿主应用
# (从开始菜单或安装目录启动)
```
### 方法 2: 使用符号链接(开发模式)
```powershell
# 需要管理员权限
$pluginDir = "$env:LOCALAPPDATA\LanMountainDesktop\plugins\HelloWorldAirApp"
$buildDir = "$(pwd)\bin\Release\net10.0"
New-Item -ItemType SymbolicLink -Path $pluginDir -Target $buildDir -Force
```
### 验证轻应用加载
1. 启动阑山桌面
2. 查看日志文件:
```powershell
Get-Content "$env:LOCALAPPDATA\LanMountainDesktop\logs\latest.log" -Tail 50
```
3. 应该看到类似输出:
```
[INFO] Hello World AirApp is initializing...
[INFO] HelloWorldComponent registered successfully
```
### 添加组件到桌面
1. 右键点击桌面空白处
2. 选择"添加组件"
3. 找到"Hello World"组件
4. 点击添加
5. 组件应该出现在桌面上
### 测试功能
1. 点击"Click Me!"按钮
2. 观察点击次数增加
3. 观察问候语在不同语言间切换
4. 重启应用,验证设置持久化
## 步骤 9: 调试轻应用
### 附加调试器
1. 启动阑山桌面应用
2. 在 Visual Studio 中:
- 选择"调试" → "附加到进程"
- 找到 `LanMountainDesktop.exe`
- 点击"附加"
3. 在轻应用代码中设置断点
4. 触发相应功能(如点击按钮)
### 查看日志
```powershell
# 实时查看日志
Get-Content "$env:LOCALAPPDATA\LanMountainDesktop\logs\latest.log" -Wait -Tail 50
```
### 常见问题
#### 轻应用没有加载
**检查清单**:
1. `airapp.json` 存在且格式正确
2. 轻应用 DLL 文件存在
3. 查看日志中的错误信息
4. 确认轻应用 ID 唯一
#### 组件没有显示
**检查清单**:
1. 组件已正确注册
2. 组件 ID 唯一
3. 视图文件正确编译为 AvaloniaResource
4. DataContext 正确设置
#### 按钮点击没有响应
**检查清单**:
1. Command 绑定正确
2. ViewModel 方法存在
3. 查看日志中的异常信息
## 下一步
恭喜!你已经创建了第一个轻应用。接下来可以:
- [轻应用生命周期](../02-核心概念/01-轻应用生命周期.md) - 深入理解轻应用运行机制
- [组件系统详解](../02-核心概念/02-组件系统.md) - 学习更多组件功能
- [设置系统](../02-核心概念/03-设置系统.md) - 添加设置页面
- [实战案例](../04-实战案例/01-天气组件.md) - 学习完整的实战案例
## 完整代码仓库
本教程的完整代码可以在以下位置找到:
- GitHub: https://github.com/HelloWRC/LanMountainDesktop.SampleAirApp
## 小结
在这个教程中,你学会了:
- ✅ 使用模板创建轻应用项目
- ✅ 配置轻应用清单
- ✅ 实现轻应用入口类
- ✅ 创建桌面组件(模型、视图、视图模型)
- ✅ 注册组件到宿主
- ✅ 使用设置系统持久化数据
- ✅ 构建、安装和测试轻应用
- ✅ 调试轻应用代码
这是一个完整但简单的轻应用,展示了轻应用开发的基本流程。在实际项目中,你可以添加更多功能,如网络请求、定时任务、复杂 UI 等。