WinAppSDK / WinUI3 项目无法使用 SystemEvents 的问题
|
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 内部线程上触发事件,自然就能正常触发了。
来源:https://www.cnblogs.com/blue-fire/p/18091294
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作! |
|
|
|
发表于 2024-3-23 17:54:17
举报
回复
分享
|
|
|
|