显示依赖于 CoreWindow 的 WinRT UI 对象
某些选取器、弹出窗口、对话框和其他 Windows 运行时 (WinRT) 对象依赖于 CoreWindow;通常用于显示显示用户界面 (UI)。 即使 CoreWindow 在桌面应用中不受支持(请参阅主要不受支持的类),但你仍可通过添加少量互操作代码在桌面应用中使用其中许多 WinRT 类。
桌面应用程序可以是 WinUI 3、Windows Presentation Foundation (WPF) 或 Windows Forms (WinForms)应用。 代码示例采用 C# 和 C++/WinRT 语言编写。
设置 WinRT UI 对象的所有者窗口句柄 (HWND)
对于实现了 IInitializeWithWindow 接口(或等效的 IDataTransferManagerInterop 接口)的类,可以在显示对象之前使用该接口在对象上设置所有者窗口。 此过程由两个步骤组成。
- 确定哪个窗口将是要显示的 UI 对象的所有者,并获取该窗口的 HWND。 有关此步骤的更多详细信息和代码示例,请参阅检索窗口句柄 (HWND)。
- 然后调用相应的互操作性 API(C# 或 C++/WinRT),为 WinRT UI 对象设置所有者窗口句柄 (HWND)。
对于实现 IInitializeWithWindow 的类
这些类会实现 IInitializeWithWindow:
- Windows.ApplicationModel.Contacts.PinnedContactManager
- Windows.ApplicationModel.Payments.PaymentMediator
- Windows.Devices.Enumeration.DevicePicker
- Windows.Graphics.Capture.GraphicsCapturePicker
- Windows.Media.Casting.CastingDevicePicker
- Windows.Media.DialProtocol.DialDevicePicker
- Windows.Networking.NetworkOperators.ProvisioningAgent
- Windows.Security.Authentication.OnlineId.OnlineIdAuthenticator
- Windows.Services.Store.StoreContext
- Windows.Storage.Pickers.FileOpenPicker
- Windows.Storage.Pickers.FileSavePicker
- Windows.Storage.Pickers.FolderPicker
- Windows.System.FolderLauncherOptions — Windows 10 版本 1903(10.0;内部版本 18362)及更高版本
- Windows.System.LauncherOptions — Windows 10 版本 1903(10.0;内部版本 18362)及更高版本
- Windows.UI.Core.CoreWindowDialog
- Windows.UI.Core.CoreWindowFlyout
- Windows.UI.Popups.MessageDialog。 但对于新应用,我们建议使用 ContentDialog 控件。
- Windows.UI.Popups.PopupMenu
- Windows.UI.StartScreen.SecondaryTile
- Windows.Web.Http.Filters.HttpBaseProtocolFilter
注意
上述列表并不完整 - 请参阅类型的文档,了解该类型是否实现了 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,允许设置所有者窗口)。
在桌面应用中,需要调用 DataTransferManager.ShowShareUI 方法,而不是调用 IDataTransferManagerInterop::ShowShareUIForWindow 方法,如以下代码示例所示。
使用 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 方法:
- C# 中的检测示例。 调用 Windows.Security.Credentials.UI.UserConsentVerifierInterop C# 互操作类的 RequestVerificationForWindowAsync 方法。 有关 C# 互操作类的详细信息,请参阅从 .NET 应用调用互操作 API。
- C++/WinRT。 调用 IUserConsentVerifierInterop::RequestVerificationForWindowAsync。
有关详细信息和示例,请参阅 UserConsentVerifier。
对于实现其他互操作接口的类
这些接口都有 XxxForWindow 方法,可用于设置所有者窗口句柄 (HWND)。 可以直接从 C++/WinRT 使用这些接口。 这些接口的版本也以 C# 类的形式存在 - 有关详细信息,请参阅从 .NET 应用程序调用互操作 API。
- IAccountsSettingsPaneInterop
- IDragDropManagerInterop
- IInputPaneInterop
- IPlayToManagerInterop
- IPrintManagerInterop
- IRadialControllerConfigurationInterop
- IRadialControllerIndependentInputSourceInterop
- IRadialControllerInterop
- ISpatialInteractionManagerInterop
- ISystemMediaTransportControlsInterop
- IUIViewSettingsInterop
- IWebAuthenticationCoreManagerInterop