ToB企服应用市场:ToB评测及商务社交产业平台
标题:
WinAppSDK / WinUI3 项目无法使用 SystemEvents 的题目
[打印本页]
作者:
小小小幸运
时间:
2024-5-15 04:01
标题:
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 内部线程上触发事件,自然就能正常触发了。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/)
Powered by Discuz! X3.4