在 Windows 11 的 Win32 桌面应用中应用 Mica
Mica 是一种不透明的材质,可以将用户的主题和桌面壁纸结合起来,从而创建高度个性化的外观。 随着用户在屏幕上移动窗口,Mica 材质会动态调整,以便使用应用程序下的壁纸创建丰富的可视化效果。 此外,如果应用处于非活动状态,该材质可以通过回退到中性色来帮助用户专注于当前任务。
本文介绍如何使用 Mica 并将它作为 Win32 应用的基本层,用于在标题栏区域中确定应用程序的优先级和可见性。 有关使用 Mica 的应用分层的详细信息,请参阅 Mica 材料。
先决条件
要将 Mica 应用于 Windows 11 的 Win32 应用,需要使用 Windows 应用 SDK。 需要准备好以下各项:
- 安装最新的 Windows App SDK Visual Studio Extension 或 Microsoft.WindowsAppSDK NuGet 包。 请参阅下载 Windows 应用 SDK。
- 对于未打包的应用,请引用 Windows 应用 SDK,安装 WinRT,并安装匹配的 Windows 应用运行时可再发行组件 (Microsoft.WindowsAppRuntime.Redist) 。 请参阅依赖于框架的使用外部位置打包的应用或未打包应用的 Windows 应用 SDK 部署指南。
如何在 Win32 应用中使用 Mica
要在应用中使用 Mica,需要使用 MicaController 类。 此类管理系统背景材料的呈现以及 Mica 材料系统策略的处理。
默认情况下,MicaController 会响应系统浅色和深色主题。 若要替代此行为,可以将以下属性传递给 MicaController:
提示
本节中的代码取自 GitHub 上的 Windows 应用 SDK Win32 Mica 示例。 有关完整代码,请参阅 GitHub 存储库。 这些示例使用 C++/WinRT。
要启用 Mica,需要引用 Windows 应用 SDK、Compositor 和 DispatcherQueue。
此示例演示如何执行以下操作来设置未打包的应用:
- 初始化 WinRT。
- 从未打包的应用引用 WindowsAppSDK。
- 有关详细信息,请参阅将 Windows 应用 SDK 运行时用于使用外部位置打包的应用或未打包的应用。
- 如需了解示例代码,请参阅
WindowsAppSDKBootstrapperContext
Utilities.h。
- 注册窗口类。
- 创建 Mica 调度程序队列控制器
- 初始化 WinRT 合成器。
int __stdcall WinMain(_In_ HINSTANCE, _In_opt_ HINSTANCE, _In_ PSTR, _In_ int)
{
// Initialize WinRt Instance
winrt::init_apartment();
// Enable referencing the WindowsAppSDK from an unpackaged app.
Utilities::WindowsAppSDKBootstrapperContext sdkContext;
// Register Window class before making the window.
MicaWindow::RegisterWindowClass();
// Mica requires a compositor, which also requires a dispatcher queue.
auto controller = Utilities::CreateDispatcherQueueControllerForCurrentThread();
auto compositor = winrt::Compositor();
// Create your window...
...
}
void MicaWindow::RegisterWindowClass()
{
auto instance = winrt::check_pointer(GetModuleHandleW(nullptr));
WNDCLASSEX wcex = { sizeof(wcex) };
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.hInstance = instance;
wcex.hIcon = LoadIconW(instance, IDI_APPLICATION);
wcex.hCursor = LoadCursorW(nullptr, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wcex.lpszClassName = ClassName.c_str();
wcex.hIconSm = LoadIconW(wcex.hInstance, IDI_APPLICATION);
winrt::check_bool(RegisterClassExW(&wcex)); // check if the window class was registered successfully
}
winrt::init_apartment
方法默认为多线程。 如果应用需要单线程(如 WebView2 示例),则可以轻松设置类型。
winrt::init_apartment(winrt::apartment_type::single_threaded);
现在可使用 CreateWindowEx()
函数创建窗口。 然后,必须创建一个窗口目标并将其设置为根,以指定要应用 Mica 的层。 最后,声明窗口和目标支持 Mica。
Win32 Mica 示例 创建 DesktopWindow 和 MicaWindow 类来完成这项工作。 这些类包括 ClassName
、windowTitle
、m_target
、m_micaController
和 m_isMicaSupported
。
// Mica window is inherited from the MicaWindow class, which is an extension of the DesktopWindow Class.
// Here, we initialize the main window and set the title.
auto window = MicaWindow(compositor, L"Hello, Mica!");
// Create the main window and enable Mica.
MicaWindow::MicaWindow(const winrt::Compositor& compositor, const std::wstring& windowTitle)
{
auto instance = winrt::check_pointer(GetModuleHandleW(nullptr));
WINRT_ASSERT(!m_window); // check that window is not initialized
WINRT_VERIFY(
// Window Properties
CreateWindowExW(
WS_EX_COMPOSITED,
ClassName.c_str(), // declared in MicaWindow.h and defined above
windowTitle.c_str(),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
800, 600,
nullptr,
nullptr,
instance,
this
));
// Check that the window was created successfully.
WINRT_ASSERT(m_window);
ShowWindow(m_window, SW_SHOWDEFAULT);
UpdateWindow(m_window);
// The Mica controller needs to set a target with a root to recognize the visual base layer.
m_target = CreateWindowTarget(compositor);
// Need to set a root before we can enable Mica.
m_target.Root(compositor.CreateContainerVisual());
m_micaController = winrt::MicaController();
m_isMicaSupported = m_micaController.SetTarget(winrt::Microsoft::UI::WindowId{ reinterpret_cast<uint64_t>(m_window) }, m_target);
}
如何在 Win32 WebView2 应用中使用 Mica
对于大多数 Win32 应用程序而言,应用 Mica 的基本原则都是一致。 WebView2 的过程遵循前面显示的 Win32 说明中的基本步骤。 但是,在这种情况下,需要从 WinRT 的 init_apartment
功能中指定一个单线程进程。
提示
本节中的代码取自 GitHub 上的 Windows 应用 WebView2 Mica 示例。 有关完整代码,请参阅 GitHub 存储库。
若要开始,请设置所需的单元、控制器、合成器、目标和根。 默认情况下,WinRT init_apartment
函数是多线程的,但 WebView2 本质上是单线程的。 要将 init_apartment
设为单线程,请传递 winrt::apartment_type::single_threaded
参数。 在 Mica WebView2 示例中,我们为以下代码中引用的 Web 视图函数创建了单独的类,以简化语法。
int __stdcall WinMain(_In_ HINSTANCE, _In_opt_ HINSTANCE, _In_ PSTR, _In_ int)
{
winrt::init_apartment(winrt::apartment_type::single_threaded);
// Enable referencing the WindowsAppSDK from an unpackaged app.
// Remember to have a matching Microsoft.WindowsAppRuntime.Redist installed.
// https://learn.microsoft.com/windows/apps/windows-app-sdk/deploy-unpackaged-apps
Utilities::WindowsAppSDKBootstrapperContext sdkContext;
CompositionWindow::RegisterWindowClass();
// A dispatcher queue is required to be able to create a compositor.
auto controller = Utilities::CreateDispatcherQueueControllerForCurrentThread();
auto compositor = winrt::Compositor();
auto window = WebView2Window(compositor, L"Hello, WebView2!");
...
}
有关 WebView2Window 类及其与 Mica 的集成的完整演示,请参阅 GitHub 上的 Windows 应用 SDK WebView2 Mica 示例。 请注意 CompositionWindow 和 WebView2Window 类处理消息、初始化 Web 视图环境,并在窗口关闭后删除窗口控制器的方式。