Visualizzare gli oggetti dell'interfaccia utente WinRT che dipendono da CoreWindow

Alcuni selettori, popup, finestre di dialogo e altri oggetti di Windows Runtime (WinRT) dipendono da CoreWindow, in genere per visualizzare un'interfaccia utente. Anche se CoreWindow non è supportato nelle app desktop (vedere Classi di base non supportate), è possibile comunque usare molte di queste classi WinRT nell'app desktop aggiungendo un po' di codice di interoperabilità.

L'app desktop può essere Libreria dell'interfaccia utente di Windows (WinUI) 3, Windows Presentation Foundation (WPF) o app Windows Form (WinForms). Gli esempi di codice vengono presentati in C# e C++/WinRT.

Impostare l'handle della finestra proprietaria (HWND) per un oggetto dell'interfaccia utente WinRT

Per le classi che implementano l'interfaccia IInitializeWithWindow (o l'interfaccia IDataTransferManagerInterop), è possibile usare tale interfaccia per impostare una finestra proprietaria sull'oggetto prima di visualizzarla. Il processo si articola in due passaggi.

  1. Decidere quale finestra sarà proprietaria dell'oggetto dell'interfaccia utente da visualizzare e recuperare l'HWND della finestra. Per altri dettagli ed esempi di codice per questo passaggio, consultare Recuperare un handle di finestra (HWND).
  2. Quindi chiamare l'API di interoperabilità appropriata (per C# o C++/WinRT) per impostare un handle di finestra proprietaria (HWND) per l'oggetto interfaccia utente WinRT.

Per le classi che implementano IInitializeWithWindow

Queste classi implementano IInitializeWithWindow:

Nota

L'elenco precedente è necessariamente incompleto: fare riferimento alla documentazione di un tipo per verificare se implementa IInitializeWithWindow (o un'interfaccia di interoperabilità equivalente).

Le sezioni successive contengono esempi di codice per visualizzare FolderPicker. in sostanza è la stessa tecnica per visualizzare una delle API elencate in precedenza.

WinUI 3 con C# (anche WPF/WinForms con .NET 6 o versione successiva)

Nota

Gli esempi di codice in questa sezione usano la classe di interoperabilità C# WinRT.Interop.WindowNative. Se si usa .NET 6 o versione successiva, è possibile usare tale classe in un progetto WPF o WinForms. Per informazioni sulla configurazione del progetto a tale scopo, vedere Chiamare le API interop da un'app .NET.

Il codice C# seguente prevede che sia già stato usato il modello documentato in Recuperare un handle di finestra (HWND). Quindi, per impostare la finestra del proprietario per l'oggetto dell'interfaccia utente da visualizzare, il codice chiama il metodo Initialize nella classe di interoperabilità C# WinRT.Interop.InitializeWithWindow. Per altre informazioni sulle classi di interoperabilità C#, vedere Chiamare le API interop da un'app .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++

Il codice C++/WinRT seguente prevede che sia già stato usato il modello documentato in Recuperare un handle di finestra (HWND). Quindi, per impostare la finestra proprietaria per l'oggetto dell'interfaccia utente da visualizzare, il codice chiama il metodo di interoperabilità 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() };
}

Per le classi che implementano IDataTransferManagerInterop

La classe Windows.ApplicationModel.DataTransfer.DataTransferManager implementa l'interfaccia IDataTransferManagerInterop (come IInitializeWithWindow, che consente di impostare una finestra proprietaria).

In un'app desktop, invece di chiamare il metodo DataTransferManager.ShowShareUI si chiama IDataTransferManagerInterop::ShowShareUIForWindow, come illustrato negli esempi di codice seguenti.

WinUI 3 con C# (anche WPF/WinForms con .NET 6 o versione successiva)

// 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);
}
...

Per le classi che implementano IUserConsentVerifierInterop

la classe Windows.Security.Credentials.UI.UserConsentVerifier implementa l'interfaccia IUserConsentVerifierInterop (come IInitializeWithWindow, che consente di impostare una finestra proprietaria).

In un'app desktop, invece di chiamare il metodo UserConsentVerifier.RequestVerificationAsync:

Per altre informazioni ed esempi di codice, consultare UserConsentVerifier.

Per le classi che implementano altre interfacce di interoperabilità

Queste interfacce hanno metodi XxxForWindow, che consentono di impostare un handle di finestra proprietaria (HWND). È possibile usare queste interfacce direttamente da C++/WinRT. Le versioni delle interfacce esistono anche sotto forma di classi C#. Per altri dettagli, vedere Chiamare le API interop da un'app .NET.