微软的跨平台开发框架已经实现了一次大的迭代进化,Xamarin(Mono)主要实现了不同平台下都能使用C#,但很多功能仍要编写各自平台的代码,升级为MAUI后,有了一套较为完整的共享代码,在基本功能上实现了编写一次代码各个平台通用的愿景。
比如文件选取器(文件打开对话框)FilePicker就是如此,Xamarin.Form和MAUI都提供了相似的调用方法,其中MAUI是由Microsoft.Maui.Storage命名空间提供“原生”的支持。而文件夹选取器(目录选择对话框)FolderPicker目前只能由MAUI社区工具包提供;在FolderPicker内部,对windows平台调用Windows.Storage.Pickers的FolderPicker,对安卓平台则调用Intent.ActionOpenDocumentTree打开文档树。
要想使用FolderPicker,需通过nuget引入CommunityToolkit.Maui包。需要注意CommunityToolkit.Maui所对应的.Net版本,必须与MAUI项目创建时所选的.Net版本一致。比如我创建项目时用.Net 8.0版,那么选CommunityToolkit.Maui默认的版本(对应.Net 9.0)就会出错,应该使用更低的版本。
下面是使用FolderPicker的最简单的完整示例:
①MauiProgram.cs
using CommunityToolkit.Maui;
using CommunityToolkit.Maui.Storage;
using Microsoft.Extensions.Logging;
namespace MauiApp1
{
public static class MauiProgram
{
public static MauiApp CreateMauiApp()
{
var builder = MauiApp.CreateBuilder();
builder
.UseMauiApp<App>()
.UseMauiCommunityToolkit()
.ConfigureFonts(fonts =>
{
fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
});
#if DEBUG
builder.Logging.AddDebug();
#endif
// FolderPicker注册为单例模式
builder.Services.AddSingleton<IFolderPicker>(FolderPicker.Default);
// Register the MainPage as transient to make sure it can resolve the IFolderPicker dependency.
builder.Services.AddTransient<MainPage>();
return builder.Build();
}
}
}
②MainPage.xaml
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:toolkit="http://schemas.microsoft.com/dotnet/2022/maui/toolkit"
x:Class="MauiApp1.MainPage">
<Button Text="选择文件夹" Clicked="OnPickFolderClicked"/>
</ContentPage>
③MainPage.xaml.cs
using CommunityToolkit.Maui.Storage;
using CommunityToolkit.Maui.Core;
using CommunityToolkit.Maui.Alerts;
namespace MauiApp1
{
public partial class MainPage : ContentPage
{
readonly IFolderPicker folderPicker;
private CancellationTokenSource cancellationTokenSource;
int count = 0;
public MainPage(IFolderPicker folderPicker)
{
InitializeComponent();
this.folderPicker = folderPicker;
// 初始化取消令牌
cancellationTokenSource = new CancellationTokenSource();
}
private async void OnPickFolderClicked(object sender, EventArgs e)
{
try
{
var folderPickerResult = await folderPicker.PickAsync(cancellationTokenSource.Token);
if (folderPickerResult.IsSuccessful)
{
await Toast.Make($"Folder picked: Path - {folderPickerResult.Folder.Path}", ToastDuration.Long).Show(cancellationTokenSource.Token);
}
else
{
await Toast.Make($"Folder is not picked, {folderPickerResult.Exception?.Message}").Show(cancellationTokenSource.Token);
}
}
catch (OperationCanceledException)
{
// 处理取消的情况
await Toast.Make("Folder picking operation was canceled.").Show(cancellationTokenSource.Token);
}
catch (Exception ex)
{
// 处理其他异常
await Toast.Make($"An error occurred while picking a folder: {ex.Message}").Show(cancellationTokenSource.Token);
}
}
protected override void OnDisappearing()
{
base.OnDisappearing();
// 页面消失时取消任何挂起的操作
cancellationTokenSource.Cancel();
}
}
}
④在安卓平台上运行需设置权限,在Platforms\Android\AndroidManifest.xml中添加:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
安卓手机运行时画面
参考资料:
https://learn.microsoft.com/zh-cn/dotnet/communitytoolkit/maui/essentials/folder-picker
开发环境:
VisualStudioVersion = 17.12
.Net MAUI = 8.0
CommunityToolkit.Maui = 8.0.1