我有一个 C# 库,希望能够将工作发送/发布到“主”ui 线程(如果存在)。
该库可供以下人员使用:
- 一个winforms应用程序
- 本机应用程序(带 UI)
- 控制台应用程序(没有 UI)
在库中,我想在初始化期间捕获一些东西(SynchronizationContext、调度程序、任务调度程序或其他东西),这将允许我(稍后)将工作发送/发布到主线程(如果主线程具有这种能力——即它有一个消息泵)。例如,当且仅当主应用程序能够让我访问主线程时,库才会在主线程上放置一些 Winforms UI。
我尝试过的事情:
- A 同步上下文 http://msdn.microsoft.com/en-us/library/system.threading.synchronizationcontext.aspx:
对于 Winforms 应用程序(aWindowsFormsSynchronizationContext http://msdn.microsoft.com/en-us/library/system.windows.forms.windowsformssynchronizationcontext.aspx将安装为Current http://msdn.microsoft.com/en-us/library/system.threading.synchronizationcontext.current.aspx同步上下文。这对于控制台应用程序也适用 - 因为我可以检测到 Current SynchronizationContext 为空(因此,知道我无法将工作发送/发布到主线程)。这里的问题是本机 UI 应用程序:它有能力(即它有消息泵),但当前同步上下文为空,因此我无法将其与控制台应用程序情况区分开来。如果我可以区分,那么我可以简单地在主线程上安装一个 WindowsFormsSynchronizationContext,然后我就可以开始了。
- A 调度员 http://msdn.microsoft.com/en-us/library/ms615907:使用捕获此Current http://msdn.microsoft.com/en-us/library/system.threading.synchronizationcontext.current.aspx创建一个新的 SynchronizationContext。因此,在所有情况下我都会找回调度程序。但是,对于控制台应用程序,使用
Dispatcher.Invoke
后台线程将挂起(如预期)。我可以用Dispatcher.FromThread http://msdn.microsoft.com/en-us/library/system.windows.threading.dispatcher.fromthread(如果线程不存在,则不会为线程创建调度程序)。但是本机 UI 应用程序将使用此方法返回 null 调度程序,因此我再次陷入无法区分 UI 应用程序和控制台应用程序的困境。
- A 任务调度器 http://msdn.microsoft.com/en-us/library/system.threading.tasks.taskscheduler.aspx: 我可以用来自当前同步上下文 http://msdn.microsoft.com/en-us/library/system.threading.tasks.taskscheduler.fromcurrentsynchronizationcontext.aspx。这与 SynchronizationContext 具有相同的问题。 IE。在调用 FromCurrentSyncronizationContext 之前,我必须检查 Current SynchronizationContext 是否为 null(控制台应用程序和本机 ui 应用程序就是这种情况)。因此,我再次无法区分本机 ui 应用程序和控制台应用程序。
当然,我可以让我的库的用户在调用我的库时指定它是否是 UI 应用程序Initialize
方法,但我希望尽可能避免图书馆用户的这种复杂情况。
这通常是不可能的,易于在线程中使用的库无法对哪个特定线程是 UI 线程做出任何假设。您可以捕获 Synchronization.Current,但只有在从 UI 线程调用初始化方法时才能正常工作。这并不是什么特别不寻常的事情,就像 TaskScheduler.FromCurrentSynchronizationContext() 往往会偶然工作,但不能保证。您可以添加一个检查,如果 Thread.CurrentThread.GetApartmentState() 不返回 STA,那么您没有从 UI 线程调用的可能性非常高。在这种情况下,SynchronizationContext.Current 通常也将为 null,这是另一种检查方法。
(可以说)更好的方法是不用担心它并让客户端代码弄清楚它,它不会在整理回调时遇到任何问题。或者公开 SynchronizationContext 类型的属性,以便客户端代码可以分配它。或者将其添加为构造函数参数。如果您准备好 Post 但发现它仍然为 null,则抛出 InvalidOperationException,这是客户端程序员只犯一次的疏忽。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)