[WinUI3]如何设置亚克力窗口?-创新互联

接触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实现。

成都创新互联公司专注于企业营销型网站建设、网站重做改版、乐东黎族网站定制设计、自适应品牌网站建设、html5购物商城网站建设、集团公司官网建设、成都外贸网站建设、高端网站制作、响应式网页设计等建站业务,价格优惠性价比高,为乐东黎族等各大城市提供网站开发制作服务。

实现步骤可以参照: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元起,快前往官网查看详情吧


网页标题:[WinUI3]如何设置亚克力窗口?-创新互联
本文URL:http://myzitong.com/article/ccshoc.html