显示依赖于 CoreWindow 的 WinRT UI 对象

某些选取器、弹出窗口、对话框和其他 Windows 运行时(WinRT)对象需要 CoreWindow;通常用于显示用户界面(UI)。 即使桌面应用不支持 CoreWindow (请参阅 Core 不支持的类),你仍可以通过添加一点点互作代码在桌面应用中使用这些 WinRT 类。

桌面应用可以是 WinUI 3Windows Presentation Foundation (WPF)Windows 窗体(WinForms) 应用。 代码示例在 C# 中呈现,C++/WinRT

设置 WinRT UI 对象的所有者窗口句柄(HWND)

对于实现 IInitializeWithWindow 接口(或等效 的 IDataTransferManagerInterop 接口)的类,可以在显示对象之前使用该接口在对象上设置所有者窗口。 这是一个两步过程。

  1. 确定哪个窗口将成为要显示的 UI 对象的所有者,并检索该窗口的 HWND。 有关此步骤的更多详细信息和代码示例,请参阅 检索窗口句柄(HWND)
  2. 然后调用适当的互作性 API(适用于 C# 或 C++/WinRT),为 WinRT UI 对象设置所有者窗口句柄(HWND)。

对于实现 IInitializeWithWindow 的类

这些类实现 IInitializeWithWindow

注释

上述列表一定不完整,请参阅类型的文档,以查看它是否实现 IInitializeWithWindow (或等效的互作接口)。

后续部分包含用于显示 FolderPicker的代码示例。 但是,显示上面列出的任何 API 都是相同的技术。

具有 C# 的 WinUI 3(以及使用 .NET 6 或更高版本的 WPF/WinForms)

注释

本节中的代码示例使用 WinRT.Interop.WindowNative C# 互作类。 如果面向 .NET 6 或更高版本,则可以在 WPF 或 WinForms 项目中使用该类。 有关配置项目以实现这一功能的信息,请参阅 从 .NET 应用调用互操作 API

下面的 C# 代码假定你已经使用了在 检索窗口句柄(HWND)中记录的模式。 然后,若要设置要显示的 UI 对象的所有者窗口,代码会在 WinRT.Interop.InitializeWithWindow C# 互作类上调用 Initialize 方法。 要了解有关 C# 互操作类的更多信息,请参阅 从 .NET 应用调用互操作 API

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

具有 C++ 的 WinUI 3

下面的C++/WinRT 代码要求你已使用 检索窗口句柄(HWND)中所述的模式。 然后,若要设置要显示的 UI 对象的所有者窗口,代码将调用互作性方法 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() };
}

对于实现 IDataTransferManagerInterop 的类

Windows.ApplicationModel.DataTransfer.DataTransferManager 类实现了 IDataTransferManagerInterop 接口(它与 IInitializeWithWindow类似,都允许您设置一个所有者窗口)。

在桌面应用中,调用 IDataTransferManagerInterop::ShowShareUIForWindow,而不是调用 DataTransferManager.ShowShareUI 方法,如下面的代码示例所示。

具有 C# 的 WinUI 3(以及使用 .NET 6 或更高版本的 WPF/WinForms)

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

具有 C++ 的 WinUI 3

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

对于实现 IUserConsentVerifierInterop 的类

Windows.Security.Credentials.UI.UserConsentVerifier 类实现了 IUserConsentVerifierInterop 接口(该接口与 IInitializeWithWindow类似,让您可以设置一个所有者窗口)。

在桌面应用中,而不是调用 UserConsentVerifier.RequestVerificationAsync 方法:

有关详细信息和代码示例,请参阅 UserConsentVerifier

对于实现其他互操作接口的类

这些接口具有 XxxForWindow 方法,可用于设置所有者窗口句柄(HWND)。 可以直接从 C++/WinRT 使用这些接口。 接口的版本也以 C# 类的形式存在,有关详细信息,请参阅 .NET 应用中的调用互作 API