MAUI Blazor学习14-选择目录

MAUI Blazor学习14-选择目录

 

MAUI Blazor系列目录

  1. MAUI Blazor学习1-移动客户端Shell布局 - SunnyTrudeau - 博客园 (cnblogs.com)
  2. MAUI Blazor学习2-创建移动客户端Razor页面 - SunnyTrudeau - 博客园 (cnblogs.com)
  3. MAUI Blazor学习3-绘制ECharts图表 - SunnyTrudeau - 博客园 (cnblogs.com)
  4. MAUI Blazor学习4-绘制BootstrapBlazor.Chart图表 - SunnyTrudeau - 博客园 (cnblogs.com)
  5. MAUI Blazor学习5-BLE低功耗蓝牙 - SunnyTrudeau - 博客园 (cnblogs.com)
  6. MAUI Blazor学习6-扫描二维码 - SunnyTrudeau - 博客园 (cnblogs.com)
  7. MAUI Blazor学习7-实现登录跳转页面 - SunnyTrudeau - 博客园 (cnblogs.com)
  8. MAUI Blazor学习8-支持多语言 - SunnyTrudeau - 博客园 (cnblogs.com)
  9. MAUI Blazor学习9-VS Code开发调试MAUI入门 - SunnyTrudeau - 博客园 (cnblogs.com)
  10. MAUI Blazor学习10-BarcodeScanner扫描二维码 - SunnyTrudeau - 博客园 (cnblogs.com)
  11. MAUI Blazor学习11-百度地图定位 - SunnyTrudeau - 博客园 (cnblogs.com)
  12. MAUI Blazor学习12-文件另存为 - SunnyTrudeau - 博客园 (cnblogs.com)
  13. MAUI Blazor学习13-打开文件 - SunnyTrudeau - 博客园 (cnblogs.com)

  

MAUI Blazor运行在浏览器网页,可以使用JavaScriptwindow.showDirectoryPicker选择目录,也可以使用MAUI社区CommunityToolkitFolderPicker选择目录。本文继续研究实现选择目录功能的不同方案。

 继续沿用之前的MAUI Blazor项目MaBlaApp,增加选择目录功能。选择目录后,查找该目录下边所有txt文件,形成列表,点击列表可以加载txt文件。

JavaScriptwindow.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页面调用JavaScriptGetTxtFileFromSelectDirectory函数获取下面的txt文件,返回的文件信息txtFileInfoes按照列表样式显示,点击一个文件名,就调用JavaScriptLoadTxtFileFromSelectDirectory函数加载它。

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

 

posted on 2023-11-09 22:09  SunnyTrudeau  阅读(212)  评论(0编辑  收藏  举报