.NET MAUI 跨平台桌面和移动
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/Images 和 Resources/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>();