在 WinUI 中使用 Windows 应用 SDK 选取器保存文件

使用 Windows 应用 SDK 生成 Windows 应用时,用户通常需要将文档、图像或其他内容等文件保存到其设备上的特定位置。 Windows 应用 SDK 提供 FileSavePicker 类,用于创建一致的用户友好界面,让用户选择保存文件的位置以及为其命名的内容。

本文介绍如何在 WinUI 应用中实现文件保存选取器。 你将了解如何配置选取器的外观和行为、处理用户的选择,以及如何将内容保存到所选位置。

可以使用建议的文件名和其他默认设置填充保存文件选取器,以便用户更轻松地保存其文件:

保存文件选取器屏幕截图,其中包含建议的文件名“我的文档”和文件类型“Documents”(.txt、.doc、.docx)。

先决条件

在开始之前,请确保具备:

  • 使用 Windows 应用 SDK 设置的 WinUI 项目
  • 基本熟悉 C# 和 XAML
  • 了解 C# 中的异步与“await”模式

重要 API

本主题使用以下 API:

使用 FileSavePicker 允许用户指定他们希望你的应用保存文件的名称和位置。

使用 FileSavePicker 保存文档

使用 FileSavePicker ,以便用户可以指定要保存的文件的名称、类型和位置。 创建、自定义和显示文件选取器对象,然后通过返回的 StorageFile 对象保存数据,该对象表示选取的文件。

  1. 创建并自定义 FileSavePicker。 首先创建新的 FileSavePicker 对象,然后在对象上设置属性以自定义应用和用户的文件选取器:

    using Microsoft.Windows.Storage.Pickers;
    ...
    var savePicker = new FileSavePicker(this.AppWindow.Id)
    {
        // (Optional) Specify the initial location for the picker. 
        //     If the specified location doesn't exist on the user's machine, it falls back to the DocumentsLibrary.
        //     If not set, it defaults to PickerLocationId.Unspecified, and the system will use its default location.
        SuggestedStartLocation = PickerLocationId.DocumentsLibrary,
    
        // (Optional) specify the default file name. If not specified, use system default.
        SuggestedFileName = "My Document",
    
        // (Optional) Sets the folder that the file save dialog displays when it opens.
        //     If not specified or the specified path doesn't exist, defaults to the last folder the user visited.
        SuggestedFolder = @"C:\MyFiles",
    
        // (Optional) specify the text displayed on the commit button. 
        //     If not specified, the system uses a default label of "Save" (suitably translated).
        CommitButtonText = "Save Document",
    
        // (Optional) categorized extension types. If not specified, "All Files (*.*)" is allowed.
        //     Note that when "All Files (*.*)" is allowed, end users can save a file without an extension.
        FileTypeChoices = {
            { "Documents", new List<string> { ".txt", ".doc", ".docx" } }
        },
    
        // (Optional) specify the default file extension (will be appended to SuggestedFileName).
        //      If not specified, no extension will be appended.
        DefaultFileExtension = ".txt",
    };
    

    此示例设置六个属性: SuggestedStartLocationSuggestedFileNameSuggestedFolderCommitButtonTextFileTypeChoicesDefaultFileExtension

    由于用户正在保存文档或文本文件,因此示例使用 PickerLocationId 枚举中的 DocumentsLibrary 值将 SuggestedStartLocation 设置为文档库文件夹。 将 SuggestedStartLocation 设置为适合所保存文件类型的位置,例如音乐、图片、视频或文档。 从起始位置开始,用户可以导航到并选择其他位置。

    为了减少用户的键入操作,该示例设置了SuggestedFileName。 建议的文件名应与所保存的文件相关。 例如,与 Word 一样,可以建议现有文件名(如果有)或用户正在保存尚没有名称的文件时文档的第一行。

    指定示例支持的文件类型(Microsoft Word 文档和文本文件)时,请使用 FileTypeChoices 属性。 这可确保应用在保存文件后可以打开该文件。 请确保应用支持你指定的所有文件类型。 用户将能够将其文件另存为你指定的任何文件类型。 它们还可以通过选择指定的另一种文件类型来更改文件类型。 默认情况下,将选择列表中的第一个文件类型。 若要控制该属性,请设置 DefaultFileExtension 属性。

    注释

     文件选取器还使用当前选定的文件类型来筛选它显示的文件,以便仅向用户显示与所选文件类型匹配的文件类型。

    此示例的等效C++代码如下所示:

    #include <winrt/Microsoft.Windows.Storage.Pickers.h>
    using namespace winrt::Microsoft::Windows::Storage::Pickers;
    
    FileSavePicker savePicker(AppWindow().Id());
    
    // (Optional) Specify the initial location for the picker. 
    //     If the specified location doesn't exist on the user's machine, it falls back to the DocumentsLibrary.
    //     If not set, it defaults to PickerLocationId.Unspecified, and the system will use its default location.
    savePicker.SuggestedStartLocation(PickerLocationId::DocumentsLibrary);
    
    // (Optional) specify the default file name. If not specified, use system default.
    savePicker.SuggestedFileName(L"NewDocument");
    
    // (Optional) Sets the folder that the file save dialog displays when it opens.
    //     If not specified or the specified path doesn't exist, defaults to the last folder the user visited.
    savePicker.SuggestedFolder = L"C:\\MyFiles",
    
    // (Optional) specify the text displayed on the commit button. 
    //     If not specified, the system uses a default label of "Save" (suitably translated).
    savePicker.CommitButtonText(L"Save Document");
    
    // (Optional) categorized extension types. If not specified, "All Files (*.*)" is allowed.
    //     Note that when "All Files (*.*)" is allowed, end users can save a file without an extension.
    savePicker.FileTypeChoices().Insert(L"Text", winrt::single_threaded_vector<winrt::hstring>({ L".txt" }));
    
    // (Optional) specify the default file extension (will be appended to SuggestedFileName).
    //      If not specified, no extension will be appended.
    savePicker.DefaultFileExtension(L".txt");
    

    注释

      FileSavePicker 对象使用 PickerViewMode.List 视图模式显示文件选取器。

  2. 接下来,让我们显示 FileSavePicker 并保存到选取的文件位置。 通过调用 PickSaveFileAsync 显示文件选取器。 用户指定名称、文件类型和位置并确认保存文件后, PickSaveFileAsync 将返回一个轻型 FilePickResult 对象,该对象包含已保存文件和文件名的路径。 如果对此文件具有读取和写入访问权限,则可以捕获和处理此文件。

    using Microsoft.Windows.Storage.Pickers;
    ...
    var savePicker = new FileSavePicker(this.AppWindow.Id);
    var result = await savePicker.PickSaveFileAsync();
    if (result != null)
    {
        if (!System.IO.File.Exists(result.Path))
        {
            // Create a file and write to it.
            System.IO.File.WriteAllText(result.Path, "Hello world." + Environment.NewLine);
        }
        else
        {
            // Append to the existing file.
            System.IO.File.AppendAllText(result.Path, "Hello again." + Environment.NewLine);
        }
    }
    else
    {
        this.textBlock.Text = "Operation cancelled.";
    }
    

    该示例检查文件是否存在,并创建一个新文件或追加到现有文件。 如果用户取消作,结果将是 null,你可以相应地处理该情况,例如向用户显示消息。

    小窍门

     应始终检查保存的文件,以确保该文件存在且在执行任何其他处理之前有效。 然后,可以根据应用将内容保存到文件。 如果选取的文件无效,应用应提供适当的行为。

    下面是此 C# 示例的等效C++:

    #include <winrt/Microsoft.Windows.Storage.Pickers.h>
    #include <fstream>
    #include <string>
    using namespace winrt::Microsoft::Windows::Storage::Pickers;
    
    FileSavePicker savePicker(AppWindow().Id());
    auto result{ co_await savePicker.PickSaveFileAsync() };
    if (result)
    {
        // Check if the file exists.
        if (!std::ifstream(result.Path().c_str()))
        {
            std::ofstream outFile(result.Path().c_str());
            outFile << "Hello world.";
            outFile.close();
        }
        else
        {
            // Append to the existing file.
            std::ofstream outFile(result.Path().c_str(), std::ios::app);
            outFile << "Hello again.";
            outFile.close();
        }
    }
    else
    {
        textBlock().Text(L"Operation cancelled.");
    }
    

Windows.Storage.Pickers

使用 Windows 应用 SDK 的文件、文件夹和库

PickSaveFileAsync