MAUI Blazor学习14-选择目录
MAUI Blazor学习14-选择目录
MAUI Blazor系列目录
- MAUI Blazor学习1-移动客户端Shell布局 - SunnyTrudeau - 博客园 (cnblogs.com)
- MAUI Blazor学习2-创建移动客户端Razor页面 - SunnyTrudeau - 博客园 (cnblogs.com)
- MAUI Blazor学习3-绘制ECharts图表 - SunnyTrudeau - 博客园 (cnblogs.com)
- MAUI Blazor学习4-绘制BootstrapBlazor.Chart图表 - SunnyTrudeau - 博客园 (cnblogs.com)
- MAUI Blazor学习5-BLE低功耗蓝牙 - SunnyTrudeau - 博客园 (cnblogs.com)
- MAUI Blazor学习6-扫描二维码 - SunnyTrudeau - 博客园 (cnblogs.com)
- MAUI Blazor学习7-实现登录跳转页面 - SunnyTrudeau - 博客园 (cnblogs.com)
- MAUI Blazor学习8-支持多语言 - SunnyTrudeau - 博客园 (cnblogs.com)
- MAUI Blazor学习9-VS Code开发调试MAUI入门 - SunnyTrudeau - 博客园 (cnblogs.com)
- MAUI Blazor学习10-BarcodeScanner扫描二维码 - SunnyTrudeau - 博客园 (cnblogs.com)
- MAUI Blazor学习11-百度地图定位 - SunnyTrudeau - 博客园 (cnblogs.com)
- MAUI Blazor学习12-文件另存为 - SunnyTrudeau - 博客园 (cnblogs.com)
- MAUI Blazor学习13-打开文件 - SunnyTrudeau - 博客园 (cnblogs.com)
MAUI Blazor运行在浏览器网页,可以使用JavaScript的window.showDirectoryPicker选择目录,也可以使用MAUI社区CommunityToolkit的FolderPicker选择目录。本文继续研究实现选择目录功能的不同方案。
继续沿用之前的MAUI Blazor项目MaBlaApp,增加选择目录功能。选择目录后,查找该目录下边所有txt文件,形成列表,点击列表可以加载txt文件。
JavaScript的window.showDirectoryPicker方案
参考文档
Window:showDirectoryPicker() 方法 - Web API 接口参考 | MDN (mozilla.org)
编写JavaScript函数GetTxtFileFromSelectDirectory,选择目录,查找该目录下边所有txt文件,保存到window.TxtFileHandles对象数组。后续可以从razor页面调用JavaScript函数LoadTxtFileFromSelectDirectory函数,找到对应的TxtFileHandles对象去加载文件。
D:\Software\gitee\mauiblazorapp\MaBlaApp\wwwroot\js\FileDialog.js
//获取选择目录下的txt文件 //https://developer.mozilla.org/zh-CN/docs/Web/API/Window/showDirectoryPicker //https://developer.mozilla.org/en-US/docs/Web/API/FileSystemDirectoryHandle export async function GetTxtFileFromSelectDirectory() { try { //显示一个目录选择器并在用户选择后返回一个 FileSystemDirectoryHandle 对象。 const dirHandle = await window.showDirectoryPicker(); var txtFileHandles = new Array(); var txtFileInfos = new Array(); for await (const [filename, fileHandle] of dirHandle) { //文件的kind=file,目录的kind=directory if (fileHandle.kind === "file") { const file = await fileHandle.getFile(); if ((file !== null) && (file.type === "text/plain")) { //缓存txt文件对象 txtFileHandles.push(fileHandle); txtFileInfos.push({ filename: file.name, size: file.size }); } } } //缓存txt文件对象数组 window.TxtFileHandles = txtFileHandles; console.log(window.TxtFileHandles); } catch (error) { console.error(error); } return txtFileInfos; } //从选择的目录中加载txt文件 export async function LoadTxtFileFromSelectDirectory(txtFilename) { try { //从选择的目录下边缓存txt文件对象数组中查找txt文件 const fileHandle = window.TxtFileHandles.find(x => x.name == txtFilename); if (fileHandle == null) return "文件不存在"; const file = await fileHandle.getFile(); if (!file) return "无法获取文件对象"; //读取文本文件,按照utf-8 const contents = await file.text(); return contents; } catch (error) { console.error(error); return error.toString(); } }
Razor页面调用JavaScript的GetTxtFileFromSelectDirectory函数获取下面的txt文件,返回的文件信息txtFileInfoes按照列表样式显示,点击一个文件名,就调用JavaScript的LoadTxtFileFromSelectDirectory函数加载它。
D:\Software\gitee\mauiblazorapp\MaBlaApp\Pages\FileDialog.razor
<div class="list-group"> @foreach (var txtFileInfo in txtFileInfoes) { <a href="/filedialog" class="list-group-item list-group-item-action d-flex justify-content-between mb-1" @onclick="((e) => LoadTxtFileFromSelectDirectory(txtFileInfo.Filename))"> <strong>@txtFileInfo.Filename</strong> <small>@($"{txtFileInfo.Size:N0}字节")</small> </a> } </div> //获取选择目录下的txt文件(JavaScript) private async void GetTxtFileFromSelectDirectoryByJavaScript() { try { //获取选择目录下的txt文件 txtFileInfoes = await module!.InvokeAsync<TxtFileInfo[]>("GetTxtFileFromSelectDirectory"); isSelectByJavaScript = true; } catch (Exception ex) { message = $"GetTxtFileFromSelectDirectoryByJavaScript出错: {ex.Message}"; } await InvokeAsync(() => StateHasChanged()); } //从选择的目录中加载txt文件 private async void LoadTxtFileFromSelectDirectory(string txtFilename) { try { if (isSelectByJavaScript) { //从选择的目录中加载txt文件 message = await module!.InvokeAsync<string>("LoadTxtFileFromSelectDirectory", txtFilename); } else { var fileInfo = FileInfoes.FirstOrDefault(x => x.Name == txtFilename); if (fileInfo is null) { message = "文件不存在"; } else { message = await File.ReadAllTextAsync(fileInfo.FullName); } } } catch (Exception ex) { message = $"LoadTxtFileFromSelectDirectory出错: {ex.Message}"; } await InvokeAsync(() => StateHasChanged()); }
MAUI社区的FolderPicker方案
FolderPicker提供从文件系统中选取文件夹的功能。
参考文档
FolderPicker - .NET MAUI 社区工具包 - Community Toolkits for .NET | Microsoft Learn
D:\Software\gitee\mauiblazorapp\MaBlaApp\Pages\FileDialog.razor
//获取选择目录下的txt文件(CommunityToolkit) private async Task GetTxtFileFromSelectDirectoryByToolkit() { cts = new CancellationTokenSource(); CancellationToken cancellationToken = cts.Token; var result = await folderPicker.PickAsync(cancellationToken); if (result.IsSuccessful) { await Toast.Make($"The folder was picked: Name - {result.Folder.Name}, Path - {result.Folder.Path}", ToastDuration.Long).Show(cancellationToken); } else { await Toast.Make($"The folder was not picked with error: {result.Exception.Message}").Show(cancellationToken); return; } var dirInfo = new DirectoryInfo(result.Folder.Path); FileInfoes = dirInfo.GetFiles("*.txt"); txtFileInfoes = FileInfoes.Select(x => new TxtFileInfo(x.Name, (int)x.Length)).ToArray(); isSelectByJavaScript = false; await InvokeAsync(() => StateHasChanged()); }
测试
在windows上面使用VS2022调试运行,GetTxtFileFromSelectDirectoryByJavaScript方案打开选择目录对话框后,经常失去了焦点,要先切换到其他窗口,再切换回来,才能选择【View files】菜单,然后才能选择目录。GetTxtFileFromSelectDirectoryByToolkit方案不会提示授权,可以直接选择目录,更方便。
考虑到手机APP一般没有读写本机文件的应用场景,所以不在手机上测试了。
结论
推荐用MAUI社区的FolderPicker选择目录方案。
DEMO代码地址:https://gitee.com/woodsun/mauiblazorapp