SystemEvents 是一个开发 win32 窗口项目很常用的类,其中封装了一些常用的系统广播消息。在 WinUI3 项目中,SystemEvents 事件经常无法触发,简单排查了一下原因。

SystemEvent 内封装了一个线程和一个窗口,通过窗口消息在内部线程上调用事件,内部使用了 SystemEventInvokeInfo 对象来保存委托,RaiseEvent 方法遍历调用保存的 SystemEventInvokeInfo.Invoke 方法来触发事件。

public SystemEventInvokeInfo(Delegate d)
{
_delegate = d;
_syncContext = AsyncOperationManager.SynchronizationContext;
}
// fire the given event with the given params.
public void Invoke(bool checkFinalization, params object[] args)
{
try
{
// If we didn't get call back invoke directly.
if (_syncContext == null)
{
InvokeCallback(args);
}
else
{
// otherwise tell the context to do it for us.
_syncContext.Send(new SendOrPostCallback(InvokeCallback), args);
}
}
catch (InvalidAsynchronousStateException)
{
// if the synch context is invalid -- do the invoke directly for app compat.
// If the app's shutting down, don't fire the event (unless it's shutdown).
if (!checkFinalization || !AppDomain.CurrentDomain.IsFinalizingForUnload())
{
InvokeCallback(args);
}
}
}

我们可以注意到 SystemEventInvokeInfo.Invoke 判断了 _syncContext 变量,_syncContext 变量在 SystemEventInvokeInfo 构造时捕获,Invoke 时使用 _syncContext.Send 方法调用。

/// <summary>
/// DispatcherQueueSyncContext allows developers to await calls and get back onto the
/// UI thread. Needs to be installed on the UI thread through DispatcherQueueSyncContext.SetForCurrentThread
/// </summary>
public class DispatcherQueueSynchronizationContext : SynchronizationContext
{
private readonly DispatcherQueue m_dispatcherQueue; public DispatcherQueueSynchronizationContext(DispatcherQueue dispatcherQueue)
{
m_dispatcherQueue = dispatcherQueue;
} public override void Post(SendOrPostCallback d, object state)
{
if (d == null)
throw new ArgumentNullException(nameof(d)); m_dispatcherQueue.TryEnqueue(() => d(state));
} public override void Send(SendOrPostCallback d, object state)
{
throw new NotSupportedException("Send not supported");
} public override SynchronizationContext CreateCopy()
{
return new DispatcherQueueSynchronizationContext(m_dispatcherQueue);
}
}

而 WinUI3 的 UI 线程的默认 SynchronizationContext 为 DispatcherQueueSynchronizationContext,简单查看源码可以发现 DispatcherQueueSynchronizationContext.Send 并未实现,而是直接抛出了异常,所以从 UI 线程注册的 SystemEvents 事件默认是不会触发的。

解决方案也很简单:

SystemEvents.InvokeOnEventsThread(() =>
{
// 不需要设置,因为默认就是null
//SynchronizationContext.SetSynchronizationContext(null); SystemEvents.DisplaySettingsChanged += (s, a) =>
{
Debug.WriteLine("DisplaySettingsChanged");
};
});

我们借用一下 SystemEvents 的内部线程,在此线程上注册事件时 SystemEventInvokeInfo 捕获不到 SynchronizationContext,就会在 SystemEvents 内部线程上触发事件,自然就能正常触发了。

WinAppSDK / WinUI3 项目无法使用 SystemEvents 的问题的更多相关文章

  1. Vue项目无法使用局域网IP直接访问的配置方法

    一般使用 vue-cli 下来的项目是可以直接访问局域网 IP 打开的,比如 192.168.1.11:8080 .但是最近公司的一个项目只可以通过 localhost 访问. 需要配置一下,才可直接 ...

  2. win10本地python第三方库安装成功,但是pycharm项目无法使用解决方案

    一.背景win10本地python第三方库安装成功,但是pycharm项目无法使用解决方案如本地安装的python中的request库,在pycharm项目中居然无法使用,比较郁闷 pip list ...

  3. jhipster生成项目无法使用restful请求,报access_denied 403错误

    写在前边: 我们的微服务是注册中心.uaa.gateway为基础,添加微服务应用,昨天下午在测试jhipster的增删改查,因为jhipster生成的代码都是restful的,好不容易找到网关配置的映 ...

  4. [转]关于MyEclipse下的项目无法使用BASE64Encoder问题的解决办法

    [链接] http://blog.csdn.net/longlonglongchaoshen/article/details/75087616

  5. 解决Idea、WebStorm下使用Vue cli脚手架项目无法使用Webpack别名的问题

    问题截图: 解决方案: 1.打开File --> Setting 窗口 2.搜索 Webpack 3.选择如下路径 问题解决

  6. 含有SilverLight项目的代码重用

    很多时候,我们工程中不只是有SilverLight项目,然而我们想把其他的项目中的工具类,或者实体类复用到SilverLight项目中时,会发现SilverLight项目无法使用.这是个很普遍的现象. ...

  7. Hibernate项目里配置环境时,jar包配置不当会对测试结果产生影响。

    问题情况: 如下图所示,该图中,显示了一堆错误的jar包.这是导致了Junit4测试通过了,数据库却没反应的原因. 原因: 之所以出现这种情况,eclipse其实已经告诉了我们原因.如下图所示,这些j ...

  8. 前段时间,接手一个项目使用的是原始的jdbc作为数据库的访问,发布到服务器上在运行了一段时间之后总是会出现无法访问的情况,登录到服务器,查看tomcat日志发现总是报如下的错误。    Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException: Data source rejected est

    前段时间,接手一个项目使用的是原始的jdbc作为数据库的访问,发布到服务器上在运行了一段时间之后总是会出现无法访问的情况,登录到服务器,查看tomcat日志发现总是报如下的错误. Caused by: ...

  9. 导入maven项目出现 Unsupported IClasspathEntry kind=4

    Unsupported IClasspathEntry kind=4 这个异常会导致项目无法使用spring ide启动 来自:http://blog.csdn.net/kongqz/article/ ...

  10. 发布报错:Error ITMS-90635 - Invalid Mach-O in bundle - submitting to App store

    发布报错:Error ITMS-90635 - Invalid Mach-O in bundle - submitting to App store 昨晚上传项目到AppStore,报了这个错,纳尼! ...

随机推荐

  1. 详解instanceof底层原理,从零手写一个instanceof

    壹 ❀ 引 本道题的核心考点还是对于javascript原型的掌握程度,比如__proto__,prototype相关概念,以及instanceof底层原理的理解.若你对于原型已经非常熟悉,那么可以直 ...

  2. Redis缓存相关的几个问题

    1  缓存穿透 问题描述 缓存穿透是指查询一个一定不存在的数据,由于缓存是不命中时需要从数据库查询,查不到数据则不写入缓存,这将导致这个不存在的数据每次请求都要到数据库去查询,进而给数据库带来压力. ...

  3. STM32F401+nRF24L01无线传输音频(对讲机原型)

    尝试结合STM32F401的ADC, PWM, SPI(NRF24L01)和TIM, 试验了一下音频的无线传输(对讲机原型) 工作机制 音频采样 因为硬件的限制, 包括STM32F401片内存储, 内 ...

  4. 如何基于three.js(webgl)引擎架构,实现3D密集架库房,3D档案室(3d机器人取档、机器人盘点、人工查档、设备巡检)

     前言: 这是最好的时代,也是最坏的时代:是充满挑战的时代,也是充满机遇的时代.是科技飞速的时代,也是无限可能的时代. 近年来,人工智能(AI)技术的飞速发展已经席卷了全球,不断突破着技术边界,为各行 ...

  5. mdbook安装使用实录

    简介 mdbook是一个基于Rust的电子书系统,效果类似于gitbook.本人写图文文章一直都采用的印象笔记,但是写系列教程的情况不方便管理.因此引入mdBook,分享一下基本安装使用过程及遇到的问 ...

  6. Redis分布式锁的正确使用姿势

    前言 分布式锁在日常开发中,用处非常的多.包括但不限于抢红包,秒杀,支付下单,幂等,等等场景. 分布式锁的实现方式有多种,包括redis实现,mysql实现,zookeeper实现等等.而其中redi ...

  7. Redis 缓存过期删除/淘汰策略分析

    Redis 缓存过期删除/淘汰策略分析 Redis 缓存删除 Redis 键过期删除,定期删除(主动)和惰性删除(被动) Redis 内存不足时,缓存淘汰策略 key 键过期删除 我们用 redis ...

  8. https://editor.csdn.net/md/?articleId=131348876

    前言   前面搭建了基础环境,在使用统信UOS系统的相关行业也是不能上网的,但是可以传递压缩包,为了很好的方便相关从业人员工作,特将此种方式流程分享出来.(与国产银河麒麟不同)  本篇文章的重点就是离 ...

  9. 麒麟系统开发笔记(十一):在国产麒麟系统上使用gdb定位崩溃异常方法流程进阶定位代码行数及专项测试Demo

    前言   上一篇,通过研究,可以定位到函数,本篇进一步优化,没有行数,程序较为复杂的时候,就无法定位,所以进一步定位.  本篇做了qBreakpad的研究,但是没有成功,过程也还是填出来,后来突然注意 ...

  10. 【Azure 应用服务】App Service / Function App 修改系统时区为中国时区的办法(Azure中所有服务的默认时间都为UTC时间,转换为北京时间需要+8小时)

    问题描述 在Azure的 App Service / Function App 服务中,如果是在Windows系统中,可以通过添加Application Setting来转换为中国时间(WEBSITE ...