Anzeigen von WinRT UI-Objekten, die von CoreWindow abhängig sind

Bestimmte Auswahlsteuerelemente, Popups, Dialogfelder und andere WinRT-Objekte (Windows-Runtime) sind von einem CoreWindow-Element abhängig. In der Regel wird eine Benutzeroberfläche (UI) angezeigt. CoreWindow wird in Desktop-Apps zwar nicht unterstützt (siehe Nicht unterstützte Core-Klassen), Sie können aber dennoch viele dieser WinRT-Klassen in Ihrer Desktop-App verwenden, indem Sie ein wenig Interoperationscode hinzufügen.

Ihre Desktop-App kann WinUI 3-, Windows Presentation Foundation (WPF)- oder Windows Forms (WinForms)-Apps sein. Codebeispiele werden in C# und C++/WinRT dargestellt.

Festlegen des Besitzerfensterhandles (HWND) für ein WinRT-UI-Objekt

Für Klassen, die die IInitializeWithWindow-Schnittstelle (oder die entsprechende IDataTransferManagerInterop-Schnittstelle) implementieren, können Sie diese Schnittstelle verwenden, um ein Besitzerfenster für das Objekt festzulegen, bevor Sie es anzeigen. Dies ist ein zweistufiger Prozess.

  1. Entscheiden Sie, welches Fenster der Besitzer des UI-Objekts sein soll, das Sie anzeigen möchten, und rufen Sie das HWND dieses Fensters auf. Weitere Details und Codebeispiele für diesen Schritt finden Sie unter Abrufen eines Fensterhandles (HWND).
  2. Rufen Sie dann die entsprechende Interoperabilitäts-API (für C# oder C++/WinRT) auf, um einen Besitzerfensterhandle (HWND) für das WinRT-UI-Objekt festzulegen.

Für Klassen, die „IInitializeWithWindow“ implementieren

Diese Klassen implementieren IInitializeWithWindow:

Hinweis

Die oben aufgeführte Liste ist notwendigerweise unvollständig – verweisen Sie auf die Dokumentation eines Typs, um festzustellen, ob IInitializeWithWindow (oder eine entsprechende Interop-Schnittstelle) implementiert wird.

Die nächsten Abschnitte enthalten Codebeispiele zum Anzeigen eines FolderPicker. Es ist jedoch dieselbe Technik, eine der oben aufgeführten APIs anzuzeigen.

WinUI 3 mit C# (auch WPF/WinForms mit .NET 6 oder höher)

Hinweis

Die Codebeispiele in diesem Abschnitt verwenden die WinRT.Interop.WindowNative C#-Interop-Klasse. Wenn Sie auf .NET 6 oder höher abzielen, können Sie diese Klasse in einem WPF- oder WinForms-Projekt verwenden. Informationen zum Einrichten Ihres Projekts hierzu finden Sie unter Aufrufen von Interop-APIs aus einer .NET-App.

Der folgende C#-Code setzt voraus, dass Sie bereits das Muster verwendet haben, das in Abrufen eines Fensterhandles (HWND) dokumentiert ist. Um dann das Besitzerfenster für das anzuzeigende UI-Objekt festzulegen, ruft der Code die Initialize-Methode für die WinRT.Interop.InitializeWithWindow C#-Interop-Klasse auf. Weitere Informationen zu den C#-Interop-Klassen finden Sie unter Aufrufen von Interop-APIs aus einer .NET-App.

// 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 mit C++

Der folgende C++/WinRT-Code setzt voraus, dass Sie bereits das Muster verwendet haben, das in Abrufen eines Fensterhandles (HWND) dokumentiert ist. Um dann das Besitzerfenster für das anzuzeigende UI-Objekt festzulegen, ruft der Code die Interoperatability-Methode IInitializeWithWindow::Initialize auf.

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

Für Klassen, die IDataTransferManagerInterop implementieren

Die Windows.ApplicationModel.DataTransfer.DataTransferManager-Klasse implementiert die IDataTransferManagerInterop-Schnittstelle (mit der Sie wie IInitializeWithWindow ein Besitzerfenster festlegen können).

Anstatt in einer Desktop-App die DataTransferManager.ShowShareUI-Methode aufzurufen, rufen Sie IDataTransferManagerInterop::ShowShareUIForWindow wie in den folgenden Codebeispielen dargestellt auf.

WinUI 3 mit C# (auch WPF/WinForms mit .NET 6 oder höher)

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

Für Klassen, die IUserConsentVerifierInterop implementieren

Die Windows.Security.Credentials.UI.UserConsentVerifier-Klasse implementiert die IUserConsentVerifierInterop-Schnittstelle (mit der Sie wie IInitializeWithWindow ein Besitzerfenster festlegen können).

Anstatt in einer Desktop-App die UserConsentVerifier.RequestVerificationAsync-Methode aufzurufen:

Weitere Informationen und Codebeispiele finden Sie unter UserConsentVerifier.

Für Klassen, die andere Interop-Schnittstellen implementieren

Diese Schnittstellen verfügen über XxxForWindow-Methoden, mit denen Sie ein Besitzerfensterhandle (HWND) festlegen können. Sie können diese Schnittstellen direkt aus C++/WinRT verwenden. Versionen der Schnittstellen sind auch in Form von C#-Klassen vorhanden. Weitere Informationen finden Sie unter Aufrufen von Interop-APIs aus einer .NET-App.