.NET MAUI 跨平台桌面和移动

FreeGuideOnline 最新 2026-07-10

bash dotnet workload install maui

该命令会安装 MAUI 所需全部组件(Android SDK、iOS 模拟器等)。

### 编辑器选择
- **Visual Studio 2022**(Windows/Mac):提供完整 GUI 调试与设计器,推荐主力使用。
- **JetBrains Rider**:支持 MAUI 开发,具备强大的代码分析。
- **Visual Studio Code**:结合 C# Dev Kit 与 MAUI 扩展,适合轻量级体验。

验证安装:
```bash
dotnet new maui -n MyFirstApp
cd MyFirstApp
dotnet build -t:Run -f net8.0-android

项目结构解析

创建新项目后,主要目录与文件:

  • MauiProgram.cs:应用启动入口,配置服务与字体。
  • App.xaml / App.xaml.cs:定义应用级资源与根页面。
  • AppShell.xaml:Shell 导航结构(路由注册与视觉层次)。
  • Platforms/:各平台特定代码(如 Android/, iOS/, MacCatalyst/, Windows/)。
  • Resources/:图像、字体、原始资源及样式(图标推荐使用 SVG 或 PNG)。

一个典型的 MauiProgram.cs 极简配置:

public static class MauiProgram
{
    public static MauiApp CreateMauiApp()
    {
        var builder = MauiApp.CreateBuilder();
        builder
            .UseMauiApp<App>()
            .ConfigureFonts(fonts =>
            {
                fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
            });
        return builder.Build();
    }
}

页面与布局基础

XAML 页面

MAUI 页面使用 XAML 声明 UI,代码后置处理交互。示例 MainPage.xaml

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="MyApp.MainPage">
    <VerticalStackLayout Spacing="20" Padding="30">
        <Label Text="欢迎使用 MAUI"
               FontSize="32"
               HorizontalOptions="Center" />
        <Button x:Name="CounterBtn"
                Text="点击我"
                Clicked="OnCounterClicked" />
    </VerticalStackLayout>
</ContentPage>

常用布局容器

  • VerticalStackLayout / HorizontalStackLayout:线性排列子元素。
  • Grid:行列网格布局,支持跨行跨列。
  • FlexLayout:弹性布局,类似 CSS Flexbox。
  • AbsoluteLayout:绝对定位,通过比例或像素控制位置。
  • Border:为单个子元素添加边框、圆角和阴影。

示例:使用 Grid 构建表单

<Grid ColumnDefinitions="Auto,*" RowDefinitions="Auto,Auto" Padding="10">
    <Label Text="姓名" Grid.Row="0" Grid.Column="0" VerticalOptions="Center"/>
    <Entry Grid.Row="0" Grid.Column="1" Placeholder="请输入姓名"/>
    <Label Text="邮箱" Grid.Row="1" Grid.Column="0" VerticalOptions="Center"/>
    <Entry Grid.Row="1" Grid.Column="1" Placeholder="请输入邮箱" Keyboard="Email"/>
</Grid>

数据绑定与 MVVM

MVVM(Model-View-ViewModel)是 MAUI 推荐架构,利用数据绑定将 UI 与逻辑解耦。

实现 ViewModel

using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Windows.Input;

public class MainViewModel : INotifyPropertyChanged
{
    private int _count;
    public int Count
    {
        get => _count;
        set { _count = value; OnPropertyChanged(); }
    }

    public ICommand IncrementCommand { get; }

    public MainViewModel()
    {
        IncrementCommand = new Command(() => Count++);
    }

    public event PropertyChangedEventHandler PropertyChanged;
    void OnPropertyChanged([CallerMemberName] string name = null) =>
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}

在 XAML 中绑定

将 ViewModel 设为 BindingContext:

public partial class MainPage : ContentPage
{
    public MainPage()
    {
        InitializeComponent();
        BindingContext = new MainViewModel();
    }
}

XAML 绑定示例:

<Label Text="{Binding Count, StringFormat='点击次数: {0}'}" />
<Button Text="增加" Command="{Binding IncrementCommand}" />

编译绑定与性能

使用 x:DataType 启用编译期绑定,提高性能并避免运行时错误:

<ContentPage ...
    xmlns:vm="clr-namespace:MyApp.ViewModels"
    x:DataType="vm:MainViewModel">

导航与 Shell

Shell 提供基于 URI 的导航、弹出式菜单和选项卡布局。

配置路由

AppShell.xaml.cs 注册路由:

Routing.RegisterRoute("details", typeof(DetailsPage));

导航至该页面:

await Shell.Current.GoToAsync("details?name=John");

目标页面通过 [QueryProperty] 接收参数:

[QueryProperty(nameof(Name), "name")]
public partial class DetailsPage : ContentPage
{
    private string _name;
    public string Name
    {
        get => _name;
        set { _name = value; OnPropertyChanged(); }
    }
}

TabBar 与 Flyout

常见 Shell 结构:

<Shell>
    <TabBar>
        <ShellContent Title="首页" ContentTemplate="{DataTemplate local:MainPage}" />
        <ShellContent Title="设置" ContentTemplate="{DataTemplate local:SettingsPage}" />
    </TabBar>
</Shell>

Flyout 侧边栏使用 <FlyoutItem> 替代 <TabBar>

访问平台特定功能

当共享代码无法满足需求时,可使用条件编译或依赖注入调用原生 API。

条件编译

#if ANDROID
    Toast.MakeText(Platform.CurrentActivity, "Hello Android", ToastLength.Short).Show();
#elif IOS
    // iOS 特定代码
#endif

使用处理程序自定义控件

每个 MAUI 控件都有对应的平台处理程序,可通过 ConfigureMauiHandlers 修改:

builder.ConfigureMauiHandlers(handlers =>
{
#if ANDROID
    handlers.AddHandler<Entry, MyCustomEntryHandler>();
#endif
});

自定义处理程序需继承平台原生处理程序并重写方法。

资源、样式与主题

添加图片和字体

将资源放入 Resources/ImagesResources/Fonts,然后在 .csproj 中确认包含:

<MauiImage Include="Resources\Images\*" />
<MauiFont Include="Resources\Fonts\*" />

使用图片:

<Image Source="dotnet_bot.png" HeightRequest="200" />

全局样式与主题

Resources/Styles 下定义样式,App.xaml 合并资源字典:

<Application.Resources>
    <ResourceDictionary>
        <ResourceDictionary.MergedDictionaries>
            <ResourceDictionary Source="Resources/Styles/Colors.xaml" />
            <ResourceDictionary Source="Resources/Styles/Styles.xaml" />
        </ResourceDictionary.MergedDictionaries>
    </ResourceDictionary>
</Application.Resources>

样式示例:

<Style TargetType="Button">
    <Setter Property="BackgroundColor" Value="{StaticResource Primary}" />
    <Setter Property="TextColor" Value="White" />
    <Setter Property="CornerRadius" Value="8" />
</Style>

明暗主题支持

使用 AppThemeBinding 根据系统主题切换值:

<Label TextColor="{AppThemeBinding Light=Black, Dark=White}" />

数据持久化与网络请求

本地存储

推荐使用 Preferences(键值对)或 SecureStorage(敏感数据):

Preferences.Set("username", "demo");
var username = Preferences.Get("username", "default");

复杂数据可使用 SQLite(通过 sqlite-net-pcl NuGet 包)。

HTTP 网络调用

注入 HttpClient

public class DataService
{
    readonly HttpClient _httpClient;
    public DataService(HttpClient httpClient) => _httpClient = httpClient;

    public async Task<string> GetDataAsync()
    {
        var response = await _httpClient.GetStringAsync("https://api.example.com/data");
        return response;
    }
}

MauiProgram.cs 注册:

builder.Services.AddSingleton<DataService>();
builder.Services.AddHttpClient<DataService>();