Visualización de objetos de la interfaz de usuario de WinRT que dependen de CoreWindow

Ciertos selectores, elementos emergentes, cuadros de diálogo y otros objetos de Windows Runtime (WinRT) dependen de una instancia de CoreWindow; normalmente, para mostrar una interfaz de usuario (UI). Aunque CoreWindow no se admite en aplicaciones de escritorio (consulte Clases principales no admitidas), puede seguir usando muchas de esas clases de WinRT en la aplicación de escritorio tras agregar algo de código de interoperación.

La aplicación de escritorio puede ser una aplicación WinUI 3, Windows Presentation Foundation (WPF) o Windows Forms (WinForms). Los ejemplos de código se presentan en C# y C++/WinRT.

Establecer el identificador de ventana de propietario (HWND) para un objeto de interfaz de usuario de WinRT

Para las clases que implementan la interfaz IInitializeWithWindow (o la interfaz equivalente IDataTransferManagerInterop), puede usar esa interfaz para establecer una ventana de propietario en el objeto antes de mostrarla. Se trata de un proceso de dos pasos:

  1. Decida qué ventana será el propietario del objeto de UI que desea mostrar y recupere el HWND de esa ventana. Para obtener más detalles y ejemplos de código para este paso, consulte Recuperación de un identificador de ventana (HWND).
  2. A continuación, llame a la API de interoperabilidad adecuada (para C# o C++/WinRT) para establecer un identificador de ventana de propietario (HWND) para el objeto de UI de WinRT.

Para las clases que implementan IInitializeWithWindow

Estas clases implementan IInitializeWithWindow:

Nota:

La lista anterior está necesariamente incompleta: consulte la documentación de un tipo para ver si implementa IInitializeWithWindow (o una interfaz de interoperabilidad equivalente).

Las secciones siguientes contienen ejemplos de código para mostrar un FolderPicker. Pero es la misma técnica para mostrar cualquiera de las API enumeradas anteriormente.

WinUI 3 con C# (también WPF/WinForms con .NET 6 o posterior)

Nota:

Los ejemplos de código de esta sección usan la clase de interoperabilidad de C# WinRT.Interop.WindowNative. Si tiene como destino .NET 6 o posterior, puede usar esa clase en un proyecto de WPF o WinForms. Para obtener información sobre cómo configurar el proyecto para ello, consulte Llamada a las API de interoperabilidad desde una aplicación con .NET.

El código de C# siguiente espera que ya haya usado el patrón documentado en Recuperar un identificador de ventana (HWND). A continuación, para establecer la ventana de propietario para el objeto de UI que desea mostrar, el código llama al método Initialize en la clase de interoperabilidad WinRT.Interop.InitializeWithWindow de C#. Para obtener más información sobre las clases de interoperabilidad de C#, consulte Llamada a las API de interoperabilidad desde una aplicación con .NET.

// MainWindow.xaml.cs
private async void ShowFolderPickerAsync(IntPtr hWnd)
{
    // Create a folder picker.
    var folderPicker = new Windows.Storage.Pickers.FolderPicker();

    // Initialize the folder picker with the window handle (HWND).
    WinRT.Interop.InitializeWithWindow.Initialize(folderPicker, hWnd);

    // Use the folder picker as usual.
    folderPicker.FileTypeFilter.Add("*");
    var folder = await folderPicker.PickSingleFolderAsync();
}

WinUI 3 con C++

El código de C++/WinRT siguiente espera que ya haya usado el patrón documentado en Recuperar un identificador de ventana (HWND). A continuación, para establecer la ventana de propietario para el objeto de UI que desee mostrar, el código llama al método de interoperabilidad IInitializeWithWindow::Initialize.

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

// MainWindow.xaml.cpp
winrt::fire_and_forget ShowFolderPickerAsync(HWND hWnd)
{
    // Create a folder picker.
    Windows::Storage::Pickers::FolderPicker folderPicker;

    // Initialize the folder picker with the window handle (HWND).
    auto initializeWithWindow{ folderPicker.as<::IInitializeWithWindow>() };
    initializeWithWindow->Initialize(hWnd);

    // Use the folder picker as usual.
    folderPicker.FileTypeFilter().Append(L"*");
    auto folder{ co_await folderPicker.PickSingleFolderAsync() };
}

Para las clases que implementan IDataTransferManagerInterop

La clase Windows.ApplicationModel.DataTransfer.DataTransferManager implementa la interfaz IDataTransferManagerInterop (que, como IInitializeWithWindow, le permite establecer una ventana de propietario).

En una aplicación de escritorio, en lugar de llamar al método DataTransferManager.ShowShareUI, llame a IDataTransferManagerInterop::ShowShareUIForWindow, como se muestra en los ejemplos de código siguientes.

WinUI 3 con C# (también WPF/WinForms con .NET 6 o posterior)

// MainWindow.xaml.cs
...
public sealed partial class MainWindow : Window
{
    ...

    [System.Runtime.InteropServices.ComImport]
    [System.Runtime.InteropServices.Guid("3A3DCD6C-3EAB-43DC-BCDE-45671CE800C8")]
    [System.Runtime.InteropServices.InterfaceType(
        System.Runtime.InteropServices.ComInterfaceType.InterfaceIsIUnknown)]
    interface IDataTransferManagerInterop
    {
        IntPtr GetForWindow([System.Runtime.InteropServices.In] IntPtr appWindow,
            [System.Runtime.InteropServices.In] ref Guid riid);
        void ShowShareUIForWindow(IntPtr appWindow);
    }

    static readonly Guid _dtm_iid = 
        new Guid(0xa5caee9b, 0x8708, 0x49d1, 0x8d, 0x36, 0x67, 0xd2, 0x5a, 0x8d, 0xa0, 0x0c);

    private void myButton_Click(object sender, RoutedEventArgs e)
    {
        // Retrieve the window handle (HWND) of the current WinUI 3 window.
        var hWnd = WinRT.Interop.WindowNative.GetWindowHandle(this);

        IDataTransferManagerInterop interop =
        Windows.ApplicationModel.DataTransfer.DataTransferManager.As
            <IDataTransferManagerInterop>();

        IntPtr result = interop.GetForWindow(hWnd, _dtm_iid);
        var dataTransferManager = WinRT.MarshalInterface
            <Windows.ApplicationModel.DataTransfer.DataTransferManager>.FromAbi(result);

        dataTransferManager.DataRequested += (sender, args) =>
        {
            args.Request.Data.Properties.Title = "In a desktop app...";
            args.Request.Data.SetText("...display WinRT UI objects that depend on CoreWindow.");
            args.Request.Data.RequestedOperation = 
                Windows.ApplicationModel.DataTransfer.DataPackageOperation.Copy;
        };

        // Show the Share UI
        interop.ShowShareUIForWindow(hWnd);
    }
}
...

WinUI 3 con C++

// pch.h in a Windows App SDK app
...
#include <shobjidl_core.h>
#include <microsoft.ui.xaml.window.h>
#include <winrt/Windows.ApplicationModel.DataTransfer.h>
...

// MainWindow.xaml.cpp
...
void MainWindow::myButton_Click(IInspectable const&, RoutedEventArgs const&)
{
    // Retrieve the window handle (HWND) of the current WinUI 3 window.
    auto windowNative{ this->m_inner.as<::IWindowNative>() };
    HWND hWnd{ 0 };
    windowNative->get_WindowHandle(&hWnd);

    winrt::com_ptr<IDataTransferManagerInterop> interop = 
        winrt::get_activation_factory<Windows::ApplicationModel::DataTransfer::DataTransferManager,
        IDataTransferManagerInterop>();

    winrt::guid _dtm_iid{ 0xa5caee9b, 0x8708, 0x49d1, { 0x8d, 0x36, 0x67, 0xd2, 0x5a, 0x8d, 0xa0, 0x0c } };
    Windows::ApplicationModel::DataTransfer::DataTransferManager dataTransferManager{ nullptr };
    interop->GetForWindow(hWnd, _dtm_iid, winrt::put_abi(dataTransferManager));

    dataTransferManager.DataRequested([](Windows::ApplicationModel::DataTransfer::DataTransferManager const& /* sender */,
        Windows::ApplicationModel::DataTransfer::DataRequestedEventArgs const& args)
    {
        args.Request().Data().Properties().Title(L"In a desktop app...");
        args.Request().Data().SetText(L"...display WinRT UI objects that depend on CoreWindow.");
        args.Request().Data().RequestedOperation(Windows::ApplicationModel::DataTransfer::DataPackageOperation::Copy);
    });

    interop->ShowShareUIForWindow(hWnd);
}
...

Para las clases que implementan IUserConsentVerifierInterop

La clase Windows.Security.Credentials.UI.UserConsentVerifier implementa la interfaz IUserConsentVerifierInterop (que, como IInitializeWithWindow, permite establecer una ventana de propietario).

En una aplicación de escritorio, en lugar de llamar al método UserConsentVerifier.RequestVerificationAsync:

Para obtener más información y ejemplos de código, consulte UserConsentVerifier.

Para las clases que implementan otras interfaces de interoperabilidad

Estas interfaces tienen métodos XxxForWindow, que le permiten establecer un identificador de ventana de propietario (HWND). Puede usar estas interfaces directamente desde C++/WinRT. Las versiones de las interfaces también existen en forma de clases de C#; para obtener más información, consulte Llamada a las API de interoperabilidad desde una aplicación con .NET.