Skip to content

Latest commit

 

History

History
481 lines (355 loc) · 11.3 KB

File metadata and controls

481 lines (355 loc) · 11.3 KB

快速开始

5 分钟上手 EclipseUI

安装

前置要求

  • .NET 10.0 SDK 或更高版本
  • Windows 10/11(目前仅支持 Windows)

克隆项目

git clone https://github.com/CeSun/EclipseUI.git
cd EclipseUI

构建

dotnet build EclipseUI.sln

创建第一个应用

1. 创建项目

# 创建新的控制台应用
dotnet new console -n MyFirstApp

# 添加 EclipseUI 引用
cd MyFirstApp
dotnet add reference ../EclipseUI/src/Eclipse.Core
dotnet add reference ../EclipseUI/src/Eclipse.Controls
dotnet add reference ../EclipseUI/src/Eclipse.Skia
dotnet add reference ../EclipseUI/src/Eclipse.Windows

2. 创建 EUI 文件

创建 Components/HomePage.eui

@using Eclipse.Controls

<StackLayout Spacing="16" Padding="20">
    <Label Text="你好 EclipseUI! 🎉" FontSize="32" />
    <Label Text="@_countText" FontSize="18" Color="#666666" />
    <Button Text="点击我" OnClick="@OnButtonClick" />
</StackLayout>

@code {
    private int _count = 0;
    
    private string _countText => _count > 0 
        ? $"点击次数: {_count}" 
        : "点击按钮开始计数";
    
    private void OnButtonClick(object? sender, EventArgs e)
    {
        _count++;
        StateHasChanged();
    }
}

3. 配置项目文件

修改 MyFirstApp.csproj,添加 EUI 文件支持:

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <OutputType>WinExe</OutputType>
    <TargetFramework>net10.0-windows</TargetFramework>
    <RootNamespace>MyFirstApp</RootNamespace>
  </PropertyGroup>

  <ItemGroup>
    <!-- 引用 EclipseUI 项目 -->
    <ProjectReference Include="..\EclipseUI\src\Eclipse.Core\Eclipse.Core.csproj" />
    <ProjectReference Include="..\EclipseUI\src\Eclipse.Controls\Eclipse.Controls.csproj" />
    <ProjectReference Include="..\EclipseUI\src\Eclipse.Skia\Eclipse.Skia.csproj" />
    <ProjectReference Include="..\EclipseUI\src\Eclipse.Windows\Eclipse.Windows.csproj" />
    
    <!-- 添加 EUI 文件作为 AdditionalFiles -->
    <AdditionalFiles Include="Components\**\*.eui" />
    
    <!-- 引用 Source Generator -->
    <ProjectReference Include="..\EclipseUI\src\Eclipse.Generator\Eclipse.Generator.csproj" 
                      OutputItemType="Analyzer" 
                      ReferenceOutputAssembly="false" />
  </ItemGroup>
</Project>

4. 配置入口

修改 Program.cs

using Eclipse.Core;
using Eclipse.Skia;
using Eclipse.Windows;

class Program
{
    static void Main(string[] args)
    {
        // 创建应用
        var app = AppBuilder.Create()
            .UseSkiaRenderer()
            .UseWindowsWindow()
            .Build();
        
        // 运行主页面
        app.Run<HomePage>();
    }
}

5. 运行应用

dotnet run

Source Generator 工作原理

编译时代码生成

EUI 文件在编译时由 Source Generator 转换为 C# 代码:

HomePage.eui → HomePage.eui.g.cs → 编译到程序集

生成的代码示例:

// <auto-generated />
// Generated from HomePage.eui
#nullable enable

using System;
using Eclipse.Core;
using Eclipse.Core.Abstractions;
using Eclipse.Controls;

namespace MyFirstApp.Components
{
    public partial class HomePage : ComponentBase
    {
        private int _count = 0;
        
        private string _countText => _count > 0 
            ? $"点击次数: {_count}" 
            : "点击按钮开始计数";
        
        private void OnButtonClick(object? sender, EventArgs e)
        {
            _count++;
            StateHasChanged();
        }
        
        public override void Build(IBuildContext context)
        {
            using (context.BeginComponent<StackLayout>(new ComponentId(1), out var __stacklayout_1))
            {
                __stacklayout_1.Spacing = 16;
                __stacklayout_1.Padding = 20;
                
                using (context.BeginChildContent())
                {
                    using (context.BeginComponent<Label>(new ComponentId(2), out var __label_2))
                    {
                        __label_2.Text = "你好 EclipseUI! 🎉";
                        __label_2.FontSize = 32;
                    }
                    
                    using (context.BeginComponent<Label>(new ComponentId(3), out var __label_3))
                    {
                        __label_3.Text = _countText?.ToString();
                        __label_3.FontSize = 18;
                        __label_3.Color = "#666666";
                    }
                    
                    using (context.BeginComponent<Button>(new ComponentId(4), out var __button_4))
                    {
                        __button_4.Text = "点击我";
                        __button_4.OnClick += OnButtonClick;
                    }
                }
            }
        }
    }
}

类型智能转换

Generator 会根据目标属性类型自动转换字面量:

EUI 写法 属性类型 生成代码
FontSize="24" double FontSize = 24
IsChecked="true" bool IsChecked = true
TextAlignment="Center" TextAlignment TextAlignment = TextAlignment.Center
Color="#FF0000" Color Color = Color.FromHex("#FF0000")
Padding="16,8" Thickness Padding = new Thickness(16, 8)

命名空间推断

生成的组件命名空间按以下规则推断:

  1. @namespace 指令(最高优先级)
  2. MSBuild RootNamespace + 相对路径
  3. 默认值 Eclipse.Generated

示例:

项目: MyApp.csproj (<RootNamespace>MyApp</RootNamespace>)
文件: Components/Pages/HomePage.eui

生成命名空间: MyApp.Components.Pages

诊断信息

Generator 会报告编译时诊断:

诊断码 说明
ECGEN001 组件生成失败
ECGEN002 Markup 解析错误
ECGEN003 控件类型未找到(警告)

运行示例项目

项目包含一个完整的示例应用:

cd samples/SkiaDemo
dotnet run

示例应用展示:

  • ✅ 基础控件(Label、Button、TextInput)
  • ✅ 布局控件(StackLayout、Grid、ScrollView)
  • ✅ 交互控件(CheckBox)
  • ✅ 图片显示(Image)
  • ✅ Emoji 文本渲染

项目结构

EclipseUI/
├── src/
│   ├── Eclipse.Core/       # 核心抽象层
│   │   ├── BuildContext    # 组件构建上下文
│   │   ├── ComponentBase   # 组件基类
│   │   └── Input/          # 输入系统
│   │
│   ├── Eclipse.Controls/   # UI 控件库
│   │   ├── Label           # 文本显示
│   │   ├── Button          # 按钮
│   │   ├── TextInput       # 文本输入(支持光标、键盘)
│   │   ├── StackLayout     # 堆叠布局
│   │   ├── Grid            # 网格布局
│   │   └── ScrollView      # 滚动视图
│   │
│   ├── Eclipse.Skia/       # SkiaSharp 渲染层
│   │   └── Text/           # 文本系统
│   │       ├── HarfBuzz    # 文本塑形
│   │       └ EmojiDetector # Emoji 检测
│   │
│   ├── Eclipse.Generator/  # EUI Source Generator
│   │   └── EclipseSourceGenerator.cs
│   │
│   └── Eclipse.Windows/    # Windows 平台支持
│
├── samples/
│   └── Demo/             # 示例应用
│
├── tests/
│   └── Eclipse.Tests/      # 单元测试(137 个测试)
│
└── docs/
    ├── architecture.md     # 架构设计
    ├── syntax.md           # EUI 语法参考
    └── getting-started.md  # 快速开始(本文档)

核心概念

组件 (Component)

组件是 EclipseUI 的基本构建单元。所有 UI 元素都继承自 ComponentBase

public abstract class ComponentBase : IComponent
{
    // 子元素集合
    public ComponentCollection Children { get; }
    
    // 脏标记(用于增量更新)
    protected bool IsDirty { get; set; } = true;
    
    // 构建 UI
    public abstract void Build(IBuildContext context);
    
    // 渲染
    public abstract void Render(IDrawingContext context, Rect bounds);
    
    // 触发重新渲染
    protected void StateHasChanged();
}

Measure/Arrange 布局系统

控件实现 Measure()Arrange() 方法:

public class StackLayout : ComponentBase
{
    public Size Measure(Size availableSize, IDrawingContext context);
    public void Arrange(Rect finalBounds, IDrawingContext context);
}
  • Measure: 计算控件所需尺寸
  • Arrange: 安排子元素位置

输入系统

EclipseUI 提供完整的输入事件系统:

指针事件:

  • PointerPressed / PointerReleased
  • PointerMoved / PointerEntered / PointerExited
  • PointerWheelChanged
  • Tapped

键盘事件:

  • KeyDown / KeyUp
  • TextInput

事件路由:

  • Bubble - 从源元素向上传播
  • Tunnel - 从根元素向下传播
  • Direct - 仅在源元素触发

下一步

学习 EUI 语法

阅读 EUI 语法参考 了解:

  • 完整指令列表(@using, @namespace, @code, @inherits, @inject, @attribute)
  • 强类型属性系统
  • 复杂类型转换(Color, Thickness, Point 等)
  • 控制流(@if, @foreach)
  • 事件处理

理解架构设计

阅读 架构设计 了解:

  • SkiaSharp 渲染原理
  • 文本塑形系统
  • Source Generator 工作流程
  • 跨平台架构设计

探索示例代码

查看 samples/Demo 目录:

  • Components/HomePage.eui - 主页面
  • Components/DemoControls.eui - 控件演示
  • Components/DemoLayout.eui - 布局演示

常见问题

Q: 为什么只支持 Windows?

EclipseUI 目前处于早期开发阶段,优先支持 Windows 平台。未来计划支持:

  • macOS
  • Linux
  • Android
  • iOS

Q: EUI 和 Razor 有什么区别?

特性 Razor EUI
目标 Web 跨平台 UI
渲染 HTML SkiaSharp
运行时 Blazor Server/WebAssembly 原生窗口
类型系统 运行时动态 编译时强类型

Q: 如何处理图片?

<Image Source="assets/photo.png" Stretch="Uniform" />

图片路径相对于应用目录。支持格式:PNG, JPEG, WEBP, GIF, BMP。

Q: 如何自定义控件?

继承 InteractiveControlComponentBase

public class MyControl : InteractiveControl
{
    public string? MyProperty { get; set; }
    
    public override Size Measure(Size availableSize, IDrawingContext context)
    {
        return new Size(100, 50);
    }
    
    public override void Render(IDrawingContext context, Rect bounds)
    {
        context.DrawRectangle(bounds, "#FF0000");
    }
}

Q: 控件类型找不到怎么办?

确保使用 @using 引入命名空间:

@using Eclipse.Controls
@using MyApp.CustomControls  <!-- 自定义控件 -->

<MyControl ... />

如果仍有警告(ECGEN003),检查类型名称是否正确。


参与贡献

欢迎提交 Issue 和 Pull Request!

贡献指南:

  1. Fork 项目
  2. 创建功能分支 (git checkout -b feature/amazing-feature)
  3. 提交更改 (git commit -m 'Add amazing feature')
  4. 推送分支 (git push origin feature/amazing-feature)
  5. 提交 Pull Request

许可证

MIT License - 自由使用、修改和分发。