Tutorial: Apertura de archivos y carpetas con selectores en WinUI

Use SDK de Aplicaciones para Windows selectores de archivos y carpetas para permitir que los usuarios examinen y seleccionen archivos o carpetas en la aplicación WinUI. Las APIs del selector proporcionan una experiencia de Windows familiar que ayuda a los usuarios a navegar por sus dispositivos y ubicaciones de almacenamiento en la nube. En este artículo se muestra cómo implementar selectores de archivos abiertos y selectores de carpetas, personalizar su comportamiento y controlar los resultados seleccionados en la aplicación.

Las clases SDK de Aplicaciones para Windows FileOpenPicker y FileSavePicker crean un cuadro de diálogo de selector que permite a los usuarios especificar el nombre y la ubicación de un archivo para abrir o guardar. La clase FolderPicker permite seleccionar una carpeta.

Para obtener información sobre cómo usar un selector para guardar archivos, consulte Guardar un archivo con un selector de SDK de Aplicaciones para Windows.

Requisitos previos

  • SDK de Aplicaciones para Windows 1.8 o posterior. Las Microsoft.Windows.Storage.Pickers API usadas en este artículo se introdujeron en SDK de Aplicaciones para Windows 1.8. Si el proyecto tiene como destino una versión anterior, consulte Uso de selectores de WinRT con interoperabilidad de HWND para el enfoque heredado.

API importantes

En este artículo se usan las SIGUIENTES API:

Interfaz de usuario del selector de archivos

Un selector de archivos muestra información para orientar a los usuarios y proporcionar una experiencia coherente al abrir o guardar archivos.

Esa información incluye:

  • Ubicación actual
  • Elemento o elementos que el usuario elige
  • Un árbol de ubicaciones que el usuario puede recorrer. Estas ubicaciones incluyen ubicaciones del sistema de archivos, como la carpeta Música o Descargas, así como las aplicaciones que implementan el contrato del selector de archivos (como Cámara, Fotos y Microsoft OneDrive).

Es posible que tenga una aplicación que permita a los usuarios abrir o guardar archivos. Cuando el usuario inicia esa acción, la aplicación llama al selector de archivos, que muestra la interfaz de usuario del selector de archivos:

Captura de pantalla de un selector de archivos abierto con un filtro seleccionado para mostrar .txt, .pdf, .doc y .docx archivos.

Cómo funcionan los selectores con tu aplicación

Con un selector, la aplicación puede acceder, examinar y guardar archivos y carpetas en el sistema del usuario. La aplicación recibe esas selecciones como objetos PickFileResult y PickFolderResult ligeros, que proporcionan la ruta de acceso al archivo o carpeta seleccionado.

El selector usa una única interfaz unificada para permitir que el usuario elija archivos y carpetas del sistema de archivos o de otras aplicaciones. Los archivos seleccionados de otras aplicaciones son como archivos del sistema de archivos. En general, la aplicación puede operar en ellos de la misma manera que otros objetos. Otras aplicaciones hacen que los archivos estén disponibles participando en contratos de selector de archivos.

Por ejemplo, puede llamar al selector de archivos en la aplicación para que el usuario pueda abrir un archivo. Esta acción convierte tu aplicación en la aplicación que realiza llamadas. El selector de archivos interactúa con el sistema y otras aplicaciones para permitir que el usuario navegue y elija el archivo. Cuando el usuario elige un archivo, el selector de archivos devuelve la ruta de acceso del archivo a la aplicación.

Selección de un archivo para abrir un ejemplo

En el código siguiente se muestra cómo usar la clase FileOpenPicker para permitir al usuario elegir un único archivo, como una foto. El código establece las propiedades del selector para personalizar su apariencia y comportamiento y, a continuación, muestra el selector al usuario mediante el método PickSingleFileAsync . Si el usuario elige un archivo, la aplicación lee el contenido del archivo y lo almacena en una variable.

using Microsoft.Windows.Storage.Pickers;

var openPicker = new FileOpenPicker(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 text displayed on the commit button. 
    //     If not specified, the system uses a default label of "Open" (suitably translated).
    CommitButtonText = "Choose selected files",

    // (Optional) specify file extension filters. If not specified, defaults to all files (*.*).
    FileTypeFilter = { ".txt", ".pdf", ".doc", ".docx" },

    // (Optional) specify the view mode of the picker dialog. If not specified, defaults to List.
    ViewMode = PickerViewMode.List,
};

var result = await openPicker.PickSingleFileAsync();
if (result is not null)
{
    var content = System.IO.File.ReadAllText(result.Path);
}
else
{
    // Add your error handling here.
}
#include <winrt/Microsoft.Windows.Storage.Pickers.h>
#include <fstream>
#include <string>

using namespace winrt::Microsoft::Windows::Storage::Pickers;

FileOpenPicker openPicker(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.
openPicker.SuggestedStartLocation(PickerLocationId::DocumentsLibrary);

// (Optional) specify the text displayed on the commit button. 
//     If not specified, the system uses a default label of "Open" (suitably translated).
openPicker.CommitButtonText(L"Choose selected files");

// (Optional) specify file extension filters. If not specified, defaults to all files (*.*).
openPicker.FileTypeFilter().ReplaceAll({ L".txt", L".pdf", L".doc", L".docx" });

// (Optional) specify the view mode of the picker dialog. If not specified, defaults to List.
openPicker.ViewMode(PickerViewMode::List);

auto result{ co_await openPicker.PickSingleFileAsync() };
if (result)
{
    std::ifstream fileReader(result.Path().c_str());
    std::string text((std::istreambuf_iterator<char>(fileReader)), std::istreambuf_iterator<char>());
    winrt::hstring hText = winrt::to_hstring(text);
}
else
{
    // Add your error handling here.
}

Selección de varios archivos para abrir el ejemplo

También puede permitir que el usuario elija varios archivos. En el código siguiente se muestra cómo usar la clase FileOpenPicker para permitir al usuario elegir varios archivos, como fotos. El proceso es el mismo, pero el método PickMultipleFilesAsync devuelve una colección de objetos PickFileResult . Cada resultado incluye la propiedad Path cuando necesite la ruta de archivo sin procesar.

using Microsoft.Windows.Storage.Pickers;

var openPicker = new FileOpenPicker(this.AppWindow.Id);

var results = await openPicker.PickMultipleFilesAsync();
if (results.Count > 0)
{
    var pickedFilePaths = results.Select(f => f.Path);
    foreach (var path in pickedFilePaths)
    {
        var content = System.IO.File.ReadAllText(path);
    }
}
else
{
    // Add your error handling here.
}
#include <winrt/Microsoft.Windows.Storage.Pickers.h>
#include <fstream>
#include <string>

using namespace winrt::Microsoft::Windows::Storage::Pickers;

FileOpenPicker openPicker(this->AppWindow().Id());
auto results{ co_await openPicker.PickMultipleFilesAsync() };
if (results.Size() > 0)
{
    for (auto const& result : results)
    {
        std::ifstream fileReader(result.Path().c_str());
        std::string text((std::istreambuf_iterator<char>(fileReader)), std::istreambuf_iterator<char>());
        winrt::hstring hText = winrt::to_hstring(text);
    }
}
else
{
    // Add your error handling here.
}

Selección de un ejemplo de carpeta

Para elegir una carpeta mediante la clase FolderPicker , use el código siguiente. Este código crea un selector de carpetas, lo muestra al usuario mediante el método PickSingleFolderAsync y recupera la ruta de acceso de la carpeta seleccionada en un objeto PickFolderResult . Si el usuario elige una carpeta, la aplicación recupera la ruta de acceso de la carpeta y la almacena en una variable para su uso posterior.

using Microsoft.Windows.Storage.Pickers;

var folderPicker = new FolderPicker(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 text displayed on the commit button. 
    //     If not specified, the system uses a default label of "Open" (suitably translated).
    CommitButtonText = "Select Folder",

    // (Optional) specify the view mode of the picker dialog. If not specified, default to List.
    ViewMode = PickerViewMode.List,
};

var result = await folderPicker.PickSingleFolderAsync();

if (result is not null)
{
    var path = result.Path;
}
else
{
    // Add your error handling here.
}
#include <winrt/Microsoft.Windows.Storage.Pickers.h>

using namespace winrt::Microsoft::Windows::Storage::Pickers;

FolderPicker folderPicker(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.
folderPicker.SuggestedStartLocation(PickerLocationId::DocumentsLibrary);

// (Optional) specify the text displayed on the commit button. 
//     If not specified, the system uses a default label of "Open" (suitably translated).
folderPicker.CommitButtonText(L"Select Folder");

// (Optional) specify the view mode of the picker dialog. If not specified, default to List.
folderPicker.ViewMode(PickerViewMode::List);

auto result{ co_await folderPicker.PickSingleFolderAsync() };
if (result)
{
    auto path{ result.Path() };
}
else
{
    // Add your error handling here.
}

Sugerencia

Cada vez que la aplicación accede a un archivo o carpeta a través de un selector, agréguelo al FutureAccessList o MostRecentlyUsedList para realizar un seguimiento de él mediante las API de Windows Runtime (WinRT). Para obtener más información, consulte Seguimiento de archivos y carpetas usados recientemente.

La interfaz de usuario del selector de carpetas tiene este aspecto:

Captura de pantalla de un selector de carpetas que ve la unidad C.

Usa selectores de WinRT con interoperabilidad con HWND

Si su proyecto está dirigido a SDK de Aplicaciones para Windows 1.7 o a una versión anterior, o si usa las API heredadas de Windows.Storage.Pickers (por ejemplo, al migrar desde UWP), debe inicializar el selector con un identificador de ventana (HWND) antes de mostrarlo. Sin este paso, el selector genera una excepción o falla silenciosamente en las aplicaciones de escritorio (WinUI 3).

Importante

Las aplicaciones de escritorio de WinUI 3 no tienen un CoreWindow. Debe asociar el selector con la ventana de la aplicación llamando a WinRT.Interop.InitializeWithWindow.Initialize (C#) o IInitializeWithWindow::Initialize (C++/WinRT) antes de realizar cualquier llamada a Pick*Async.

Ejemplo de C# (selectores de WinRT heredados)

// This example assumes you have a reference to your app's main window.
// In a Window class, use 'this'. In a Page, use a stored reference like App.MainWindow.

var picker = new Windows.Storage.Pickers.FileOpenPicker();
picker.FileTypeFilter.Add(".png");
picker.FileTypeFilter.Add(".jpg");

// Get the window handle (HWND) for the current WinUI 3 window.
var hwnd = WinRT.Interop.WindowNative.GetWindowHandle(App.MainWindow);

// Associate the picker with the window.
WinRT.Interop.InitializeWithWindow.Initialize(picker, hwnd);

var file = await picker.PickSingleFileAsync();
if (file is null)
{
    // The user cancelled the picker.
}

Ejemplo de C++/WinRT (selectores de WinRT heredados)

// pch.h
#include <winrt/Windows.Storage.Pickers.h>
#include <microsoft.ui.xaml.window.h>
#include <shobjidl_core.h>

// MainWindow.xaml.cpp — inside a MainWindow member function
Windows::Storage::Pickers::FileOpenPicker picker;
picker.FileTypeFilter().Append(L".png");
picker.FileTypeFilter().Append(L".jpg");

// Get the window handle (HWND) of the current WinUI 3 window.
auto windowNative{ this->m_inner.as<::IWindowNative>() };
HWND hwnd{ 0 };
windowNative->get_WindowHandle(&hwnd);

// Associate the picker with the window.
auto initializeWithWindow{ picker.as<::IInitializeWithWindow>() };
initializeWithWindow->Initialize(hwnd);

auto file{ co_await picker.PickSingleFileAsync() };
if (!file)
{
    // The user cancelled the picker.
}

Sugerencia

El enfoque recomendado para las aplicaciones nuevas es usar los selectores de SDK de Aplicaciones para Windows (Microsoft.Windows.Storage.Pickers), que aceptan un WindowId en el constructor y no requieren el patrón InitializeWithWindow. Consulte los ejemplos anteriores de este artículo.

Para obtener más información sobre cómo recuperar un identificador de ventana, consulte Recuperación de un identificador de ventana (HWND).