接触WinUI3是我第一次知道原来微软有这么多前端技术:Winforms、WPF、UWP、MAUI、WinUI3、Win32 API、WinRT。前五个都是Visual Studio提供的模板,Win32是Windows底层的C/C++API接口,WinRT是Windows提供的一种跨平台运行时API接口。
WinUI3是新推出的一些列的Windows UI平台组件(根据我的理解也就是一堆UI组件了,基本上啥高级封装都没有),功能实现基本上是靠Win32和WinRT实现。
实现步骤可以参照:Example: Use Mica in a Windows AppSDK/WinUI 3 app
或者WinUI-Gallery
首先,必须明确WinUI3是通过WinRT中的DesktopAcrylicController类提供了为COM组件设置亚克力笔刷的方法,所以先创建对象,然后指定COM组件
DesktopAcrylicController m_acrylicController = new();
m_acrylicController.AddSystemBackdropTarget(m_Window.As());
非常理论,非常正确。运行会抛出一个不知所云的C++异常
然后如果仔细查看AddSystemBackdropTarget的文档,会发现该方法必须要通过线程调度队列(DispatcherQueue)去调用
这里有个坑,开始我以为这个DispatcherQueue是指Window的队列(Microsoft.UI.Dispatching.DispatcherQueue),但实际上指的是由WinRT创建的DispatcherQueue(Windows.System.DispatcherQueue)
详细可以看我在Stackoverflow上的提问:How to set the acrylic style to window?
对于这一部分,需要通过CreateDispatcherQueueController()函数来实现。参考MS的示例,可以通过创建WindowsSystemDispatcherQueueHelper去实现
首先引入函数,根据官方文档对CreateDispatcherQueueController和DispatcherQueueOptions的描述,需要对参数中的结构体DispatcherQueueOptions做映射
struct DispatcherQueueOptions
{internal int dwSize;
internal int threadType;
internal int apartmentType;
}
之后引入函数
[DllImport("CoreMessaging.dll")]
private static extern int CreateDispatcherQueueController(
[In] DispatcherQueueOptions options,
[In, out, MarshalAs(UnmanagedType.IUnknow)] ref object dispatcherQueueController // MarshalAs指示应该将这个object参数封装成IUnknown类型传递给C++函数
)
最后检查并确保调度线程控制器存在
object m_dispatcherQueueController = null;
public void EnsureWindowsSystemDispatcherQueueController()
{if (DispatcherQueue.GetForCurrentThread() != null)
{return;
}
if (m_dispatcherQueueController == null)
{DispatcherQueueOptions options;
options.dwSize = Marshal.SizeOf(typeof(DispatcherQueueOptions));
options.threadType = 2;
options.apartmentType = 2;
CreateDispatcherQueueController(options, ref m_dispatcherQueueController);
}
}
之后在调用AddSystemBackdropTarget()函数前先确保WinRT显示层的调度线程存在再运行
WindowsSystemDispatcherQueueHelper m_wsdqHelper = new();
m_wsdqHelper.EnsureWindowsSystemDispatcherQueueController();
DesktopAcrylicController m_backdropController = new();
m_backdropController.AddSystemBackdropTarget(m_window.As());
运行发现程序没有报错并成功启动,但是并没有实现亚克力的效果。通过看MS的示例我发现我没有为acrylicController设置SystemBackdropConfiguration。所以实例化一个SystemBackdropConfiguration对象然后为acrylicController配置上就解决了。
ps:看了一下SystemBackdropConfiguration的源码,不太理解这个函数在实例化时注册和初始化了一些什么东西。
最终成功代码如下:
WindowsSystemDispatcherQueueHelper m_wsdqHelper = new();
m_wsdqHelper.EnsureWindowsSystemDispatcherQueueController();
SystemBackdropConfiguration m_configurationSource = new();
// m_configurationSource.IsInputActive = true;
DesktopAcrylicController m_backdropController = new();
m_backdropController.AddSystemBackdropTarget(m_window.As());
m_backdropController.SetSystemBackdropConfiguration(m_configurationSource);
但是他有个问题:窗口在失去焦点时不会更新背景,我看WinUI-Gallery的处理办法好像是让失去焦点的窗口暂时不启用亚克力效果,不知道有没有更好的解决办法,欢迎分享。
你是否还在寻找稳定的海外服务器提供商?创新互联www.cdcxhl.cn海外机房具备T级流量清洗系统配攻击溯源,准确流量调度确保服务器高可用性,企业级服务器适合批量采购,新人活动首月15元起,快前往官网查看详情吧