UnoPlatform跨平台开发技能 dotnet-uno-platform

Uno Platform 是一个基于 .NET 的跨平台应用开发框架,支持单项目结构、MVUX 响应式模式、Toolkit 控件、Material/Cupertino/Fluent 主题资源、热重载等功能。用于构建适用于 Web、移动和桌面的应用程序,关键词包括 Uno Platform、.NET、跨平台开发、MVUX、Toolkit、热重载、XAML、iOS、Android、WASM。

移动开发 0 次安装 0 次浏览 更新于 3/6/2026

名称: dotnet-uno-platform 描述: “构建 Uno Platform 跨平台应用。扩展、MVUX、Toolkit 控件、热重载。” 用户可调用: false

dotnet-uno-platform

Uno Platform 核心开发:扩展生态系统(导航、依赖注入、配置、序列化、本地化、日志记录、HTTP、身份验证)、MVUX 响应式模式、Toolkit 控件、主题资源(Material/Cupertino/Fluent)、热重载和单项目结构。涵盖基于 .NET 8.0+ 的 Uno Platform 5.x+。

范围

  • Uno Platform 单项目结构,带条件目标框架
  • 扩展生态系统(导航、依赖注入、配置、序列化、HTTP、身份验证)
  • MVUX 响应式模式
  • Toolkit 控件和主题资源(Material/Cupertino/Fluent)
  • 热重载

超出范围

  • 按目标部署(WASM、iOS、Android、桌面)——见 [技能:dotnet-uno-targets]
  • MCP 服务器集成以获取实时文档——见 [技能:dotnet-uno-mcp]
  • Uno Platform 测试——见 [技能:dotnet-uno-testing]
  • 通用序列化模式——见 [技能:dotnet-serialization]
  • WASM 的 AOT/裁剪——见 [技能:dotnet-aot-wasm]
  • UI 框架选择决策树——见 [技能:dotnet-ui-chooser]

交叉引用:[技能:dotnet-uno-targets] 用于按目标部署,[技能:dotnet-uno-mcp] 用于 MCP 集成,[技能:dotnet-uno-testing] 用于测试模式,[技能:dotnet-serialization] 用于序列化深度,[技能:dotnet-aot-wasm] 用于 WASM AOT,[技能:dotnet-ui-chooser] 用于框架选择,[技能:dotnet-accessibility] 用于无障碍模式(WASM 上的 AutomationProperties、ARIA 映射)。


单项目结构

Uno Platform 5.x 使用单项目结构,带条件目标框架以支持多目标。一个 .csproj 通过多目标针对所有平台。

<!-- MyApp.csproj -->
<Project Sdk="Uno.Sdk">
  <PropertyGroup>
    <TargetFrameworks>
      net8.0-browserwasm;
      net8.0-ios;
      net8.0-android;
      net8.0-maccatalyst;
      net8.0-windows10.0.19041;
      net8.0-desktop
    </TargetFrameworks>
    <OutputType>Exe</OutputType>
    <UnoFeatures>
      Extensions;
      Toolkit;
      Material;
      MVUX;
      Navigation;
      Configuration;
      Hosting;
      Http;
      Localization;
      Logging;
      LoggingSerilog;
      Serialization;
      Authentication;
      AuthenticationOidc
    </UnoFeatures>
  </PropertyGroup>
</Project>

UnoFeatures MSBuild 属性控制包含哪些 Uno 扩展和主题包。Uno SDK 自动解析这些功能到正确的 NuGet 包。

项目布局

MyApp/
  MyApp/
    App.xaml / App.xaml.cs        # 应用程序入口、资源字典
    MainPage.xaml / .xaml.cs      # 初始页面
    Presentation/                 # ViewModels 或 MVUX Models
    Views/                        # XAML 页面
    Services/                     # 服务接口和实现
    Strings/                      # 本地化资源 (.resw)
      en/Resources.resw
    Assets/                       # 图像、字体、图标
    appsettings.json              # 配置(Extensions.Configuration)
    Platforms/                    # 平台特定代码(条件编译)
      Android/
      iOS/
      Wasm/
      Desktop/
  MyApp.Tests/                   # 单元测试(共享逻辑)

Uno 扩展

Uno 扩展在平台之上提供基于观点的架构。所有模块通过主机构建器模式注册。

主机构建器设置

// App.xaml.cs
public App()
{
    this.InitializeComponent();

    Host = UnoHost
        .CreateDefaultBuilder()
        .UseConfiguration(configure: configBuilder =>
            configBuilder.EmbeddedSource<App>()
                         .Section<AppConfig>())
        .UseLocalization()
        .UseNavigation(RegisterRoutes)
        .UseSerilog(loggerConfiguration: config =>
            config.WriteTo.Debug())
        .ConfigureServices((context, services) =>
        {
            services.AddSingleton<IProductService, ProductService>();
        })
        .Build();
}

导航

包: Uno.Extensions.Navigation

基于区域的导航,带路由映射、深度链接和类型安全参数传递。导航可从 XAML 声明式或从代码命令式驱动。

// 路由注册
private static void RegisterRoutes(IViewRegistry views, IRouteRegistry routes)
{
    views.Register(
        new ViewMap(ViewModel: typeof(ShellModel)),
        new ViewMap<MainPage, MainModel>(),
        new ViewMap<ProductDetailPage, ProductDetailModel>(),
        new DataViewMap<ProductDetailPage, ProductDetailModel, ProductEntity>()
    );

    routes.Register(
        new RouteMap("", View: views.FindByViewModel<ShellModel>(),
            Nested: new RouteMap[]
            {
                new("Main", View: views.FindByViewModel<MainModel>()),
                new("ProductDetail", View: views.FindByViewModel<ProductDetailModel>())
            })
    );
}
<!-- XAML 基础导航使用附加属性 -->
<Button Content="查看产品"
        uen:Navigation.Request="ProductDetail"
        uen:Navigation.Data="{Binding SelectedProduct}" />

关键概念: 基于区域的导航将导航行为附加到可视区域(Frame、NavigationView、TabBar)。路由映射定义导航图。深度链接将 URL 映射到 WASM 的路由。

依赖注入

包: Uno.Extensions.Hosting

使用 Microsoft.Extensions.Hosting 底层。主机构建器模式带服务注册、键控服务和作用域生命周期。

.ConfigureServices((context, services) =>
{
    // 标准 DI 注册
    services.AddSingleton<IAuthService, AuthService>();
    services.AddTransient<IOrderService, OrderService>();

    // 键控服务 (.NET 8+)
    services.AddKeyedSingleton<ICache>("memory", new MemoryCache());
    services.AddKeyedSingleton<ICache>("distributed", new RedisCache());
})

配置

包: Uno.Extensions.Configuration

appsettings.json(嵌入式资源)、环境特定覆盖和运行时可写选项加载配置。

// appsettings.json
{
  "AppConfig": {
    "ApiBaseUrl": "https://api.example.com",
    "MaxRetries": 3
  }
}
// 绑定到强类型选项
.UseConfiguration(configure: configBuilder =>
    configBuilder
        .EmbeddedSource<App>()
        .Section<AppConfig>())

// AppConfig.cs
public record AppConfig
{
    public string ApiBaseUrl { get; init; } = "";
    public int MaxRetries { get; init; } = 3;
}

序列化

包: Uno.Extensions.Serialization

集成 System.Text.Json 带源生成器以支持 AOT 兼容性。在扩展生态系统中配置 JSON 序列化。

.UseSerialization(configure: serializerBuilder =>
    serializerBuilder
        .AddJsonTypeInfo(AppJsonContext.Default.ProductDto)
        .AddJsonTypeInfo(AppJsonContext.Default.OrderDto))

对于通用序列化模式和 AOT 源生成深度,见 [技能:dotnet-serialization]。

本地化

包: Uno.Extensions.Localization

基于资源的本地化使用 .resw 文件带运行时文化切换。

.UseLocalization()
<!-- Strings/en/Resources.resw -->
<!-- 名称: MainPage_Title.Text, 值: 欢迎 -->
<!-- 名称: MainPage_LoginButton.Content, 值: 登录 -->

<!-- XAML: 使用 x:Uid 进行自动资源绑定 -->
<TextBlock x:Uid="MainPage_Title" />
<Button x:Uid="MainPage_LoginButton" />

运行时文化切换:

// 编程切换文化
var localizationService = serviceProvider.GetRequiredService<ILocalizationService>();
await localizationService.SetCurrentCultureAsync(new CultureInfo("fr-FR"));

日志记录

包: Uno.Extensions.Logging

集成 Microsoft.Extensions.Logging。Serilog 集成用于平台特定接收器。

.UseSerilog(loggerConfiguration: config =>
    config
        .MinimumLevel.Information()
        .WriteTo.Debug()
        .WriteTo.Console())

平台特定接收器:桌面调试输出、WASM 浏览器控制台、Android 平台 Logcat、iOS NSLog。

HTTP

包: Uno.Extensions.Http

HTTP 客户端集成带端点配置。支持 Refit 用于类型化 API 客户端和 Kiota 用于 OpenAPI 生成的客户端。

.UseHttp(configure: (context, services) =>
    services
        .AddRefitClient<IProductApi>(context,
            configure: builder => builder
                .ConfigureHttpClient(client =>
                    client.BaseAddress = new Uri("https://api.example.com"))))
// Refit 接口
public interface IProductApi
{
    [Get("/products")]
    Task<List<ProductDto>> GetProductsAsync(CancellationToken ct = default);

    [Get("/products/{id}")]
    Task<ProductDto> GetProductByIdAsync(int id, CancellationToken ct = default);
}

身份验证

包: Uno.Extensions.Authentication

OIDC、自定义身份验证提供程序和令牌管理。集成导航用于登录/注销流。

.UseAuthentication(auth =>
    auth.AddOidc(oidc =>
    {
        oidc.Authority = "https://login.example.com";
        oidc.ClientId = "my-app";
        oidc.Scope = "openid profile email";
    }))

令牌管理是自动的:令牌按平台安全存储(iOS/macOS 上的 Keychain、Android 上的 KeyStore、Windows 上的 Credential Manager、WASM 上的浏览器存储)并透明刷新。


MVUX(模型-视图-更新-扩展)

MVUX 是 Uno 推荐的响应式模式,不同于 MVVM。它使用不可变记录、Feeds 和 States 以声明式建模数据流。源生成器从普通模型类生成可绑定代理。

核心概念

概念 目的 MVVM 等价物
模型 定义 UI 状态的不可变记录 ViewModel
Feed 异步数据源(加载/数据/错误状态) ObservableCollection + 加载标志
State 可变响应式状态带变更跟踪 INotifyPropertyChanged 属性
ListFeed 专门用于集合的 Feed ObservableCollection
Command 从公共异步方法自动生成 ICommand

模型示例

// ProductModel.cs -- MVUX 模型(源生成器生成可绑定代理)
public partial record ProductModel(IProductService ProductService)
{
    // Feed: 异步数据源带加载/错误/数据状态
    public IFeed<IImmutableList<ProductDto>> Products => Feed
        .Async(async ct => await ProductService.GetProductsAsync(ct));

    // State: 可变响应式值
    public IState<string> SearchTerm => State<string>.Value(this, () => "");

    // ListFeed 带选择支持
    public IListFeed<ProductDto> FilteredProducts => SearchTerm
        .SelectAsync(async (term, ct) =>
            await ProductService.SearchProductsAsync(term, ct))
        .AsListFeed();

    // Command: 从异步方法签名自动生成
    public async ValueTask AddProduct(CancellationToken ct)
    {
        var term = await SearchTerm;
        await ProductService.AddProductAsync(term, ct);
    }
}
<!-- ProductPage.xaml -- 绑定到生成的代理 -->
<Page x:Class="MyApp.Views.ProductPage"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

    <StackPanel>
        <TextBox Text="{Binding SearchTerm, Mode=TwoWay}" />

        <FeedView Source="{Binding FilteredProducts}">
            <FeedView.ValueTemplate>
                <DataTemplate>
                    <ListView ItemsSource="{Binding Data}">
                        <ListView.ItemTemplate>
                            <DataTemplate>
                                <TextBlock Text="{Binding Name}" />
                            </DataTemplate>
                        </ListView.ItemTemplate>
                    </ListView>
                </DataTemplate>
            </FeedView.ValueTemplate>
            <FeedView.ProgressTemplate>
                <DataTemplate>
                    <ProgressRing IsActive="True" />
                </DataTemplate>
            </FeedView.ProgressTemplate>
            <FeedView.ErrorTemplate>
                <DataTemplate>
                    <TextBlock Text="加载产品错误" Foreground="Red" />
                </DataTemplate>
            </FeedView.ErrorTemplate>
        </FeedView>

        <Button Content="添加产品" Command="{Binding AddProduct}" />
    </StackPanel>
</Page>

MVUX 对比 MVVM

关注点 MVUX MVVM
模型定义 不可变 record 类型 可变类带 INotifyPropertyChanged
数据加载 IFeed<T> 带内置加载/错误状态 手动加载标志和 try/catch
集合 IListFeed<T> 带不可变快照 ObservableCollection<T> 带突变
命令 async 方法自动生成 ICommand 实现(RelayCommand)
状态变更 IState<T> 带显式更新语义 属性设置器触发 PropertyChanged
样板代码 最小(源生成器) 显著(基类、属性)

何时使用 MVUX: 新的 Uno Platform 项目,特别是那些有异步数据源和复杂加载状态的项目。MVUX 消除了大多数样板代码并声明式处理加载/错误状态。

何时使用 MVVM: 从现有 WPF/UWP/WinUI 代码库迁移的项目,熟悉 MVVM 模式的团队,或使用 CommunityToolkit.Mvvm 的项目。


Uno Toolkit 控件

Uno Toolkit 提供跨平台控件和助手,超出标准 WinUI 控件。通过 UnoFeaturesToolkit 启用。

关键控件

控件 目的
AutoLayout Flexbox 式布局带间距、填充和对齐
Card / CardContentControl Material 风格卡片表面带高程
Chip / ChipGroup 过滤器芯片、操作芯片、选择芯片
Divider 水平/垂直分隔线
DrawerControl 侧边抽屉(汉堡菜单)
LoadingView 加载状态包装器带骨架/闪烁效果
NavigationBar 跨平台导航栏
ResponsiveView 基于屏幕宽度断点的自适应布局
SafeArea 切口、状态栏、导航栏的插入
ShadowContainer 跨平台下拉阴影通过 ThemeShadow
TabBar 底部或顶部标签导航
ZoomContentControl 捏合缩放容器

Toolkit 助手

助手 目的
CommandExtensions 附加命令到任何控件(不只是 Button)
ItemsRepeaterExtensions ItemsRepeater 的选择和命令支持
InputExtensions 自动对焦、返回键命令、输入范围
ResponsiveMarkupExtensions XAML 标记中的响应式值(例如,Responsive.Narrow
StatusBarExtensions 按平台控制状态栏外观
AncestorBinding 在模板中绑定到祖先 DataContext

AutoLayout 示例

<!-- 垂直堆栈带间距、填充和对齐 -->
<utu:AutoLayout Spacing="16" Padding="24"
                PrimaryAxisAlignment="Start"
                CounterAxisAlignment="Stretch">

    <TextBlock Text="产品列表"
               Style="{StaticResource HeadlineMedium}" />

    <utu:AutoLayout Spacing="8" Orientation="Horizontal">
        <TextBox PlaceholderText="搜索..."
                 utu:AutoLayout.PrimaryLength="*" />
        <Button Content="搜索"
                utu:AutoLayout.CounterAlignment="Center" />
    </utu:AutoLayout>

    <ListView ItemsSource="{Binding Products}"
              utu:AutoLayout.PrimaryLength="*" />
</utu:AutoLayout>

主题资源

Uno 支持 Material、Cupertino 和 Fluent 设计系统作为主题包。主题在所有平台上提供一致的颜色、排版、高程和控件样式。

主题配置

<!-- .csproj 中的 UnoFeatures -->
<UnoFeatures>Material</UnoFeatures>   <!-- 或 Cupertino,或两者 -->
<!-- App.xaml -- 主题资源字典 -->
<Application.Resources>
    <ResourceDictionary>
        <ResourceDictionary.MergedDictionaries>
            <!-- Material 主题资源 -->
            <MaterialTheme />

            <!-- 可选: 颜色调色板覆盖 -->
            <ResourceDictionary Source="ms-appx:///Themes/ColorPaletteOverride.xaml" />
        </ResourceDictionary.MergedDictionaries>
    </ResourceDictionary>
</Application.Resources>

颜色自定义

通过 ColorPaletteOverride.xaml 覆盖 Material 主题颜色:

<!-- Themes/ColorPaletteOverride.xaml -->
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Color x:Key="PrimaryColor">#6750A4</Color>
    <Color x:Key="SecondaryColor">#625B71</Color>
    <Color x:Key="TertiaryColor">#7D5260</Color>
    <Color x:Key="ErrorColor">#B3261E</Color>
</ResourceDictionary>

排版

使用主题系统中的现有 TextBlock 样式。从不设置显式字体大小——使用 Material 类型比例:

<TextBlock Text="标题" Style="{StaticResource HeadlineMedium}" />
<TextBlock Text="正文文本" Style="{StaticResource BodyLarge}" />
<TextBlock Text="说明文字" Style="{StaticResource LabelSmall}" />
样式 典型用途
DisplayLarge/Medium/Small 英雄文本、启动屏幕
HeadlineLarge/Medium/Small 页面标题、部分标题
TitleLarge/Medium/Small 卡片标题、对话框标题
BodyLarge/Medium/Small 段落文本、描述
LabelLarge/Medium/Small 按钮标签、说明文字、元数据

ThemeService

编程切换浅色和深色主题:

var themeService = serviceProvider.GetRequiredService<IThemeService>();
await themeService.SetThemeAsync(AppTheme.Dark);
var currentTheme = themeService.Theme;

热重载

Uno Platform 通过其自定义实现在所有目标上提供热重载。XAML 和 C# 代码隐藏的更改无需重启应用程序即可反映。

支持的更改

更改类型 热重载支持
XAML 布局/样式 完全重载,即时
C# 代码隐藏(方法体) 通过 MetadataUpdateHandler 支持
新属性/方法 需要重新构建
资源字典更改 完全重载
导航路由更改 需要重新构建

启用热重载

# 在 dotnet run 前设置环境变量
export DOTNET_MODIFIABLE_ASSEMBLIES=debug

# 运行带热重载
dotnet run -f net8.0-desktop --project MyApp/MyApp.csproj

热重载由 Visual Studio 和 VS Code(带 Uno 扩展)自动配置。对于 CLI 使用,在运行前设置 DOTNET_MODIFIABLE_ASSEMBLIES=debug

陷阱: 热重载不支持添加新类型、更改继承层次结构或修改 UnoFeatures。这些需要完全重新构建。


代理陷阱

  1. 不要混淆 MVUX 和 MVVM。 MVUX 使用不可变记录、Feeds 和 States——不是 INotifyPropertyChanged。不要在 MVUX 模型上添加 ObservableProperty 属性。
  2. 不要硬编码 Uno 扩展的 NuGet 包版本。 UnoFeatures MSBuild 属性通过 Uno SDK 自动解析包。为扩展添加显式 PackageReference 项可能导致版本冲突。
  3. 不要在 Uno XAML 中使用 {Binding StringFormat=...} 这是仅限 WPF 的功能。对于格式化文本,使用转换器或多个 <Run> 元素。
  4. 不要在绑定中使用 x:Static{x:Reference} 这些是仅限 WPF 的标记扩展,在 WinUI/Uno 中不可用。
  5. 不要设置显式字体大小或粗细。 使用主题的 TextBlock 样式(例如,HeadlineMediumBodyLarge)以保持设计系统一致性。
  6. 不要使用硬编码的十六进制颜色。 始终引用主题资源(PrimaryColorSecondaryColor)或语义笔刷以保持主题兼容性。
  7. 不要在 CommandBar 外部使用 AppBarButton 对于独立图标按钮,使用带图标内容的常规 Button
  8. 不要忘记本地化的 x:Uid 每个用户可见字符串应使用 x:Uid 引用 .resw 资源,而不是硬编码文本。

先决条件

  • .NET 8.0+(Uno Platform 5.x 基线)
  • Uno SDK(Uno.Sdk 项目 SDK)
  • 根据需要的工作负载:dotnet workload install ios android maccatalyst wasm-tools
  • Visual Studio 2022+ 或带 Uno Platform 扩展的 VS Code

参考