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

14 KiB
Raw Permalink Blame History

创建第一个轻应用

通过这个教程,你将在 15 分钟内创建一个简单但功能完整的轻应用。

学习目标

  • 使用模板创建轻应用项目
  • 实现轻应用入口类
  • 创建一个简单的桌面组件
  • 注册组件到宿主
  • 运行和测试轻应用

前置准备

确保你已经:

  • 安装了 .NET 10 SDK
  • 安装了轻应用模板(参考 环境准备
  • 有一个支持 C# 的 IDE

步骤 1: 创建项目

使用模板创建

# 创建新轻应用项目
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,修改基本信息:

{
  "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

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

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

<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

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

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: 构建轻应用

# 构建项目
dotnet build -c Release

# 查看输出
dir bin\Release\net10.0\

输出目录应包含:

  • HelloWorldAirApp.dll - 主程序集
  • airapp.json - 轻应用清单
  • Assets/ - 资源文件
  • 依赖的 DLL 文件

步骤 8: 安装和测试

方法 1: 复制到轻应用目录

# 创建轻应用目录
$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: 使用符号链接(开发模式)

# 需要管理员权限
$pluginDir = "$env:LOCALAPPDATA\LanMountainDesktop\plugins\HelloWorldAirApp"
$buildDir = "$(pwd)\bin\Release\net10.0"

New-Item -ItemType SymbolicLink -Path $pluginDir -Target $buildDir -Force

验证轻应用加载

  1. 启动阑山桌面
  2. 查看日志文件:
    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. 触发相应功能(如点击按钮)

查看日志

# 实时查看日志
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. 查看日志中的异常信息

下一步

恭喜!你已经创建了第一个轻应用。接下来可以:

完整代码仓库

本教程的完整代码可以在以下位置找到:

小结

在这个教程中,你学会了:

  • 使用模板创建轻应用项目
  • 配置轻应用清单
  • 实现轻应用入口类
  • 创建桌面组件(模型、视图、视图模型)
  • 注册组件到宿主
  • 使用设置系统持久化数据
  • 构建、安装和测试轻应用
  • 调试轻应用代码

这是一个完整但简单的轻应用,展示了轻应用开发的基本流程。在实际项目中,你可以添加更多功能,如网络请求、定时任务、复杂 UI 等。